From 726b1fdb0970ddc62b370424e15df0d4b44bc439 Mon Sep 17 00:00:00 2001 From: Shibo Sheng Date: Fri, 25 Sep 2026 00:06:55 +0800 Subject: [PATCH] fix(agent-org): preserve team history across upgrades Isolate current team execution from legacy runtime tables, archive legacy facts transactionally, expose paged read-only history, and keep v2.0.8 readable copies without restoring retired execution authority. Verification: - cargo test -p agent_core -p session_persistence --lib --no-fail-fast passed - cargo clippy --all-targets -- -D warnings passed - full and focused Vitest, typecheck, lint, circular, placement, and i18n checks passed - pnpm run tauri:build:fast -- --instance 31 completed successfully - BuildFast migration/restart and user-reported v2.0.8 round trip passed --- .../AgentOrgHistoryCompatibilityAcceptance.md | 144 ++ ...ntOrgHistoryCompatibilityImplementation.md | 88 ++ ...storyCompatibilityManualFormalRoundTrip.md | 106 ++ ...entOrgHistoryCompatibilityManualNewTeam.md | 113 ++ ...tOrgHistoryCompatibilityManualRoundTrip.md | 163 ++ .../AgentOrgHistoryBoundary.md | 17 + .../AgentOrgHistoryCompatibility.md | 51 + .../coordination/agent_inbox/message_tests.rs | 14 +- .../core/coordination/agent_inbox/schema.rs | 78 +- .../coordination/agent_inbox/store_drain.rs | 134 +- .../coordination/agent_inbox/store_read.rs | 56 +- .../coordination/agent_inbox/store_write.rs | 24 +- .../agent_inbox/store_write_tests.rs | 16 +- .../coordination/agent_inbox/task_bindings.rs | 48 +- .../core/coordination/agent_inbox/tests.rs | 24 +- .../agent_member_interventions.rs | 106 +- .../continuation.rs | 2 +- .../continuation_tests.rs | 17 +- .../agent_member_interventions/persistence.rs | 44 +- .../agent_member_interventions_tests.rs | 74 +- .../core/coordination/agent_org_archive.rs | 74 +- .../coordination/agent_org_archive_tests.rs | 84 +- .../agent_org_final_summary/context.rs | 4 +- .../agent_org_final_summary/mod.rs | 2 +- .../agent_org_final_summary/schema.rs | 22 +- .../agent_org_final_summary/store.rs | 44 +- .../tests/context_tests.rs | 8 +- .../agent_org_final_summary/tests/fixture.rs | 4 +- .../tests/retry_tests.rs | 10 +- .../tests/scale_tests.rs | 4 +- .../tests/state_tests.rs | 2 +- .../core/coordination/agent_org_finality.rs | 64 +- .../agent_org_finality/coordinator_recheck.rs | 28 +- .../agent_org_finality/execution_authority.rs | 16 +- .../restart_reconciliation.rs | 50 +- .../agent_org_finality/scope_closure.rs | 36 +- .../task_delivery_settlement.rs | 24 +- .../agent_org_formal_triggers/claim.rs | 38 +- .../agent_org_formal_triggers/schema.rs | 30 +- .../agent_org_formal_triggers/store.rs | 28 +- .../tests/assignment_tests.rs | 6 +- .../tests/claim_tests.rs | 10 +- .../tests/fixture.rs | 4 +- .../tests/scale_tests.rs | 2 +- .../tests/store_tests.rs | 10 +- .../core/coordination/agent_org_history.rs | 10 +- .../agent_org_history_store/archive.rs | 132 ++ .../agent_org_history_store/capture.rs | 301 ++++ .../conformance_tests.rs | 193 +++ .../agent_org_history_store/copies.rs | 372 +++++ .../agent_org_history_store/mod.rs | 103 ++ .../agent_org_history_store/read.rs | 234 +++ .../agent_org_history_store/schema.sql | 52 + .../agent_org_history_store/tests.rs | 350 ++++ .../core/coordination/agent_org_ownership.rs | 6 +- .../src/core/coordination/agent_org_pause.rs | 144 +- .../agent_org_pause/turn_authority.rs | 14 +- .../agent_org_plan_approvals/artifact.rs | 2 +- .../agent_org_plan_approvals/mod.rs | 30 +- .../agent_org_plan_approvals/persistence.rs | 10 +- .../agent_org_plan_approvals/store.rs | 40 +- .../agent_org_plan_approvals/tests.rs | 5 +- .../tests/formal_receipt_tests.rs | 8 +- .../tests/immutable_revision_tests.rs | 2 +- .../tests/pause_resume_tests.rs | 10 +- .../tests/persistence_boundary_tests.rs | 2 +- .../tests/projection_tests.rs | 4 +- .../tests/request_changes_tests.rs | 2 +- .../agent_org_plan_approvals/transitions.rs | 18 +- .../coordination/agent_org_run_blockers.rs | 110 +- .../coordination/agent_org_run_completion.rs | 84 +- .../keep_stopped_tests.rs | 12 +- .../agent_org_run_completion/notifications.rs | 56 +- .../agent_org_run_completion/pending.rs | 56 +- .../agent_org_run_completion/presentation.rs | 14 +- .../coordination/agent_org_runs/helpers.rs | 6 +- .../agent_org_runs/materialization.rs | 34 +- .../core/coordination/agent_org_runs/mod.rs | 18 +- .../coordination/agent_org_runs/progress.rs | 34 +- .../coordination/agent_org_runs/quiescence.rs | 66 +- .../agent_org_runs/store/completion.rs | 4 +- .../agent_org_runs/store/delete.rs | 50 +- .../agent_org_runs/store/lifecycle.rs | 6 +- .../agent_org_runs/store/next_work.rs | 4 +- .../agent_org_runs/store/queries.rs | 10 +- .../agent_org_runs/store/quiescence.rs | 6 +- .../agent_org_runs/store/session_lookup.rs | 6 +- .../agent_org_runs/store/starting.rs | 20 +- .../agent_org_runs/store/worker_sessions.rs | 10 +- .../core/coordination/agent_org_runs/tests.rs | 62 +- .../agent_org_task_execution_fence.rs | 14 +- .../coordination/agent_org_task_handoffs.rs | 88 +- .../coordination/agent_org_tasks/actor.rs | 12 +- .../coordination/agent_org_tasks/helpers.rs | 6 +- .../core/coordination/agent_org_tasks/mod.rs | 44 +- .../agent_org_tasks/store/annotations.rs | 8 +- .../agent_org_tasks/store/create.rs | 8 +- .../agent_org_tasks/store/delete.rs | 4 +- .../agent_org_tasks/store/dependencies.rs | 10 +- .../coordination/agent_org_tasks/store/fsm.rs | 21 +- .../agent_org_tasks/store/plan_completion.rs | 11 +- .../agent_org_tasks/store/read.rs | 30 +- .../agent_org_tasks/store/repair.rs | 30 +- .../agent_org_tasks/store/requeue.rs | 16 +- .../agent_org_tasks/store/update.rs | 2 +- .../agent_org_tasks/store/validation.rs | 8 +- .../task_assignment_race_tests.rs | 22 +- .../task_store_contract_tests.rs | 146 +- .../coordination/agent_org_tasks/tests.rs | 34 +- .../coordination/agent_org_tool_receipts.rs | 8 +- .../coordination/agent_org_turn_contexts.rs | 197 +-- .../agent_org_turn_contexts/tests.rs | 179 ++- .../agent_org_turn_contexts/wake_admission.rs | 18 +- .../wake_admission_tests.rs | 38 +- .../agent_org_user_directed_work.rs | 119 +- .../agent_org_user_directed_work/recovery.rs | 28 +- .../coordination/agent_org_watchdog/budget.rs | 30 +- .../agent_org_watchdog/reservation.rs | 12 +- .../tests/doorbell_repair_tests.rs | 32 +- .../agent_org_watchdog/tests/fixture.rs | 4 +- .../coordination/agent_org_work_episodes.rs | 54 +- .../agent_org_work_episodes/tests.rs | 12 +- .../fixtures/background_history_agent_org.sql | 1405 +++++++++++++++++ .../fixtures/official_v2_0_8_agent_org.sql | 1399 ++++++++++++++++ .../agent-core/src/core/coordination/mod.rs | 1 + .../src/core/coordination/schema.rs | 996 ++---------- .../src/core/coordination/schema_tests.rs | 607 +++++++ .../agent-core/src/core/definitions/orgs.rs | 29 +- .../src/core/session/persistence/crud/ops.rs | 11 +- .../src/core/session/persistence/messages.rs | 36 +- .../src/core/session/persistence/sidebar.rs | 37 +- .../persistence/sidebar_history_tests.rs | 34 + .../final_summary_event_tests.rs | 8 +- .../initial_reply_event_tests.rs | 4 +- .../turn/processor/inbox_drain/tests.rs | 4 +- .../agent_org/completion_wait_tests.rs | 30 +- .../orchestration/agent_org/inbox_repair.rs | 12 +- .../agent_org/next_work_tests.rs | 19 +- .../orchestration/agent_org/rework_tests.rs | 2 +- .../agent_org/send_message/persistence.rs | 16 +- .../agent_org/send_message/tests.rs | 94 +- .../agent_org/summary_terminal_tests.rs | 10 +- .../agent_org/task_formal_receipt_tests.rs | 4 +- .../orchestration/agent_org/task_tests.rs | 77 +- .../impls/orchestration/agent_org/tasks.rs | 2 +- .../tests/formal_receipt_wake_tests.rs | 8 +- .../impls/orchestration/member_idle/tests.rs | 14 +- .../core/tools/impls/plan_mode/create_plan.rs | 8 +- .../agent-core/src/core/tools/registry.rs | 4 + .../db_helpers/messages/cleanup.rs | 8 +- .../foundation/persistence/db_helpers/mod.rs | 4 +- .../src/foundation/persistence/test_schema.rs | 18 + src-tauri/crates/agent-core/src/init/mod.rs | 7 +- src-tauri/crates/agent-core/src/lifecycle.rs | 6 +- .../commands/session/debug/org_runtime.rs | 4 +- .../commands/session/message/org_wake.rs | 10 +- .../state/commands/session/message/send.rs | 1 + .../state/commands/session/message/tests.rs | 32 +- .../message/tests/history_read_only_tests.rs | 74 + .../message/tests/pause_continuation_tests.rs | 10 +- .../commands/session/org_tasks/context.rs | 2 + .../session/org_tasks/group_actions.rs | 22 +- .../commands/session/org_tasks/group_chat.rs | 25 +- .../org_tasks/group_projection/tests.rs | 26 +- .../org_tasks/group_projection/timeline.rs | 56 +- .../commands/session/org_tasks/handoff.rs | 10 +- .../commands/session/org_tasks/history.rs | 28 + .../org_tasks/history_provenance_tests.rs | 10 +- .../commands/session/org_tasks/lifecycle.rs | 2 +- .../state/commands/session/org_tasks/mod.rs | 2 + .../org_tasks/rejected_request_draft.rs | 14 +- .../org_tasks/resource_teardown_tests.rs | 4 +- .../commands/session/org_tasks/run_view.rs | 10 +- .../state/commands/session/org_tasks/tests.rs | 172 +- .../src/state/commands/session/persistence.rs | 2 +- .../commands/session/persistence_tests.rs | 84 +- .../agent-core/src/tests/lifecycle_tests.rs | 35 +- .../crates/session-persistence/src/crud.rs | 8 +- .../session-persistence/src/crud_tests.rs | 3 + .../src/history_compatibility_tests.rs | 132 ++ .../session-persistence/src/turn_index.rs | 42 +- .../src/turn_index_inbox_backfill_tests.rs | 10 +- .../commands/agent_org_plan_history.rs | 18 +- .../aggregation/agent_org.rs | 21 + .../aggregation/history_tests.rs | 28 + .../aggregation/native_page.rs | 1 + .../aggregation/native_sidebar.rs | 19 +- .../aggregation/test_support.rs | 1 + .../session_directory/conversion.rs | 6 + .../session_directory/display.rs | 1 + .../session_directory/orgtrack_adapter.rs | 21 + .../session_directory/sections/mod.rs | 14 +- .../session_directory/sections/tests.rs | 22 + .../tests/session_filter_tests.rs | 1 + .../agent_sessions/session_directory/types.rs | 3 + src-tauri/src/api/agent/test/agent_org.rs | 38 +- .../api/agent/test/agent_org_user_directed.rs | 14 +- src-tauri/src/commands/handler_list.inc | 2 + src-tauri/src/test_utils/test_env.rs | 10 +- src/api/tauri/agent/orgTasks/errors.ts | 1 + src/api/tauri/agent/orgTasks/history.test.ts | 60 + src/api/tauri/agent/orgTasks/history.ts | 61 + src/api/tauri/rpc/schemas/sessionAggregate.ts | 1 + src/api/tauri/session/index.ts | 1 + .../ChatPanel/AgentOrgHistoryBoundary.test.ts | 178 +++ .../ChatPanel/AgentOrgHistoryBoundary.tsx | 229 +++ src/engines/ChatPanel/ChatView.tsx | 33 +- .../components/agentOrgRunViewStore.test.ts | 59 + .../components/agentOrgRunViewStore.ts | 9 + .../hooks/useChatViewAgentOrgSurface.tsx | 4 +- src/i18n/locales/de/sessions.json | 10 + src/i18n/locales/en/sessions.json | 10 + src/i18n/locales/es/sessions.json | 10 + src/i18n/locales/fr/sessions.json | 10 + src/i18n/locales/hi/sessions.json | 10 + src/i18n/locales/id/sessions.json | 10 + src/i18n/locales/ja/sessions.json | 10 + src/i18n/locales/ko/sessions.json | 10 + src/i18n/locales/pl/sessions.json | 10 + src/i18n/locales/pt/sessions.json | 10 + src/i18n/locales/ru/sessions.json | 10 + src/i18n/locales/tr/sessions.json | 10 + src/i18n/locales/vi/sessions.json | 10 + src/i18n/locales/zh-Hant/sessions.json | 10 + src/i18n/locales/zh/sessions.json | 10 + src/store/session/sessionAtom/mutations.ts | 1 + .../session/sessionAtom/sidebarRoster.ts | 3 +- src/store/session/sessionAtom/types.ts | 1 + src/util/session/sessionVisibility.ts | 7 +- .../core/agent-org-pause-resume-live.spec.mjs | 36 +- .../support/core/agentOrgCompletionDriver.mjs | 26 +- .../support/core/agentOrgSummaryDriver.mjs | 14 +- .../support/core/agentOrgTerminalDriver.mjs | 6 +- tests/e2e/support/core/agentOrgWakeDriver.mjs | 14 +- 234 files changed, 9562 insertions(+), 3176 deletions(-) create mode 100644 docs/architecture-audit-2026-09-24/AgentOrgHistoryCompatibilityAcceptance.md create mode 100644 docs/architecture-audit-2026-09-24/AgentOrgHistoryCompatibilityImplementation.md create mode 100644 docs/architecture-audit-2026-09-24/AgentOrgHistoryCompatibilityManualFormalRoundTrip.md create mode 100644 docs/architecture-audit-2026-09-24/AgentOrgHistoryCompatibilityManualNewTeam.md create mode 100644 docs/architecture-audit-2026-09-24/AgentOrgHistoryCompatibilityManualRoundTrip.md create mode 100644 docs/frontend-ui-audit-2026-09-24/AgentOrgHistoryBoundary.md create mode 100644 docs/org2-performance-guard-2026-09-24/AgentOrgHistoryCompatibility.md create mode 100644 src-tauri/crates/agent-core/src/core/coordination/agent_org_history_store/archive.rs create mode 100644 src-tauri/crates/agent-core/src/core/coordination/agent_org_history_store/capture.rs create mode 100644 src-tauri/crates/agent-core/src/core/coordination/agent_org_history_store/conformance_tests.rs create mode 100644 src-tauri/crates/agent-core/src/core/coordination/agent_org_history_store/copies.rs create mode 100644 src-tauri/crates/agent-core/src/core/coordination/agent_org_history_store/mod.rs create mode 100644 src-tauri/crates/agent-core/src/core/coordination/agent_org_history_store/read.rs create mode 100644 src-tauri/crates/agent-core/src/core/coordination/agent_org_history_store/schema.sql create mode 100644 src-tauri/crates/agent-core/src/core/coordination/agent_org_history_store/tests.rs create mode 100644 src-tauri/crates/agent-core/src/core/coordination/fixtures/background_history_agent_org.sql create mode 100644 src-tauri/crates/agent-core/src/core/coordination/fixtures/official_v2_0_8_agent_org.sql create mode 100644 src-tauri/crates/agent-core/src/core/coordination/schema_tests.rs create mode 100644 src-tauri/crates/agent-core/src/core/session/persistence/sidebar_history_tests.rs create mode 100644 src-tauri/crates/agent-core/src/state/commands/session/message/tests/history_read_only_tests.rs create mode 100644 src-tauri/crates/agent-core/src/state/commands/session/org_tasks/history.rs create mode 100644 src-tauri/crates/session-persistence/src/history_compatibility_tests.rs create mode 100644 src-tauri/src/agent_sessions/session_directory/aggregation/history_tests.rs create mode 100644 src/api/tauri/agent/orgTasks/history.test.ts create mode 100644 src/api/tauri/agent/orgTasks/history.ts create mode 100644 src/engines/ChatPanel/AgentOrgHistoryBoundary.test.ts create mode 100644 src/engines/ChatPanel/AgentOrgHistoryBoundary.tsx diff --git a/docs/architecture-audit-2026-09-24/AgentOrgHistoryCompatibilityAcceptance.md b/docs/architecture-audit-2026-09-24/AgentOrgHistoryCompatibilityAcceptance.md new file mode 100644 index 0000000000..9879abab1e --- /dev/null +++ b/docs/architecture-audit-2026-09-24/AgentOrgHistoryCompatibilityAcceptance.md @@ -0,0 +1,144 @@ +# Agent Org 历史兼容验收及手测指南 + +## 当前结论 + +实现和自动检查已落地;历史浏览、只读、分页和真实退出/重启已用隔离包验证,最终 BuildFast 还已使用正式 `~/.orgii` 完成首次升级与浏览检查。用户于 2026-09-25 报告修复版真实模型和官方 v2.0.8 往返验收成功,并授权提交、推送和创建 Draft PR。两项实机操作由用户完成;代理没有代为发送模型请求,以下记录将用户签收与代理可复核证据分开陈述。 + +分支 `codex/agent-org-history-compatibility`,基线 `22767a2a4f3185b127bf6d5669302cffcbe6dce4`,未来 PR 目标 `codex/agent-org-background-history`。基线相对用户方案中的 `384a7a71d` 仅增加子进程测试,生产代码相同。 + +## 可复现构建 + +```sh +WEBDRIVER=1 NODE_OPTIONS=--max-old-space-size=16384 CARGO_BUILD_JOBS=4 \ + pnpm run tauri:build:fast -- --instance 31 "$ARTIFACT_DIR" +``` + +独立应用名 `ORG2 Instance 31`,应用身份 `org2ai.org2.instance31`,API 端口 13877,代理端口 17918。启动器显式设置 `ORGII_HOME`,清除 E2E 模拟环境变量;隔离模式把外部来源发现目录放在夹具内,正式模式则把 `ORGII_EXTERNAL_HISTORY_HOME` 设为真实用户主目录,使 Codex 继续读取 `~/.codex/sessions`。正式模式要求 `--allow-primary-profile` 并在存在任何 ORG2 进程时拒绝启动,保证版本不会并行写库。 + +最终应用:`/private/tmp/org-history-verification/build-final/ORG2 Instance 31.app`。二进制 SHA-256:`845b3235a510a860aef13efb603a2f048a71bb6e6963da0c1501dbb8ffdcb58b`。构建日志:`/private/tmp/org-history-build-formal-fix.log`,退出码 0,用时 460.6 秒。最终包包含共享运行视图停止历史重试、缺失模板快照仍按已保存成员关系归档,以及旧版群聊定向回复在新版执行区建表前仍可生成历史副本三处实机修正。 + +源码清单及逐文件哈希:`/private/tmp/org-history-verification/final-source-manifest.json`;已跟踪文件补丁 SHA-256 为 `bcccb7fa32819eef92e5b0f90d33010ec059bd42f7c0adc2b5d4ef3f8dc219e5`。未跟踪新增文件另在清单中逐个记录,不能仅凭 HEAD 代表本次实现。最终复核 GitHub #2130 仍为上述基线。 + +首次安装包及其证据保留在 `build/`;其二进制 SHA-256 为 `fe976fa549f8bd3225251179a6d4ff6809a3f5add9da69c14a3f6e787bae4874`。该包不能替代本次交付版本。 + +## 自动验证 + +原始日志及其 SHA-256 清单:`/private/tmp/org-history-verification/automated-evidence-manifest.json`。 + +| 实际执行命令/范围 | 结果 | 证明边界 | +| ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `cargo test --manifest-path src-tauri/Cargo.toml -p agent_core -p session_persistence --lib --no-fail-fast` | 最终核心 3,755 通过、3 项原有忽略;会话持久化 67 通过 | 固定 v2.0.8、2105/2130 相同旧 DDL、中间附加 BLOB、缺表、事务回滚/并发、当前区损坏、幂等、增量副本、旧群聊事件初始化顺序、发送与工具准入、原有新团队生命周期 | +| `cargo test --manifest-path src-tauri/Cargo.toml -p agent_core --lib retired_archived_roots_remain_discoverable` | 后补 1 项通过 | 归档历史根仍可发现;副本不能挤占分页名额 | +| `cargo test --manifest-path src-tauri/Cargo.toml --lib agent_sessions::session_directory` | 93 项通过 | 置顶、自定义分组与侧栏历史身份一致 | +| `cargo clippy --manifest-path src-tauri/Cargo.toml --all-targets -- -D warnings` | 最终 Rust 源码通过 | 所有目标编译和严格检查;不代表实机运行通过 | +| `NODE_OPTIONS=--max-old-space-size=16384 pnpm exec vitest run --config config/vitest.config.ts` | 2,262 文件通过、1 文件因依赖软链接越界导入而未运行;17,076 测试通过、2 expected fail、3 skipped | 完整前端套件实际结果;不是一次全绿运行 | +| 本工作区 `pnpm install --frozen-lockfile --offline` 后,重跑 `ReactArtifactRunner.runtime.test.ts` | 7 项通过 | 修复测试环境;未修改业务代码规避失败 | +| `pnpm exec vitest run --config config/vitest.config.ts src/engines/ChatPanel/InputArea/components/agentOrgRunViewStore.test.ts src/engines/ChatPanel/AgentOrgHistoryBoundary.test.ts src/api/tauri/agent/orgTasks/history.test.ts` | 最后前端修正后 27 项通过 | 历史错误停止所有共享消费者的轮询/重连发现;当前团队继续刷新;身份在途合并、分页和只读界面 | +| `NODE_OPTIONS=--max-old-space-size=16384 pnpm typecheck` | 通过 | 前后端新增字段的 TS 使用契约 | +| `pnpm run lint`,最后改动再检查对应 3 文件的 oxlint/eslint | 通过 | 无抑制规则、无跳过 hook | +| `pnpm run check:circular` | 通过 | 无循环依赖 | +| `node scripts/quality/check-test-placement.mjs` | 635 目录通过 | 测试位置 | +| `pnpm run check:i18n:contracts` | 15 语言、128,918 值,零新增问题 | 新只读/分页/失败文案 | +| `git diff --check` | 通过 | 无空白错误 | +| `cargo fmt --manifest-path src-tauri/Cargo.toml --all -- --check` | 未全仓通过 | 最终重跑仍有 70 个未改动基线文件的格式差异,逐文件与 HEAD 字节一致;与本次 227 文件交集为 0。受影响文件没有剩余格式差异,未扩展到全仓格式清理 | + +## 首次安装包实机记录(保留原证据) + +测试数据库来自前置 PR 的**既有隔离真实模型夹具**,不是用户主数据库。升级前有 5 个团队、25 个根/成员会话、947 条事件、13 份已保存报告。 + +| 操作 | 结果与数据库证据 | +| --------------------------------------- | ---------------------------------------------------------------------------------------------------------- | +| 首次启动 | 5 个历史根、25 个历史身份、25 个独立普通副本、1 批原始归档;新执行区和固定旧区均为空 | +| 打开根和成员 | 根报告与 Implementer 正文可读;显示 `Older-version conversation, view only`,无发送输入框 | +| 打开保存内容、下一页 | 中文/英文群聊、任务输出和报告可读;首个 50 条窗口可翻到后续内容;不是全量累计渲染 | +| 原本 archived 的团队 | 在侧栏可发现、可打开;可置顶,仍呈现同一历史身份 | +| Command+Q、确认退出、进程消失、重新启动 | 归档批次、历史身份/副本、947 原事件、13 报告不重复;打开后报告仍可读 | +| 原始内容对照 | 947 条事件的正文、结果 JSON、时间均保持;13 份报告与普通副本的正文逐一匹配;副本无父会话或团队成员执行字段 | +| 原事件缓存元数据 | 既有正文加载过程修改 32 条事件 args 中的 `historySequence` / `turnPreviewOnly`;没有声称共享缓存逐字节不变 | +| 旧任务状态 | 原始归档仍是 running 2、idle 2、archived 1;没有改成完成或取消 | +| 多次打开、成员切换、翻页、隐藏、关闭 | Command+5 `No API calls yet`;历史事件数 947,模型用量记录 720,均未增长 | +| 新建团队 | UI 正常建立 1 个新版团队和增量副本;真实调用被过期测试登录阻断,不能作为模型执行/交付通过证据 | + +旧版副本的原始事件与可见快照有独立稳定 ID;新版本列表排除副本。自动测试覆盖写入失败时源事件和副本一起回滚、重复写入不增加版本,以及再升级不重新扫描已归档正文。 + +## 前一候选包的隔离历史复测 + +以下隔离复测使用候选 SHA-256 `fb4b52ad4bd774b6d663dc06008f76a91ab384320ae49cb3c3149b632693f959` 和新的 `profile-final`。该证据仍证明共享 UI 与生命周期边界,但候选包已被正式库发现的初始化顺序修正取代,不能作为最终二进制身份。 + +| 检查 | 实际结果 | +| ------------------ | --------------------------------------------------------------------------------------------------------------------------- | +| 第一次升级 | 5 个历史根、25 个历史身份、25 个普通副本、333 条可见历史项、1 批原始归档;旧运行区 0、新执行区 0 | +| 根、成员、保存内容 | 根报告可读;Implementer 原文可读;长群聊翻到下一页,保留首页入口和只读提示 | +| 归档根及置顶 | 原 archived 团队可发现、打开并置顶,保持历史身份 | +| 真实退出/重启 | PID 57632 经 Command+Q 确认退出,进程消失;同包新 PID 59826;重启后报告可读、置顶保留 | +| 数量与正文 | 前后 50 个共享会话(25 源 + 25 副本)、1,839 事件(947 源 + 892 副本);947 条源正文哈希逐条一致;13 份报告副本正文全部匹配 | +| 原状态 | running 2、idle 2、archived 1,未改成完成/取消 | +| 幂等与授权 | 归档、映射、报告与源会话事件集合重启前后完全一致;重复来源映射和重复副本 ID 均为 0;副本执行关联为空 | +| 模型与后台 | 模型用量记录 720→720;无历史模型请求;Command+5 仅见普通本地 IPC。共享工作站跨 60 秒周期无历史运行视图 fallback | +| 生命周期采样 | 可见、隐藏、离开历史但保留标签、明确关闭历史标签各 16 样本/约 75 秒;详见性能审查,未把主进程样本称作整机或长期指标 | + +可复核 JSON 位于 `/private/tmp/org-history-verification/`:`final-before-upgrade.json`、`final-after-upgrade.json`、`final-after-browse.json`、`final-before-restart.json`、`final-after-restart.json`、`final-runtime-evidence.json`。同次启动记录和进程日志在 `manual-evidence/final-history-*` 与 `manual-evidence/final-restart-*`。初版证据继续保留,没有覆盖为最终通过。 + +## 最终包正式库首次升级检查 + +正式 v2.0.8 数据库升级前为 3.3 GB,638 个 session、3,311 条事件、6,626 条模型用量记录、25 条旧运行记录和 18 份报告;`PRAGMA quick_check` 为 `ok`。一致性备份保存于 `~/.orgii-agent-org-history-before-fixed-20260924-225841/sessions.db`,SHA-256 为 `a598dcc3fba0979edee3bebb48fb95a2fdeb7dc919c94501ce6253d063493161`。 + +第一次正式库启动暴露旧群聊定向回复会在执行区建表前查询新表,界面报缺表。迁移事务完整回滚;启动前后数量、正文和结构指纹一致。修正并完成上表核心检查后,用最终 SHA 重新启动成功:638 个源 session、3,311 条源事件和 18 份报告逐项保持;421 个历史身份及普通副本、88 个历史根、1 个原始归档批次;旧运行区与新执行区均为 0;重复来源映射/副本 ID 为 0;18 份报告副本全部匹配;旧区指纹仍为 v2.0.8 固定值,`quick_check` 为 `ok`。 + +Computer Use 已看到原正式侧栏,打开“规划德州扑克游戏开发”根报告与 Implementer 正文,显示“旧版本会话,仅供查看”且无发送输入区。没有新建执行团队、发送模型任务或启动官方 v2.0.8;最终包保持打开供用户继续两项手测。证据:`manual-evidence/formal-before-fixed.json`、`formal-after-failed-fixed.json`、`formal-after-fixed-ready.json`、`formal-fixed-ready-*-launch.json/.log`。 + +后续版本切换发现正式启动器曾把 `ORGII_EXTERNAL_HISTORY_HOME` 错设为 `~/.orgii/external-history-home`。该变量是 Codex、Claude 等来源的发现主目录;错误值使扫描看不到真实 `~/.codex/sessions`,并将可重建的 `imported_history_session_cache` 中 Codex 行暂时裁掉。源文件未删除,升级前备份和当前正式库均为 590 条 Codex 缓存、585 条可列出。直接启动官方应用后缓存恢复;启动器现已在正式模式使用 `$HOME`。这是手测启动环境修正,不改变产品实现或 Agent Org 历史迁移结果。 + +## 用户最终手测签收 + +1. **真实模型**:用户于 2026-09-25 报告修复版新团队与真实模型验收成功。代理未代为发送请求;用户没有回传团队 ID、Command+5 截图或结果文件,因此本记录把它列为用户签收,不伪造逐项机器证据。 +2. **官方 v2.0.8 往返**:用户使用正式 `~/.orgii` 完成版本切换并报告成功。官方 v2.0.8 二进制 SHA-256 为 `c11a1e709ee6b27014a7fbb413fa97b158ddf4448dc8a678e3d473796b83d267`;发布压缩包 SHA-256 为 `7479d1cdc36e94d028ed8e806adffd12d0507790be3e873ba19bdb3a1005d3dc`。收尾只读快照仍有 638 个源 session、18 份报告、421 个历史身份和副本、88 个历史根、1 个归档批次;新旧执行区均为 0,重复来源映射和副本 ID 均为 0,旧区指纹保持 v2.0.8 固定值。该快照保存在本机验收证据目录,不提交数据库或用户内容。 + +官方包来源:[v2.0.8 macOS Apple Silicon 发布包](https://github.com/org2AI/ORG2/releases/download/v2.0.8/ORG2-updater-mac-apple-silicon.app.tar.gz)。 + +## 用户手测指南 + +- [手测 1:修复版新团队和真实模型执行](AgentOrgHistoryCompatibilityManualNewTeam.md) +- [手测 2:本机正式 `~/.orgii` 往返](AgentOrgHistoryCompatibilityManualFormalRoundTrip.md) +- [备用:独立测试用户/机器四阶段往返](AgentOrgHistoryCompatibilityManualRoundTrip.md) + +指南包含固定应用/二进制 SHA-256、正式或隔离目录与启动器、逐步操作、每步预期与失败判定,以及 UI、数据库、日志、文件、Command+5 的证据清单。往返指南提供团队、会话、正文、报告、副本和归档的逐阶段计数表。用户已签收两项;没有回传的分项证据继续明确标为“用户报告”,不转换成代理实测结论。 + +Command+5 包含普通本地 IPC 请求;“历史零模型请求”不等于面板所有请求为零。侧栏既有的 `session_aggregate_list` 周期刷新与用户触发的正文读取仍存在,不能将它们误判为历史模型执行,也不能声称应用完全没有轮询。 + +## 风险和恢复 + +首次升级需要一次原始行归档和可见内容副本写入,会增加磁盘占用;中断/写入失败整体事务回滚。成功后原始归档保留用于提取数据,不能直接接回旧执行授权。旧版可将共享排队状态改为 stale,本次不承诺 unfinished 任务续跑。普通会话、项目、设置、模板原文和其他数据库对象保留。用户已签收实机验收,但未回传的逐步请求、文件和数量证据不能由自动测试代替。 + +## 改动分类 + +按显式 SQL 对象映射先剥离机械改名,再按行为差异计数;schema 中原有 594 行测试提取到 607 行独立测试文件,不算删除业务逻辑。完整逐文件清单保存在本地验收证据目录。 + +最终实际差异:207 个已跟踪文件新增 2,908/删除 3,176 行;20 个新增文件共 5,972 行,合计 **227 文件,新增 8,880/删除 3,176 行**。审计文档单列,不在此数中。 + +显式对象映射剥离后的分类使用逐行序列比较,和 Git 分块计数略有差异;不同类别可涉及同一物理文件,文件数不能相加: + +| 类别 | 文件数 | 新增 / 删除 | 说明 | +| ---------------------------------- | -------------- | ------------- | --------------------------------------------------------------------------------------------------- | +| 表、索引与查询机械改名 | 161 | 2,392 / 2,392 | 共 4,784 行,位于预算 4,000–5,500 内 | +| 改名后换行/逗号格式适配 | 4 | 26 / 11 | 无行为变化,单列 | +| 实质生产逻辑 | 45 | 1,815 / 254 | 合计 2,069 行,位于 1,400–2,200 预算内;18 文件至少 10 行非机械变动,其余多数为 DTO、导出或入口接入 | +| 行为测试及测试支持(不含整段移动) | 22 | 1,172 / 11 | 低于预估行数;并未据此缩减验收矩阵 | +| 原 schema 测试移动 | 1 个新测试文件 | 607 / 594 | 从生产 schema 文件提取,不计为删除生产逻辑 | +| 两份固定版本 SQL | 2 | 2,804 / 0 | v2.0.8 固定结构及前置 PR 升级输入 | +| 国际化 | 15 | 150 / 0 | 历史提示和分页文案 | + +物理生产文件 45 个高于初估 22–32,原因是既有跨层 DTO、目录和入口的分散接入;未扩展功能、执行授权迁移或常驻同步。逐文件分类在 `/private/tmp/org-history-verification/diff-classification.json`。 + +最终复核:没有新增凭据、个人绝对目录、构建产物、依赖锁文件修改或检查抑制规则;新增 UI 控件均使用共享 Button,无原生按钮或可点击替代元素。主工作区和 2130 工作区的原有改动未被本工作区纳入。用户已授权从本分支提交、推送并创建 Draft PR。 + +本地审计文档受仓库共享 `.git/info/exclude` 的 `/docs/` 规则忽略,按用户要求保存在工作区,没有改忽略规则或强制暂存。未来得到提交授权时需要显式处理这些交付文档。 + +## 交付索引 + +- [设计到代码、验收到测试及十层架构复核](AgentOrgHistoryCompatibilityImplementation.md) +- [UI 审查](../frontend-ui-audit-2026-09-24/AgentOrgHistoryBoundary.md):0 fix / 5 keep with reason / 0 abstract +- [性能审查](../org2-performance-guard-2026-09-24/AgentOrgHistoryCompatibility.md):历史路径已验证,完整矩阵两格由用户实机签收 +- [新团队真实模型手测](AgentOrgHistoryCompatibilityManualNewTeam.md) +- [官方 v2.0.8 往返手测](AgentOrgHistoryCompatibilityManualRoundTrip.md) +- [本机正式 `~/.orgii` 往返手测](AgentOrgHistoryCompatibilityManualFormalRoundTrip.md) diff --git a/docs/architecture-audit-2026-09-24/AgentOrgHistoryCompatibilityImplementation.md b/docs/architecture-audit-2026-09-24/AgentOrgHistoryCompatibilityImplementation.md new file mode 100644 index 0000000000..7123e07c52 --- /dev/null +++ b/docs/architecture-audit-2026-09-24/AgentOrgHistoryCompatibilityImplementation.md @@ -0,0 +1,88 @@ +# Agent Org 历史兼容实现与验收记录 + +## 范围和版本 + +目标:升级前的团队全部保留为只读历史;升级后新建团队进入独立执行区。 +降级范围仅 v2.0.8;保留已保存内容,不保证未完成任务续跑。 + +分支 `codex/agent-org-history-compatibility`,叠加目标 `codex/agent-org-background-history`。 +基线 `22767a2a4f3185b127bf6d5669302cffcbe6dce4`:相对方案记录的 `384a7a71d` 仅多一处子进程测试修改,生产实现相同。 +官方 v2.0.8 源码为 `55b14b1937b4cac8d4ff9acc98f7e225aba9e5c9`。 + +## 根因与事实来源 + +历史事实的权威来源是持久化会话、事件正文、团队成员 materialization、可见任务输出和报告。前置 PR 修改了旧运行区 4 张表的字段/约束及严格校验指纹,导致 v2.0.8 无法接受;侧栏又依赖运行记录发现团队,旧版启动还会改变共享排队状态,因此仅放宽校验或在 UI 隐藏行无法修复。 + +源头修复是数据库初始化的原子隔离,以及原事件/输出/群聊写事务中的幂等副本保存。当前执行表只持有修复版新团队;历史身份和正文不依赖完整执行记录。新版列表排除普通副本是批准方案中的明确产品要求,依据持久化来源映射,不根据标题或正文猜测隐藏。旧数据保全为无执行约束的原始归档和独立历史索引,既不删除原文,也不把未完成状态改成完成/取消。验证证据见下表和最终验收记录。 + +## 设计到代码、验收到测试 + +| 契约 | 负责位置 | 来源/入口 | 确定性证明 | 失败/重启边界 | 实机证据 | +| ---------------------------------- | ------------------------------------------------------------------------------------- | ------------------------------------------------------ | -------------------------------------------------------------------------------- | --------------------------------------------------- | ---------------------------------------------------------------------------- | +| 旧版校验固定结构,新版只执行新表 | `coordination/schema.rs`、`fixtures/official_v2_0_8_agent_org.sql` | 生产、测试同一 `init_agent_org_schemas` | 固定旧指纹;39 表、79 索引、1 触发器的新指纹;旧扫描不包含新表和原始归档 | 当前区结构异常报错;全部表消失且标记存在也拒绝重建 | 实机旧区为空、新区初始为空,历史 5 根/25 会话 | +| 首次升级原子保全,不恢复旧状态机 | `agent_org_history_store/archive.rs`、`capture.rs` | v2.0.8、前置 PR 结构、中间字段、缺表 | 事务故障回滚;原始 BLOB/DDL;原状态不改写;并发初始化只归档一次 | 同一事务内原始副本、可见内容、旧区、新区、完成标记 | 自动检查通过;相应实机边界见最终验收记录 | +| 历史身份独立于执行记录 | `agent_org_history_store/read.rs`、会话目录 | 打开、侧栏、置顶、自定义分组、成员 | 根和成员描述;分页游标绑定会话;部分缺表 | 未知关系保持 NULL,不造运行状态或验收结果 | 自动检查通过;相应实机边界见最终验收记录 | +| 历史不会被发送或恢复执行 | `message/send.rs`、`init/mod.rs`、`org_tasks/context.rs`、工具注册入口、turn contexts | 用户发送、队列、立即发送、恢复、群聊、干预、重试、工具 | 直接调用所有发送来源和两个工具入口均返回同一只读错误,无运行实例 | 启动执行恢复仅查当前执行区;读取使用独立历史 API | 历史打开、切换、翻页、重启:Command+5 零请求,usage spans 不变 | +| 副本可由旧版普通会话读取 | `agent_org_history_store/copies.rs`、`session-persistence/crud.rs` | 原事件事务、团队输出事务、群聊可见内容事务 | 真实 `save_events` → `load_session`;独立 ID、无授权、增量幂等、写入失败整批回滚 | 旧版可改变共享排队状态;历史正文读取不受 stale 覆盖 | 用户报告正式数据往返通过;收尾快照保留 421 个稳定映射、18 份匹配报告且无重复 | +| 旧版创建的新团队在再升级时单独归档 | `archive.rs`、`capture.rs` | 旧区出现新行 | 稳定来源去重;已有副本不再次导出;当前成员不被误退休 | 正常重启只检查旧区对象和是否有行,不遍历正文 | 自动检查通过;相应实机边界见最终验收记录 | +| UI 浏览只读历史 | `AgentOrgHistoryBoundary.tsx`、`useChatViewAgentOrgSurface.tsx` | 打开根、切换成员、展开保存内容 | 未解析身份前不挂可写界面;过期响应丢弃;按需翻页;请求失败可显式重试 | 不生成假的 RunView,不启动运行视图轮询 | 实机根/成员/报告/翻页/归档根/置顶均通过;见验收记录 | +| 普通会话、模板和其他对象保持原义 | `definitions/orgs.rs`、明确对象映射 | 初始化和模板读取 | 不再删除旧模板原文;旧表归档只拥有显式集合;现有核心回归套件 | 原始归档供恢复,不能直接接回执行 | 自动检查通过;相应实机边界见最终验收记录 | + +## 十层架构复核 + +| 层 | 结论和证据 | +| --------------- | -------------------------------------------------------------------------------------------------------------- | +| 1 编译 | 应用所有目标编译与严格 Clippy 已通过;后续修改重跑对应检查 | +| 2 重复/死代码 | 历史读和执行读职责分离;共享正文仍由原存储拥有;删除旧丢弃迁移路径;较大的原 schema 测试移到独立文件 | +| 3 命名 | 39 张执行表和附属索引/触发器显式改名;不在运行时替换 SQL;错误标识不随表名机械变化 | +| 4 状态语义 | `current/history_only` 是读取和准入模式;不是任务完成/取消状态;原始状态原样归档 | +| 5 默认分支 | 初次迁移允许已知旧结构漂移和缺表;当前执行区异常拒绝启动;身份 API 失败时 UI 不出现可写控件 | +| 6 跨域依赖 | 核心拥有历史身份、快照和副本写入;会话持久化仅在原事务内调用核心投影;前端只接收描述与分页 DTO | +| 7 可理解性 | 模块按归档、事实提取、副本、读取拆分;固定旧 SQL 与测试升级输入注明出处 | +| 8 序列化 | 新增历史描述/分页 API;可空成员/根关系;固定错误 `agent_org_history_read_only`;副本剥离执行字段,保留可见正文 | +| 9 初始化一致 | 生产注册、独立实例和测试都使用同一初始化入口;必须独立事务;外键开关在返回时恢复 | +| 10 读取来源一致 | 侧栏、置顶、分组和打开使用持久化历史身份;当前执行事实不从历史副本反推;新列表排除副本来源映射 | + +正式库首次升级还发现一个初始化顺序缺口:v2.0.8 已保存的群聊定向回复会在历史副本生成时尝试读取尚未创建的新版成员物化表。根因位于副本写入边界,而非 UI。现在只有当两张新版执行表都已存在时才投影当前运行成员;首次切换仍保存原正文副本,不猜造执行关系。失败尝试的迁移事务完整回滚,正式库数量和旧结构指纹均未变化。新增 `official_old_group_mention_is_copied_before_execution_schema_exists` 覆盖该边界,随后核心测试为 3,755 通过、3 忽略,会话持久化 67 通过,严格 Clippy 通过。 + +## 数据恢复和兼容限制 + +- 失败的切换整笔回滚。成功后每张旧表的无约束原始行副本和原建表 SQL 都保留。 +- 原始副本没有执行索引、触发器或级联关系;恢复应从备份提取可见数据,不能自动复活旧授权/任务。 +- 降级时 v2.0.8 可按原行为改变共享排队状态;本次只保证保存的历史可读。 +- 副本使用普通会话,旧版可以显示其原有输入控件;它们没有指向新版团队执行区的授权。 +- 增量副本直接在原事务写共享存储,不调用会话创建、自动化或云发布钩子;新版列表和目录投影排除副本。 +- 本次不修改普通布局格式。历史身份每次由后端重新解析,实机验证如发现团队布局阻断打开再修正该特定快照。 +- 2130 已知的长历史 minimap 最早轮定位问题不在本次范围,也不作为通过证据;不运行无关 65 分钟后台服务验收。 + +## 自动验证记录 + +完整结果、代理证据与用户最终签收见 [验收及手测指南](AgentOrgHistoryCompatibilityAcceptance.md)。 + +早期检查:核心库 3,747 通过、3 项原有忽略;会话持久化原有 65 项通过;新增跨存储 2 项通过;前端相关 38 项通过;应用全目标编译、严格 Clippy、typecheck、lint、循环依赖、测试位置和国际化检查通过。 + +后续新增测试和同一最终源码的复跑结果、实机证据以本目录最终验收记录为准;此处不将中间证据当作最终通过。 + +## 实机发现并修正的共享读取遗漏 + +Agent Station 的两个运行视图消费者也会读取历史会话。后端正确返回只读错误,但原共享 store 将错误当成暂时失败并继续 60 秒重试。现在该明确错误终止发现、丢弃当前运行投影并撤销轮询;正常团队和暂时网络错误沿用原行为。新增共享消费者/重连,以及历史与当前团队并存的回归测试,避免只在 ChatView 层禁止轮询。 + +缺失模板快照时,成员关系直接读取已保存的 materialization;快照只补充显示名称。回归用例同时去掉模板快照和共享父链接,仍从持久化成员关系恢复根/成员关联并保留成员正文副本。 + +## 验收用例到自动测试的对应 + +| 验收条件 | 测试文件与关键用例 | 结果 | +| ---------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------ | +| 官方旧版结构接受独立执行区与归档 | `agent_org_history_store/tests.rs` → `official_old_validator_accepts_fixed_area_beside_new_objects_and_archives` | 自动通过;不替代官方包实机 | +| 官方旧版群聊事件在执行区建表前仍可复制 | `agent_org_history_store/tests.rs` → `official_old_group_mention_is_copied_before_execution_schema_exists` | 通过;正式库首次失败事务回滚后由同一数据成功升级 | +| 2105/2130、缺表与缺模板仍保存事实 | `conformance_tests.rs` → `finalization_and_background_history_inputs_retire_without_interpreting_execution_state`、`saved_materialization_preserves_membership_without_a_template_snapshot_or_parent_link`;`tests.rs` → `partial_old_tables_keep_shared_member_identity_and_body_without_inventing_a_run` | 通过 | +| 原子切换及两次初始化 | `tests.rs` → `raw_schema_blobs_and_all_changes_roll_back_when_completion_write_fails`;`conformance_tests.rs` → `two_initializers_archive_populated_database_exactly_once` | 通过 | +| 当前区损坏拒绝重建、正常重启不重复 | `conformance_tests.rs` → `completion_marker_with_all_execution_tables_missing_is_corruption_not_first_install`、`repeated_old_team_import_does_not_retire_current_members_or_rescan_archived_bodies` | 通过 | +| 所有发送来源和工具入口只读 | `message/tests/history_read_only_tests.rs` → `all_send_sources_and_tool_entries_reject_history_before_loading_a_runtime` | 通过;历史运行实例不创建 | +| 普通副本可读、旧版 stale 不遮正文、源写入与副本原子 | `session-persistence/src/history_compatibility_tests.rs` 两项测试 | 通过 | +| 侧栏、置顶与分页身份一致 | `sidebar_history_tests.rs`、`aggregation/history_tests.rs`、`sections/tests.rs` | 通过;实机可发现与打开 | +| 大历史有界分页,正常启动不扫描正文 | `conformance_tests.rs` → `large_archive_pages_use_keyset_index_and_normal_restart_writes_no_history`;`tests.rs` → `history_pages_are_bounded_stable_and_bound_to_the_requested_session` | 通过 | +| UI 解析身份前禁止写入,失败/切换/分页有界 | `AgentOrgHistoryBoundary.test.ts` 5 项;`orgTasks/history.test.ts` 3 项 | 通过 | +| 共享工作站历史消费者停止 60 秒重试,当前团队保留刷新 | `agentOrgRunViewStore.test.ts` → `stops history discovery across shared surfaces and reconnects`、`discards a retired projection while continuing to poll a current team` | 通过;最终包跨周期观察另见性能审查 | + +十层均已覆盖,没有跳过编译层。实现已冻结;用户于 2026-09-25 报告两项手测验收成功。没有回传的分项证据保持用户报告属性,不由本记录补写为代理实测。 diff --git a/docs/architecture-audit-2026-09-24/AgentOrgHistoryCompatibilityManualFormalRoundTrip.md b/docs/architecture-audit-2026-09-24/AgentOrgHistoryCompatibilityManualFormalRoundTrip.md new file mode 100644 index 0000000000..3e10ed97cc --- /dev/null +++ b/docs/architecture-audit-2026-09-24/AgentOrgHistoryCompatibilityManualFormalRoundTrip.md @@ -0,0 +1,106 @@ +# 正式数据往返手测:官方 v2.0.8 ↔ 修复版 BuildFast + +**状态:用户于 2026-09-25 报告往返验收成功。** 本指南使用本机正式 `~/.orgii` 数据环境。代理准备版本、备份和启动入口;版本切换和团队操作由用户执行。 + +## 已固定的起点 + +- 正式数据目录:`~/.orgii` +- 正式外部历史发现主目录:`$HOME`,因此 Codex 来源为 `~/.codex/sessions` +- 官方应用:`/Applications/ORG2.app` +- 官方版本:v2.0.8;二进制 SHA-256:`c11a1e709ee6b27014a7fbb413fa97b158ddf4448dc8a678e3d473796b83d267` +- 修复版:`/private/tmp/org-history-verification/build-final/ORG2 Instance 31.app` +- 修复版二进制 SHA-256:`845b3235a510a860aef13efb603a2f048a71bb6e6963da0c1501dbb8ffdcb58b` +- 升级前备份:`~/.orgii-agent-org-history-before-fixed-20260924-225841/sessions.db` +- 备份 SHA-256:`a598dcc3fba0979edee3bebb48fb95a2fdeb7dc919c94501ce6253d063493161` +- 双击启动器:`/private/tmp/org-history-verification/ORG2 BuildFast 正式数据.app` +- 命令行启动器:`/private/tmp/org-history-verification/launch-app.py` +- 只读取证:`/private/tmp/org-history-verification/inspect-history.py` + +升级前数据库已经过 `PRAGMA quick_check`,结果为 `ok`:638 个 session、3,311 条事件、6,626 条模型用量记录、25 个旧运行区团队、18 份已保存报告;旧结构指纹为 v2.0.8 的 `ca0b99fc4d60fe4a4d691c405114d7e48009b8b86fdeec78cf1a0f82998cd352`。 + +## 切换版本的硬规则 + +1. 任一时刻只能运行一个 ORG2 进程。切换前使用 Command+Q 真退出,等待窗口和进程消失。 +2. BuildFast 必须使用“ORG2 BuildFast 正式数据.app”或下面的命令行启动器;不能直接双击 `build-final/ORG2 Instance 31.app`,后者会按 Instance 31 规则进入隔离数据目录。 +3. 官方 v2.0.8 可从 `/Applications/ORG2.app` 正常启动,也可用启动器的 `--version official`;二者二进制哈希相同。 +4. 不删除历史表、兼容副本或原始归档,不手动修数据库来让步骤通过。 +5. Command+5 会包含正常的本地 IPC。按根/成员 session ID 判断模型请求;列表和正文读取不算团队执行。 + +启动器在使用正式 profile 时要求 `--allow-primary-profile`,并且检测到任何 ORG2 进程都会拒绝启动,防止两个版本同时写正式数据库。正式模式把 `ORGII_EXTERNAL_HISTORY_HOME` 设为用户主目录 `$HOME`;不能改成 `~/.orgii/external-history-home`,否则应用会把真实 `~/.codex/sessions` 判为不存在,并在重扫期间暂时清空 Codex 侧栏缓存。 + +## A:修复版首次升级 + +代理已完成本阶段的非模型启动检查:正式 session 可见,旧团队根报告和 Implementer 正文可读,界面显示“旧版本会话,仅供查看”。数据库结果为 638 个源 session、3,311 条源事件、18 份报告全部保持;421 个历史身份及普通兼容副本、88 个可发现历史根、1 个归档批次;旧运行区和新执行区均为 0,重复来源映射/副本 ID 均为 0,`PRAGMA quick_check` 为 `ok`。证据是 `manual-evidence/formal-before-fixed.json` 与 `manual-evidence/formal-after-fixed-ready.json`。用户随后报告 B/C/D 往返成功。 + +双击 `/private/tmp/org-history-verification/ORG2 BuildFast 正式数据.app`,或执行等价命令: + +```sh +python3 /private/tmp/org-history-verification/launch-app.py \ + --version fixed \ + --profile "$HOME/.orgii" \ + --allow-primary-profile \ + --label formal-fixed-ready +``` + +预期:应用正常进入工作台,能看到原正式 session;此前 25 个团队作为“旧版本会话,仅供查看”出现,普通 session、项目和设置仍可用。不得出现应用错误、空白侧栏、结构校验错误或自动重放旧团队。 + +先打开你熟悉的普通 session 和至少两个旧团队,分别检查根正文、成员、群聊和报告。再执行: + +```sh +python3 /private/tmp/org-history-verification/inspect-history.py \ + --profile "$HOME/.orgii" \ + --out /private/tmp/org-history-verification/manual-evidence/formal-A-fixed.json +``` + +记录 UI 截图、Command+5、启动 JSON 和对应 `.log`。失败判定包括:原 session 消失、旧团队可执行、正文/报告打不开、归档或副本重复、历史 session 发出模型请求。 + +## B:在修复版创建真实模型团队 + +按[新团队真实模型手测指南](AgentOrgHistoryCompatibilityManualNewTeam.md)执行最小任务,但数据目录保持本指南的正式 `~/.orgii`,不要改回 `profile-final`。记录新团队根/成员 ID、真实模型请求、任务输出、报告和结果文件。 + +退出并重新启动一次修复版,确认新团队仍在新版执行区、旧团队仍只读且没有重复导入。再次保存取证 JSON,例如 `formal-B-fixed-restart.json`。 + +## C:降级到官方 v2.0.8 + +先 Command+Q 退出 BuildFast,再确认没有 ORG2 进程。推荐用同一启动器保留日志: + +```sh +python3 /private/tmp/org-history-verification/launch-app.py \ + --version official \ + --profile "$HOME/.orgii" \ + --allow-primary-profile \ + --label formal-official-downgrade +``` + +预期:官方 v2.0.8 正常打开;原正式普通 session 仍可读;旧团队和修复版新团队的普通兼容副本可发现并打开正文/报告。旧版可能显示输入控件,不要求其强制只读;不要通过兼容副本发送消息。新版执行表必须保留,旧版不得清空它。 + +可在官方版另建一个小团队并保存可见正文、群聊和报告,用于验证再次升级的新增旧团队归档。退出后保存 `formal-C-official.json`。 + +## D:再次升级修复版 + +确认官方版已退出后,重新执行 A 的 BuildFast 启动命令,将 `--label` 改为 `formal-fixed-reupgrade`。 + +预期:最初 25 个旧团队和 C 阶段新增团队均为历史只读;B 阶段新团队仍在新版执行区,ID、正文和报告保留;普通兼容副本不会在新版侧栏造成重复;历史团队不产生模型请求或自动重放。退出、再启动一次,归档批次、历史身份和副本映射不再增加。 + +## 每阶段记录 + +| 指标 | 升级前 v2.0.8 | A 修复版 | B 修复版重启 | C v2.0.8 | D 再升级 | D 重启 | +| ---------------------- | ------------- | ------------ | ------------ | ------------ | ----------- | ------ | +| 全部 session / event | 638 / 3,311 | | | | | | +| 旧运行区团队数 | 25 | 0 | 0 | C 新团队数 | 0 | 0 | +| 新执行区团队 ID | 无 | 0 | B | B | B | B | +| 历史根 / 历史会话数 | 无 | | 不增加 | 保留 | 增加 C | 不增加 | +| 普通兼容副本数 | 无 | | 不增加 | 保留 | 增加 C | 不增加 | +| 源会话正文哈希 | 基线 | 保持 | 保持 | 保持 | 保持 | 保持 | +| 已保存报告数 / 哈希 | 18 / 基线 | 保持并增加 B | 保持 | 保持并增加 C | 全保留 | 保持 | +| 原始归档批次数 | 无 | 1 | 1 | 1 | 因 C 增加 1 | 不增加 | +| 重复来源映射 / 副本 ID | 无 | 0 / 0 | 0 / 0 | 0 / 0 | 0 / 0 | 0 / 0 | +| 历史模型请求 | — | 0 | 0 | 不验收续跑 | 0 | 0 | + +每阶段同时保留:侧栏、成员与报告 UI;取证 JSON;启动 JSON 和 `.log`;Command+5 中请求对应的 session ID;B/C 测试文件实际字节。若数量发生合法变化,必须能由新团队和稳定来源映射解释,不能只比较全库总数。 + +## 失败与恢复 + +任一步失败,先退出应用并保存当时 `sessions.db`、`-wal`、`-shm` 和日志,不要继续下一个版本。升级前备份已经独立保留,且不含运行中的 WAL 依赖。恢复会覆盖正式数据库,必须在所有 ORG2 进程退出、失败现场另存后再做;不要边运行边复制,也不要只删兼容表。 + +用户已报告完整往返通过。收尾只读快照保留 638 个源 session、18 份报告、421 个历史身份和副本、88 个历史根、1 个归档批次;新旧执行区均为 0,重复来源映射和副本 ID 均为 0,旧区指纹仍为固定 v2.0.8 值。用户未回传每阶段表格、截图和 Command+5 记录,因此这些数量是代理可复核的最终快照,完整操作结论仍标记为用户签收。 diff --git a/docs/architecture-audit-2026-09-24/AgentOrgHistoryCompatibilityManualNewTeam.md b/docs/architecture-audit-2026-09-24/AgentOrgHistoryCompatibilityManualNewTeam.md new file mode 100644 index 0000000000..efd5b71468 --- /dev/null +++ b/docs/architecture-audit-2026-09-24/AgentOrgHistoryCompatibilityManualNewTeam.md @@ -0,0 +1,113 @@ +# 手测 1:修复版新团队和真实模型执行 + +**状态:用户于 2026-09-25 报告验收成功。** 新团队和真实模型步骤由用户执行;代理未代为发送请求。用户未回传团队 ID、Command+5 截图或结果文件,因此本文件记录用户签收,不将缺失的分项证据写成代理实测。 + +若从[正式数据往返指南](AgentOrgHistoryCompatibilityManualFormalRoundTrip.md)进入本项,只复用本文件的任务原文、操作和判定;应用启动、数据目录、前后取证路径以正式数据往返指南为准。下面的 `profile-final` 启动说明仅适用于隔离夹具模式。 + +> 这是隔离验收环境,不是你的正式 `~/.orgii` 数据库。正式 session 不会出现在这里;当前夹具只有 25 个历史源会话及其 25 个普通兼容副本。下面的 `.app` 路径只用于固定测试版本,**不要直接双击启动**,因为双击不会设置本指南要求的数据目录。始终使用下方 `launch-app.py` 命令启动。 + +正式数据模式已经由用户明确选择,并完成一致性备份和首次升级检查。若从正式数据往返指南进入,忽略本节的隔离 profile 提示,保持使用 `~/.orgii`;仍需保证任一时刻只有一个 ORG2 进程。若单独执行本指南,继续使用下面的隔离夹具。 + +## 固定版本与启动 + +- BuildFast:`/private/tmp/org-history-verification/build-final/ORG2 Instance 31.app` +- 可执行文件:上述 `.app/Contents/MacOS/org2` +- 二进制 SHA-256:`845b3235a510a860aef13efb603a2f048a71bb6e6963da0c1501dbb8ffdcb58b` +- 分支:`codex/agent-org-history-compatibility`;基线:`22767a2a4f3185b127bf6d5669302cffcbe6dce4` +- 隔离数据:`/private/tmp/org-history-verification/profile-final` +- 隔离外部历史:`/private/tmp/org-history-verification/profile-final/external-history` +- 测试输出目录:`/private/tmp/org-history-verification/new-team-workspace` +- 身份:`org2ai.org2.instance31`;API 13877;代理 17918 + +若测试实例已经由下方脚本启动,可直接使用。否则只对 **ORG2 Instance 31** 使用 Command+Q 并确认退出,再运行: + +```sh +python3 /private/tmp/org-history-verification/launch-app.py \ + --version fixed \ + --profile /private/tmp/org-history-verification/profile-final \ + --label new-team +``` + +启动器会校验 SHA-256、拒绝重复启动相同实例、设置两处隔离目录并去掉 E2E 模拟变量。不要用其他安装包代替,也不要退出主 ORG2。每次启动的 PID、时间、版本和日志路径写入 `manual-evidence/*-launch.json`;同目录 `.log` 是对应进程日志。 + +启动后侧栏应看到隔离夹具中的 5 个历史团队,而不是你正式环境中的 session。若侧栏完全没有这 5 个团队,先退出测试实例并重新执行上述脚本;不要通过“改成正式数据库”来修正启动方式。 + +先自行完成测试模型账户登录;此前隔离账户的过期错误只作为环境证据保留。本指南不要求复用该账户。 + +## 记录起点 + +```sh +mkdir -p /private/tmp/org-history-verification/manual-evidence +python3 /private/tmp/org-history-verification/inspect-history.py \ + --profile /private/tmp/org-history-verification/profile-final \ + --out /private/tmp/org-history-verification/manual-evidence/new-team-before.json +mkdir -p /private/tmp/org-history-verification/new-team-workspace +``` + +脚本只读数据库,不打印凭据。初始夹具应有 5 个历史团队、25 个历史会话、25 个普通副本、947 条原始事件、13 份已保存报告;旧运行区为 0,新执行区为 0。若你此前已做过测试,以保存的 `before.json` 实际值为准,不删除历史来凑数量。 + +Command+5 同时记录本地 IPC;判断时按根/成员会话 ID 区分真实模型请求与列表/正文读取,不能用面板总请求数代替模型请求数。 + +## 操作与判定 + +| 步骤 | 操作 | 预期结果 / 失败判定 | +| ---- | ------------------------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------- | +| 1 | 新会话选择 Default Agent Org、可用真实模型,并选择上述独立输出目录 | 显示新版团队操作界面,不能出现历史只读提示;工作目录不得指向代码仓库或旧夹具项目 | +| 2 | 发送下方最小任务 | Command+5 出现此**新团队根/成员**的真实请求;若只有登录错误、排队或模型口头答复而没有真实请求,不算通过 | +| 3 | 等待 Implementer 与 Reviewer/Tester 完成 | 正式任务有输出、独立验证完成、保存最终报告;不能只有聊天文本“已完成” | +| 4 | 读文件、抓取数据库、日志和请求记录 | `hello.txt` 恰为 18 字节 `HISTORY_COMPAT_OK\n`;新执行区增加 1 个团队;对应会话存在副本;原 5 个历史团队不产生请求、不变成 current | +| 5 | Command+Q 真退出,再用同一命令启动 | 原新团队 ID 保持在新执行区,任务/报告仍可读;不得清空或退休成历史;不得重复产生执行团队或副本 | +| 6 | 回到旧团队,切成员、翻页,再看 Command+5 | 历史仍无输入执行控件;不能出现属于旧根/成员的新模型请求;旧正文/报告哈希不变 | + +建议任务原文: + +```text +只在 /private/tmp/org-history-verification/new-team-workspace 工作。 +使用最小正式团队流程:Implementer 创建 hello.txt,内容恰好是 HISTORY_COMPAT_OK 加一个换行;Reviewer 或 Tester 独立读取并核对完整字节。记录正式 TaskOutput,完成交付认证并保存简短最终报告。不要启动服务、安装依赖、提交 Git,也不要修改目录外的文件。 +``` + +文件独立检查: + +```sh +python3 - <<'PY' +from pathlib import Path +p = Path('/private/tmp/org-history-verification/new-team-workspace/hello.txt') +data = p.read_bytes() +print('bytes:', len(data), 'repr:', repr(data)) +assert data == b'HISTORY_COMPAT_OK\n' +PY +``` + +## 同一团队继续回归 + +以下是用户计划要求的真实模型回归项。用户已给出整体验收成功结论,但没有回传每项前后快照和 Command+5 记录;因此这些步骤继续作为可复现清单,不单独宣称每一格都有机器证据。 + +| 场景 | 可直接执行的操作 | 预期 / 失败判定 | +| --------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------ | +| 暂停后交付 | 追加给 Implementer 的任务:若 `pause.marker` 不存在,创建它并同步等待 90 秒;若已存在则跳过等待,写 `pause-result.txt` 为 `RESUMED\n`。在等待时通过团队按钮暂停,确认进入 Paused,再恢复 | 同一正式 Task ID 继续;结果文件和最终报告保存;不得重复创建替代任务来冒充恢复 | +| 报告 Stop/Retry | 在任务结束、最终报告仍在生成时点击 Stop;确认报告停止,再 Retry | 新请求属于报告重试;正式任务不重新执行;只保留有效报告结果,不重复交付。如果模型太快而未捕获生成中窗口,记为未覆盖 | +| 结算禁发 | 在最终报告生成的结算阶段尝试发普通团队消息 | 明确禁止/拒绝,不接收为新任务,不产生额外执行授权;请求不能偷偷排队到下一轮 | +| 拒绝请求恢复 | 在团队空闲时自行使测试模型凭据不可用,发送一条小任务,确认拒绝;恢复可用账户并使用产品重试入口 | 错误清晰;重试不丢正文、不重复正式任务;只有有效请求产生真实用量。只改测试实例配置 | + +## 每阶段证据 + +将快照命令中的文件名改为 `new-team-after-delivery.json`、`new-team-after-restart.json`、`new-team-after-pause.json` 等: + +```sh +python3 /private/tmp/org-history-verification/inspect-history.py \ + --profile /private/tmp/org-history-verification/profile-final \ + --out /private/tmp/org-history-verification/manual-evidence/new-team-after-delivery.json +``` + +检查并回传: + +- UI:团队根标题、成员、任务状态、报告正文、旧历史只读提示截图 +- 数据库:`runs.agent_org_execution_runs` 中新团队 ID;`history_roots` 仍为原历史;每个源会话事件数量与正文哈希;报告数;副本映射 +- 重复检查:`duplicate_source_mappings=0`、`duplicate_copy_ids=0`、`copy_authority_violations=[]`;当前新增报告的 `copy_body_matches=true` +- 日志:对应启动记录中的 `.log`,保留发送、暂停、恢复、报告保存时段,不把凭据贴入记录 +- 文件:`hello.txt` 和后续暂停测试文件实际字节 +- Command+5:模型名、根/成员会话 ID、请求时间与结果;历史会话请求数应为 0 + +回传格式:每项 `PASS / FAIL / 未覆盖`,新团队根 ID、模型、前后 JSON 文件、相关请求截图、文件验证输出、错误或日志时间段。用户已报告整体 `PASS`;若后续补交分项材料,可追加到验收记录,无需修改产品实现。 + +只读取证脚本同时输出 `source_session_count`(扣除兼容副本的会话数)、`source_event_count`(原会话事件数)、`compatibility_copy_event_count`(副本事件数);历史群聊/可见输出按种类统计在 JSON 的 `visible_items_by_kind`。总事件数增加可以来自合法副本,必须结合这些分类和逐会话 ID/哈希判定,不要直接比较全库总数推断丢失或重复。 diff --git a/docs/architecture-audit-2026-09-24/AgentOrgHistoryCompatibilityManualRoundTrip.md b/docs/architecture-audit-2026-09-24/AgentOrgHistoryCompatibilityManualRoundTrip.md new file mode 100644 index 0000000000..fb41a17828 --- /dev/null +++ b/docs/architecture-audit-2026-09-24/AgentOrgHistoryCompatibilityManualRoundTrip.md @@ -0,0 +1,163 @@ +# 手测 2:官方 v2.0.8 → 修复版 → v2.0.8 → 修复版 + +**状态:备用指南,未单独执行。** 用户后来选择正式 `~/.orgii` 路径完成往返并于 2026-09-25 报告成功;本文件保留独立 macOS 用户或另一台 Apple Silicon 测试机的可复现方案,不宣称这条备用路径也已执行。 + +## 需要带到测试环境的文件 + +将 `/private/tmp/org-history-verification` 中以下内容复制到测试环境的同一目录(例如 `$HOME/OrgHistoryManual`),保持相对结构: + +- `build-final/ORG2 Instance 31.app`:修复版 BuildFast +- `official-v2.0.8/ORG2.app`:未经修改的正式 v2.0.8 +- `official-v2.0.8/ORG2-updater-mac-apple-silicon.app.tar.gz`:原始发布包 +- `launch-app.py`、`inspect-history.py`、`manual-artifacts.json`:启动、只读取证和版本清单 + +**不要复制 `profile`、`profile-final` 或凭据文件作为本项起点**;它们来自前置 PR 隔离夹具。本项必须让官方 v2.0.8 在全新测试目录中建立自己的数据库。 + +| 版本 | 原机应用路径 | 二进制 SHA-256 | +| ----------- | ------------------------------------------------------------------------ | ------------------------------------------------------------------ | +| 修复版 | `/private/tmp/org-history-verification/build-final/ORG2 Instance 31.app` | `845b3235a510a860aef13efb603a2f048a71bb6e6963da0c1501dbb8ffdcb58b` | +| 官方 v2.0.8 | `/private/tmp/org-history-verification/official-v2.0.8/ORG2.app` | `c11a1e709ee6b27014a7fbb413fa97b158ddf4448dc8a678e3d473796b83d267` | + +正式发布压缩包 SHA-256:`7479d1cdc36e94d028ed8e806adffd12d0507790be3e873ba19bdb3a1005d3dc`。来源:[官方 v2.0.8 发布包](https://github.com/org2AI/ORG2/releases/download/v2.0.8/ORG2-updater-mac-apple-silicon.app.tar.gz)。表中的二进制哈希与压缩包哈希是不同对象,不能混用。 + +## 一次设置 + +以下命令在**独立测试用户/机器**的 Terminal 执行;若文件复制位置不同,仅修改第一行: + +```sh +VERIFY_ROOT="$HOME/OrgHistoryManual" +VERIFY_PROFILE="$VERIFY_ROOT/roundtrip-profile" +mkdir -p "$VERIFY_PROFILE" "$VERIFY_ROOT/manual-evidence" "$VERIFY_ROOT/roundtrip-workspace" +``` + +每次启动都用脚本设置相同 `ORGII_HOME=$VERIFY_PROFILE` 和 `ORGII_EXTERNAL_HISTORY_HOME=$VERIFY_PROFILE/external-history`。官方包的 WebView 身份仍是系统中的主应用身份,因此独立系统用户/测试机是必要条件;数据目录变量不能代替它。 + +启动器校验二进制哈希、拒绝已有 ORG2 进程时启动官方包,不会关闭任何应用。切换前必须 Command+Q 确认退出。不要修改 app 标识或注入替代 SQL 来让旧版“通过”。如系统要求正式应用的正常首启操作,请由你完成;不要关闭系统安全保护。 + +## 逐阶段操作 + +### A:官方旧版建立基线 + +```sh +python3 "$VERIFY_ROOT/launch-app.py" --version official \ + --profile "$VERIFY_PROFILE" --label A-old-first +``` + +1. 自行配置可用测试模型,在 `roundtrip-workspace` 创建旧团队 **A**。让至少一个成员写文件 `old-a.txt` 为 `OLD_A\n`,另一成员读取验证,保存可见最终报告。 +2. 加一条可辨认的群聊消息,例如 `ROUNDTRIP_OLD_A_GROUP`,保留成员回复;记录根与成员会话 ID。 +3. 再建立一个普通会话 **S**,保存文字 `ROUNDTRIP_ORDINARY_S`。记录一个普通项目/设置值,后面检查它们没有被迁移重置。 +4. Command+5 保存 A 的真实请求记录;不要把仍运行中的任务当成已保存报告。 +5. 真退出旧版,取证并备份整份隔离数据: + +```sh +python3 "$VERIFY_ROOT/inspect-history.py" --profile "$VERIFY_PROFILE" \ + --out "$VERIFY_ROOT/manual-evidence/A-old-before-upgrade.json" +ditto "$VERIFY_PROFILE" "$VERIFY_ROOT/backup-A-old" +``` + +**预期:** 旧版正常初始化;A 的根/成员/群聊/报告和 S 可读。若出现结构校验错误、未落盘或模型失败,先记录,A 不算完成,不能直接跳到后续阶段宣称往返通过。 + +### B:首次升级到修复版 + +```sh +python3 "$VERIFY_ROOT/launch-app.py" --version fixed \ + --profile "$VERIFY_PROFILE" --label B-fixed-first +``` + +1. 在侧栏及置顶列表打开 A;切换成员、查看群聊和保存内容、翻页、查看最终报告。 +2. A 显示“旧版本会话,仅供查看”,不能发送/恢复/重试旧团队;Command+5 不得出现 A 根/成员的新模型请求。 +3. S、普通项目和设置保持;不要把 S 变成只读团队历史。 +4. 让修复版新建团队 **B**,使用真实模型写 `new-b.txt` 为 `NEW_B\n` 并保存报告。B 应拥有新版团队操作;它必须与 A 的只读身份区别明确。 +5. 退出后取证,再启动/退出一次取第二份快照,检查正常重启幂等: + +```sh +python3 "$VERIFY_ROOT/inspect-history.py" --profile "$VERIFY_PROFILE" \ + --out "$VERIFY_ROOT/manual-evidence/B-fixed-before-restart.json" +python3 "$VERIFY_ROOT/launch-app.py" --version fixed \ + --profile "$VERIFY_PROFILE" --label B-fixed-restart +# 在 UI 打开 A 和 B 后,Command+Q 退出,再执行: +python3 "$VERIFY_ROOT/inspect-history.py" --profile "$VERIFY_PROFILE" \ + --out "$VERIFY_ROOT/manual-evidence/B-fixed-after-restart.json" +ditto "$VERIFY_PROFILE" "$VERIFY_ROOT/backup-B-fixed" +``` + +**预期:** A 成为历史;B 在新执行区;固定旧运行区为空;普通副本无执行关联。两次 B 快照的历史身份、归档批次、副本映射数量不增加,B 团队 ID 不变。源正文/报告哈希不丢失。出现空库、A 可执行、B 被退休或重启重复导入均判失败。 + +### C:降级回官方 v2.0.8 + +```sh +python3 "$VERIFY_ROOT/launch-app.py" --version official \ + --profile "$VERIFY_PROFILE" --label C-old-downgrade +``` + +1. 必须看到应用正常打开,无数据库结构校验错误。 +2. 找到 A 和 B 的普通历史副本,打开根/成员正文、群聊和报告;名字保留团队/成员含义。用前一步 JSON 的 `copy_mapping` 对照会话身份;如果列表看不到或打不开,即使数据库有行也判失败。 +3. 旧版可能仍显示输入控件,本项不要求它强制只读;**不要通过副本发送消息**作为兼容性验收。副本不得关联新版执行区。 +4. 旧版另建团队 **C**,保存文字、成员输出、群聊标记 `ROUNDTRIP_OLD_C_GROUP` 和报告;写 `old-c.txt` 为 `OLD_C\n`。 +5. 退出后取证和备份: + +```sh +python3 "$VERIFY_ROOT/inspect-history.py" --profile "$VERIFY_PROFILE" \ + --out "$VERIFY_ROOT/manual-evidence/C-old-before-reupgrade.json" +ditto "$VERIFY_PROFILE" "$VERIFY_ROOT/backup-C-old" +``` + +**预期:** A/B 已保存历史可发现且可读,原报告正文匹配;新执行区 B 的结构与记录仍存在。旧版可以将共享排队项改为 stale,不要求未完成任务继续执行。C 留在旧运行区,等待再升级归档。若旧版删除/重置新执行区、正文或报告丢失,则失败。 + +### D:再次升级修复版 + +```sh +python3 "$VERIFY_ROOT/launch-app.py" --version fixed \ + --profile "$VERIFY_PROFILE" --label D-fixed-reupgrade +``` + +1. A 与 C 都可发现、可读、只读;B 仍在当前执行区,原 ID、报告和正文保留;S 保持普通会话。 +2. 新版列表只展示源团队身份,不展示普通兼容副本造成的重复团队。 +3. 打开 A/C、成员切换、翻页后,Command+5 不得有这些历史会话的新请求;不能自动重放 A/C 退休任务。 +4. 退出取证,再正常启动/退出一次,检查没有再次导入 C: + +```sh +python3 "$VERIFY_ROOT/inspect-history.py" --profile "$VERIFY_PROFILE" \ + --out "$VERIFY_ROOT/manual-evidence/D-fixed-first.json" +python3 "$VERIFY_ROOT/launch-app.py" --version fixed \ + --profile "$VERIFY_PROFILE" --label D-fixed-repeat +# UI 检查后 Command+Q,再执行: +python3 "$VERIFY_ROOT/inspect-history.py" --profile "$VERIFY_PROFILE" \ + --out "$VERIFY_ROOT/manual-evidence/D-fixed-repeat.json" +``` + +**预期:** C 只归档一次;D 两份快照的归档批次、历史身份、兼容副本数量及映射相同。B 不清空,A/C 不恢复执行,旧运行区再次为空。副本不能带 org/member/parent/work-item 执行关联。 + +Command+5 同时记录本地 IPC;对照具体根/成员会话 ID 和模型请求目标,列表刷新、正文读取并不代表执行旧团队。 + +## 每个阶段必须记录的数量 + +不要只记全库 `events` 总数:兼容副本的新增本来就会使总数增加。以下表每列填实际数,并同时保留脚本输出 JSON。 + +| 指标 | A 旧版基线 | B 首次升级 | B 重启 | C 降级后 | D 再升级 | D 重启 | +| --------------------------------- | ---------- | ----------------- | ------ | -------------------- | ----------------- | ------ | +| 旧运行区团队数及根 ID | | 0 | 0 | 新 C | 0 | 0 | +| 新执行区团队数及根 ID | 无 | B | 同 B | 同 B | 同 B | 同 B | +| 历史根团队数及 ID | 无 | A | 同左 | 同左 | A+C | 同左 | +| 历史根/成员会话数 | 无 | | 不增加 | | 仅增加 C 关联会话 | 不增加 | +| 普通兼容副本数与来源映射 | 无 | A+B 的已保存会话 | 不增加 | 不应删除 | 增加 C 副本 | 不增加 | +| 全部 agent_sessions / events 行数 | | | | | | | +| 各**源**会话事件数 / 正文哈希 | | 原 A/S 保持 | 保持 | A/B/S 保持 | A/B/C/S 保持 | 保持 | +| 已保存报告数 / 正文哈希 | | 原 A 保留、另有 B | 保持 | A/B 保留、另有 C | 全保留 | 保持 | +| 原始归档批次数 | 无 | 首次一批 | 不增加 | 不增加 | 因 C 新增一批 | 不增加 | +| 重复来源映射 / 重复副本 ID | 无 | 0 / 0 | 0 / 0 | 0 / 0 | 0 / 0 | 0 / 0 | +| 历史身份对应新增模型请求 | — | 0 | 0 | 不作为未完成续跑验收 | 0 | 0 | + +脚本 `sessions` 包含逐会话事件 ID/正文哈希;`reports` 包含逐报告正文与副本匹配结果;`counts`、`history_roots`、`runs`、`copy_mapping` 是数量与身份依据。完整历史保留可能包含合法重复文本,不能按正文相同就当作重复导入;应比较稳定来源/事件 ID 和映射。 + +最终固定旧区指纹应为 `ca0b99fc4d60fe4a4d691c405114d7e48009b8b86fdeec78cf1a0f82998cd352`。指纹只能证明结构,不替代官方应用真正打开和浏览。 + +## 需要回传的证据及失败处理 + +每阶段保存 UI 截图(侧栏、成员、报告、只读提示)、Command+5 请求会话 ID/时间/结果、取证 JSON、启动 JSON、同次 `.log`、三个结果文件的字节校验。普通 S 的正文及项目/设置也需前后对照。日志不可包含你复制粘贴的凭据。 + +任一步失败,记录 `FAIL`、阶段、操作和日志时间;保留失败数据库、WAL/SHM 和当时应用版本,退出应用后复制整个 profile 作为故障证据。不要删除表、清空数据或修复后跳过失败阶段。可从对应完整备份复制到另一个测试目录重测。不要把原始归档重新接回执行区,也不要自动复活旧任务。 + +正式数据路径的用户验收结论见 `AgentOrgHistoryCompatibilityAcceptance.md`。本备用路径没有单独证据,不能引用正式库签收来声称独立测试用户/机器也已运行。 + +只读取证脚本同时输出 `source_session_count`(扣除兼容副本的会话数)、`source_event_count`(原会话事件数)、`compatibility_copy_event_count`(副本事件数);历史群聊/可见输出按种类统计在 JSON 的 `visible_items_by_kind`。总事件数增加可以来自合法副本,必须结合这些分类和逐会话 ID/哈希判定,不要直接比较全库总数推断丢失或重复。 diff --git a/docs/frontend-ui-audit-2026-09-24/AgentOrgHistoryBoundary.md b/docs/frontend-ui-audit-2026-09-24/AgentOrgHistoryBoundary.md new file mode 100644 index 0000000000..548c42e5e0 --- /dev/null +++ b/docs/frontend-ui-audit-2026-09-24/AgentOrgHistoryBoundary.md @@ -0,0 +1,17 @@ +# AgentOrgHistoryBoundary UI audit + +| Line | Element | Verdict | Reason | Suggested change | +| --------------------------------- | ------------------ | ---------------- | ---------------------------------------------------------------------------------- | ---------------- | +| `AgentOrgHistoryBoundary.tsx:70` | 读取失败重试 | keep with reason | 使用共享 Button;只重试当前身份查询,未解析前不能发送 | None | +| `AgentOrgHistoryBoundary.tsx:111` | 成员和保存内容切换 | keep with reason | 使用共享小尺寸 Button 和 aria-pressed;允许浏览;不提供运行操作 | None | +| `AgentOrgHistoryBoundary.tsx:143` | 只读提示 | keep with reason | 复用 SessionReadOnlyBar,15 种语言具备对应文案 | None | +| `AgentOrgHistoryBoundary.tsx:208` | 历史分页 | keep with reason | 共享 Button;每页 50 条;不累计无限历史列表;失败显示重试入口 | None | +| `ChatView.tsx:670` | 历史正文 | keep with reason | 复用现有正文分页和 mutationActionsDisabled;运行视图读取关闭,成员身份来自历史描述 | None | + +Verdict totals: **0 fix**, **5 keep with reason**, **0 abstract**. + +控制项复核:新增生产组件没有原生 button/input 或伪造可点击 div;没有 layout="custom" 绕过。自动测试使用真实共享 Button;打包应用已验证深色主题、英文控件、中文/英文正文、成员切换、分页和只读提示;加载/错误由组件测试覆盖。浅色主题、窄窗口和其他语言尚未实机逐项检查。没有提出全仓清理或组件配置级改动。 + +最终包复测:SHA 为 `845b3235a510a860aef13efb603a2f048a71bb6e6963da0c1501dbb8ffdcb58b` 的 BuildFast 已连接正式 `~/.orgii`。侧栏显示原正式会话;旧团队“规划德州扑克游戏开发”的根报告和 Implementer 正文可读,成员切换有效,界面显示“旧版本会话,仅供查看”且没有发送输入区。此前隔离包还验证了长群聊下一页/首页入口、归档根发现与置顶。Computer Use 记录留在本次对话工具记录;状态中保留的旧执行卡片是已保存回放内容,不能当作当前运行投影或新任务完成证据。 + +最后一次生产源检查涵盖新增历史组件、ChatView 以及历史读取 hook:没有新增原生按钮、原生表单字段、可点击 div/span 或自定义布局绕过。分页和成员按钮使用共享组件,身份未解析或失败时不挂可写正文界面。用户于 2026-09-25 报告两项实机验收成功;UI 审查本身仍只证明上表覆盖的界面边界,不替代模型请求或数据库证据。 diff --git a/docs/org2-performance-guard-2026-09-24/AgentOrgHistoryCompatibility.md b/docs/org2-performance-guard-2026-09-24/AgentOrgHistoryCompatibility.md new file mode 100644 index 0000000000..8d68c97321 --- /dev/null +++ b/docs/org2-performance-guard-2026-09-24/AgentOrgHistoryCompatibility.md @@ -0,0 +1,51 @@ +# Agent Org 历史兼容性能复核 + +| Area | Verdict | Evidence | Change or reason kept | Verification | +| ------------------ | ------- | ------------------------------------------------------------------------- | ------------------------------------------------------ | --------------------------------------------------------------------------------------------------------- | +| Background work | keep | 身份读取在打开时触发;历史不挂运行视图轮询;副本在来源写事务内触发 | 无新增轮询、定时导出或退出导出 | 请求单次合并/失败清理/过期响应测试;实机历史零模型请求。另补共享运行视图 store 在历史错误后停止轮询的测试 | +| Memory | keep | 身份 Map 仅保留在途请求,上限 128;历史 UI 仅保留当前 50 条 | 完成/失败立即删除;换会话/卸载丢弃迟到结果 | 前端请求容量测试、分页与切换测试 | +| Scope/isolation | keep | 后端身份为本地 sessions.db;正常实例只读本实例存储 | 数据目录和外部历史目录显式绑定;切换版本前拒绝并行进程 | BuildFast 独立实例与正式 `~/.orgii` 首次升级由代理验证;用户报告官方包往返通过 | +| Rendering/hot path | keep | 成员正文继续使用既有按会话快照和回合分页;副本只检查来源本次写入的事件 ID | 不全量重写;无新长驻订阅 | 真实持久化增量/幂等/回滚测试;大历史索引查询 | +| Startup | keep | 完成标记和执行指纹校验;旧区只检查有限对象及存在性 | 没有旧版新行时不访问历史正文 | 5,000 KiB 测试中首次归档约 1.1 秒、三次正常初始化约 67 毫秒,历史写入数零;不是端到端应用启动指标 | + +| Provider | Raw transition | App/UI state | Topology/boundary | Expected invariant | Observed evidence | +| ------------ | ---------------------------- | --------------- | ------------------- | -------------------------------- | -------------------- | +| 本地团队存储 | 首次升级/再升级新增旧团队 | 初始化/重复启动 | 本地 SQLite | 保存正文和身份,不重放执行 | 单元与持久化契约测试 | +| 本地事件写入 | 新增/重写/相同内容重复写入 | 当前团队 | 原事务→普通副本 | 有限增量、版本只在内容变动时增加 | 跨存储测试通过 | +| 打包应用 | 打开/成员切换/隐藏/关闭/重启 | 隔离实例 | UI→RPC→SQLite/日志 | 没有额外模型请求或持续历史轮询 | 见下方记录 | +| 官方 v2.0.8 | 降级/读取/再次升级 | 独立身份 | 官方包→同一隔离数据 | 旧版可读,回到新版不重复导入 | 见下方记录 | + +不涉及外部 CLI 提供方解析、账号切换、远程共享或双机云同步,不以本次测试宣称这些场景通过。 + +## 实机资源样本及其限制 + +初版隔离包每种状态取 6 个主进程样本、窗口约 25 秒: + +| 状态 | 主进程平均 CPU(累计 CPU 时间差) | 主进程 RSS KiB | 历史事件 / 模型用量记录 | +| ------------ | --------------------------------- | --------------- | ----------------------- | +| 历史可见 | 4.55% | 237,728–237,776 | 947 / 720,不变 | +| 应用隐藏 | 0.00% | 238,224–238,272 | 947 / 720,不变 | +| 历史标签关闭 | 0.36% | 239,552–239,600 | 947 / 720,不变 | + +这些是主进程局部样本,不是 WebView 总内存、长期稳定性或原版本性能对比。可见状态仍复用既有正文/Agent Station 渲染,不能将其 CPU 视为迁移成本。 + +随后发现 Agent Station 共享运行视图收到历史只读错误时仍保留 60 秒 fallback,已在共享 store 修正;自动测试证明多个消费者和重连不继续发现,当前团队仍可轮询。初版 25 秒窗口无法证明原 60 秒 fallback 不存在,不把初版样本误当作修正通过证据。最终安装包已使用新的隔离旧库重复浏览,跨过 60 秒周期;Command+5 没有历史运行视图持续请求,只有原有侧栏刷新和按需正文读取。最终量化样本见下表。 + +## 最终安装包复测 + +资源量化使用的候选包 SHA-256 为 `fb4b52ad4bd774b6d663dc06008f76a91ab384320ae49cb3c3149b632693f959`,隔离数据目录 `profile-final`。最终包在正式库暴露并修复首次迁移的旧群聊事件顺序问题后重建,SHA-256 为 `845b3235a510a860aef13efb603a2f048a71bb6e6963da0c1501dbb8ffdcb58b`;该修正只避免执行区建表前的查询,没有增加轮询、订阅或正文扫描。未新建团队或调用模型,未启动官方包。 + +| 状态 | 主进程平均 CPU | 主进程 RSS KiB | 历史原事件 / 模型用量记录 | +| -------------------- | -------------- | --------------- | ------------------------- | +| 历史可见 | 4.05% | 228,576–233,024 | 947 / 720,不变 | +| 应用隐藏 | 0.01% | 251,424–251,504 | 947 / 720,不变 | +| 离开历史(标签保留) | 1.24% | 247,568–247,728 | 947 / 720,不变 | +| 关闭历史标签 | 0.17% | 249,344–249,424 | 947 / 720,不变 | + +每种状态 16 个样本,约 75 秒,覆盖原运行视图 60 秒重试周期;“离开历史”是切换到空白新会话而保留旧标签,“关闭历史”才是明确关闭该标签。历史原事件始终 947,模型用量记录始终 720。原始样本与汇总分别保存为 `final-lifecycle-samples.jsonl`、`final-lifecycle-summary.json`。反复打开、成员切换和保存内容下一页均通过;归档根可置顶;真实重启数量对照见最终验收记录。 + +样本只包含测试主进程,不能代替 WebView/子进程总资源、长期内存稳定性或旧版性能对照。现有侧栏每约 15 秒刷新属于原行为;本次未扩展到该轮询的全仓治理,也不声称零后台请求。 + +Performance verdict: pass with evidence boundary — 历史浏览生命周期的自动检查和最终包短窗口实测已完成;用户于 2026-09-25 报告“新团队真实模型增量写入/恢复”和“官方 v2.0.8 降级/再升级”两格验收成功。代理没有代为执行模型请求,且未收到逐项资源样本,因此该签收只关闭人工验收门槛,不扩展为长期内存、整机资源或旧版性能对照结论。 + +正式库首次升级补充证据:3.3 GB 数据库在一次启动事务中完成切换,638 个源 session、3,311 条源事件及 18 份报告保持,421 个兼容副本一次生成;重复映射为 0,新旧执行区均为空,启动后没有新增模型用量记录。此证据验证一次性迁移及浏览,不扩展为长期资源、真实模型写入或官方版往返结论。 diff --git a/src-tauri/crates/agent-core/src/core/coordination/agent_inbox/message_tests.rs b/src-tauri/crates/agent-core/src/core/coordination/agent_inbox/message_tests.rs index 3cbaff48d6..0685f0985f 100644 --- a/src-tauri/crates/agent-core/src/core/coordination/agent_inbox/message_tests.rs +++ b/src-tauri/crates/agent-core/src/core/coordination/agent_inbox/message_tests.rs @@ -19,7 +19,7 @@ fn sandbox_with_inbox_schema() -> test_helpers::test_env::SandboxGuard { fn seed_minimal_running_run_for_delivery_resolution(run_id: &str) { let conn = get_connection().expect("open sandbox database"); conn.execute_batch( - "CREATE TABLE IF NOT EXISTS agent_org_runtime_runs ( + "CREATE TABLE IF NOT EXISTS agent_org_execution_runs ( id TEXT PRIMARY KEY, status TEXT NOT NULL, org_snapshot_json TEXT, @@ -41,7 +41,7 @@ fn seed_minimal_running_run_for_delivery_resolution(run_id: &str) { org_member_id TEXT, updated_at TEXT NOT NULL ); - CREATE TABLE IF NOT EXISTS agent_org_runtime_tasks ( + CREATE TABLE IF NOT EXISTS agent_org_execution_tasks ( id TEXT PRIMARY KEY, org_run_id TEXT NOT NULL );", @@ -57,7 +57,7 @@ fn seed_minimal_running_run_for_delivery_resolution(run_id: &str) { ) .expect("seed coordinator session"); conn.execute( - "INSERT INTO agent_org_runtime_runs ( + "INSERT INTO agent_org_execution_runs ( id,org_id,coordinator_agent_id,status,org_snapshot_json, root_session_id,entry_mode,created_at,updated_at ) VALUES (?1,'delivery-repair-org','coordinator','running',NULL,?2, @@ -75,7 +75,7 @@ fn seed_legacy_orphan_inbox_row(run_id: &str, summary: &str, text: &str) -> Agen let payload_json = serde_json::to_string(&message).expect("serialize legacy payload"); let conn = get_connection().expect("open sandbox database"); conn.execute( - "INSERT INTO agent_org_runtime_inbox ( + "INSERT INTO agent_org_execution_inbox ( recipient_agent_id, recipient_member_id, sender_agent_id, sender_member_id, org_run_id, payload_kind, payload_json, request_id, @@ -720,7 +720,7 @@ fn delivery_resolution_invalidates_stale_materialization_guard() { seed_legacy_orphan_inbox_row(run_id, "Stale receipt", "Do not acknowledge after repair"); let conn = get_connection().expect("open sandbox database"); conn.execute( - "INSERT INTO agent_org_runtime_inbox_materializations ( + "INSERT INTO agent_org_execution_inbox_materializations ( inbox_id, session_id, transcript_message_id, transcript_intent_id, materialized_at ) VALUES (?1, 'old-session', 'message-1', 'intent-1', ?2)", @@ -796,7 +796,7 @@ fn superseded_delivery_requires_an_existing_same_run_replacement() { let source = seed_legacy_orphan_inbox_row(run_id, "Original", "Original work"); let conn = get_connection().expect("open sandbox database"); conn.execute( - "INSERT INTO agent_org_runtime_tasks (id, org_run_id) VALUES ('replacement-task', ?1)", + "INSERT INTO agent_org_execution_tasks (id, org_run_id) VALUES ('replacement-task', ?1)", params![run_id], ) .expect("seed replacement task"); @@ -871,7 +871,7 @@ fn superseded_delivery_can_follow_a_real_replacement_chain_but_not_cycle() { }; let conn = get_connection().expect("open sandbox database"); conn.execute( - "UPDATE agent_org_runtime_runs SET org_snapshot_json=?1 WHERE id=?2", + "UPDATE agent_org_execution_runs SET org_snapshot_json=?1 WHERE id=?2", params![ serde_json::to_string(&crate::definitions::orgs::AgentOrgLaunchSnapshot::from( &org diff --git a/src-tauri/crates/agent-core/src/core/coordination/agent_inbox/schema.rs b/src-tauri/crates/agent-core/src/core/coordination/agent_inbox/schema.rs index 56ddf16c4a..3ddb30a0f3 100644 --- a/src-tauri/crates/agent-core/src/core/coordination/agent_inbox/schema.rs +++ b/src-tauri/crates/agent-core/src/core/coordination/agent_inbox/schema.rs @@ -21,14 +21,14 @@ pub(crate) fn create_schema(conn: &Connection) -> SqliteResult<()> { create_agent_inbox_table(conn)?; super::create_task_message_binding_schema(conn)?; let schema = format!( - "CREATE TABLE IF NOT EXISTS agent_org_runtime_inbox_materializations ( + "CREATE TABLE IF NOT EXISTS agent_org_execution_inbox_materializations ( inbox_id INTEGER PRIMARY KEY, session_id TEXT NOT NULL, transcript_message_id TEXT NOT NULL, transcript_intent_id TEXT NOT NULL, materialized_at TEXT NOT NULL ); - CREATE TABLE IF NOT EXISTS agent_org_runtime_inbox_delivery_resolutions ( + CREATE TABLE IF NOT EXISTS agent_org_execution_inbox_delivery_resolutions ( inbox_id INTEGER PRIMARY KEY, org_run_id TEXT NOT NULL, resolution_kind TEXT NOT NULL @@ -48,25 +48,25 @@ pub(crate) fn create_schema(conn: &Connection) -> SqliteResult<()> { <> (replacement_task_id IS NOT NULL))) ) ); - CREATE INDEX IF NOT EXISTS idx_agent_org_runtime_inbox_delivery_resolutions_run - ON agent_org_runtime_inbox_delivery_resolutions(org_run_id, inbox_id); - CREATE INDEX IF NOT EXISTS idx_agent_org_runtime_inbox_materializations_session - ON agent_org_runtime_inbox_materializations(session_id, inbox_id); - CREATE INDEX IF NOT EXISTS idx_agent_org_runtime_inbox_recipient_member_unread - ON agent_org_runtime_inbox(recipient_member_id, read_at, created_at); - CREATE INDEX IF NOT EXISTS idx_agent_org_runtime_inbox_recipient_unread - ON agent_org_runtime_inbox(recipient_agent_id, read_at, created_at); - CREATE INDEX IF NOT EXISTS idx_agent_org_runtime_inbox_org_run - ON agent_org_runtime_inbox(org_run_id, created_at); - CREATE INDEX IF NOT EXISTS idx_agent_org_runtime_inbox_org_run_id - ON agent_org_runtime_inbox(org_run_id, id); - CREATE INDEX IF NOT EXISTS idx_agent_org_runtime_inbox_run_unread_recipient - ON agent_org_runtime_inbox(org_run_id, recipient_member_id, recipient_agent_id, id) + CREATE INDEX IF NOT EXISTS idx_agent_org_execution_inbox_delivery_resolutions_run + ON agent_org_execution_inbox_delivery_resolutions(org_run_id, inbox_id); + CREATE INDEX IF NOT EXISTS idx_agent_org_execution_inbox_materializations_session + ON agent_org_execution_inbox_materializations(session_id, inbox_id); + CREATE INDEX IF NOT EXISTS idx_agent_org_execution_inbox_recipient_member_unread + ON agent_org_execution_inbox(recipient_member_id, read_at, created_at); + CREATE INDEX IF NOT EXISTS idx_agent_org_execution_inbox_recipient_unread + ON agent_org_execution_inbox(recipient_agent_id, read_at, created_at); + CREATE INDEX IF NOT EXISTS idx_agent_org_execution_inbox_org_run + ON agent_org_execution_inbox(org_run_id, created_at); + CREATE INDEX IF NOT EXISTS idx_agent_org_execution_inbox_org_run_id + ON agent_org_execution_inbox(org_run_id, id); + CREATE INDEX IF NOT EXISTS idx_agent_org_execution_inbox_run_unread_recipient + ON agent_org_execution_inbox(org_run_id, recipient_member_id, recipient_agent_id, id) WHERE read_at IS NULL; - CREATE INDEX IF NOT EXISTS idx_agent_org_runtime_inbox_run_kind_id - ON agent_org_runtime_inbox(org_run_id, payload_kind, id); - CREATE INDEX IF NOT EXISTS idx_agent_org_runtime_inbox_run_task_assignment_v4 - ON agent_org_runtime_inbox( + CREATE INDEX IF NOT EXISTS idx_agent_org_execution_inbox_run_kind_id + ON agent_org_execution_inbox(org_run_id, payload_kind, id); + CREATE INDEX IF NOT EXISTS idx_agent_org_execution_inbox_run_task_assignment_v4 + ON agent_org_execution_inbox( org_run_id, recipient_member_id, json_extract( @@ -85,16 +85,16 @@ pub(crate) fn create_schema(conn: &Connection) -> SqliteResult<()> { THEN payload_json ELSE '{{}}' END, '$.task_id' )='text'; - DROP INDEX IF EXISTS idx_agent_org_runtime_inbox_run_task_assignment_v3; - DROP INDEX IF EXISTS idx_agent_org_runtime_inbox_run_task_assignment_v2; - CREATE INDEX IF NOT EXISTS idx_agent_org_runtime_inbox_request_id - ON agent_org_runtime_inbox(request_id); - CREATE UNIQUE INDEX IF NOT EXISTS idx_agent_org_runtime_inbox_user_message_once - ON agent_org_runtime_inbox(org_run_id, sender_agent_id, client_message_id) + DROP INDEX IF EXISTS idx_agent_org_execution_inbox_run_task_assignment_v3; + DROP INDEX IF EXISTS idx_agent_org_execution_inbox_run_task_assignment_v2; + CREATE INDEX IF NOT EXISTS idx_agent_org_execution_inbox_request_id + ON agent_org_execution_inbox(request_id); + CREATE UNIQUE INDEX IF NOT EXISTS idx_agent_org_execution_inbox_user_message_once + ON agent_org_execution_inbox(org_run_id, sender_agent_id, client_message_id) WHERE client_message_id IS NOT NULL; - DROP INDEX IF EXISTS idx_agent_org_runtime_inbox_causation_once; - CREATE UNIQUE INDEX IF NOT EXISTS idx_agent_org_runtime_inbox_causation_recipient_once - ON agent_org_runtime_inbox( + DROP INDEX IF EXISTS idx_agent_org_execution_inbox_causation_once; + CREATE UNIQUE INDEX IF NOT EXISTS idx_agent_org_execution_inbox_causation_recipient_once + ON agent_org_execution_inbox( causation_inbox_id, payload_kind, recipient_agent_id, @@ -117,13 +117,13 @@ pub(crate) fn repair_dangling_materializations(conn: &Connection) -> SqliteResul )?; if transcript_tables_exist { conn.execute( - "DELETE FROM agent_org_runtime_inbox_materializations AS receipt + "DELETE FROM agent_org_execution_inbox_materializations AS receipt WHERE NOT EXISTS ( - SELECT 1 FROM agent_org_runtime_inbox inbox + SELECT 1 FROM agent_org_execution_inbox inbox WHERE inbox.id=receipt.inbox_id AND inbox.read_at IS NULL AND NOT EXISTS ( - SELECT 1 FROM agent_org_runtime_inbox_delivery_resolutions resolution + SELECT 1 FROM agent_org_execution_inbox_delivery_resolutions resolution WHERE resolution.inbox_id=inbox.id ) ) @@ -144,7 +144,7 @@ pub(crate) fn repair_dangling_materializations(conn: &Connection) -> SqliteResul fn create_agent_inbox_table(conn: &Connection) -> SqliteResult<()> { conn.execute_batch( - "CREATE TABLE IF NOT EXISTS agent_org_runtime_inbox ( + "CREATE TABLE IF NOT EXISTS agent_org_execution_inbox ( id INTEGER PRIMARY KEY AUTOINCREMENT, delivery_class TEXT NOT NULL DEFAULT 'formal_work' CHECK(delivery_class IN ('formal_work','user_directed')), @@ -176,7 +176,7 @@ mod tests { init_schema(&conn).expect("create canonical inbox schema"); let mut stmt = conn - .prepare("PRAGMA table_info(agent_org_runtime_inbox)") + .prepare("PRAGMA table_info(agent_org_execution_inbox)") .expect("inspect inbox schema"); let columns = stmt .query_map([], |row| row.get::<_, String>(1)) @@ -192,7 +192,7 @@ mod tests { "SELECT EXISTS( SELECT 1 FROM sqlite_master WHERE type='table' - AND name='agent_org_runtime_inbox_task_bindings' + AND name='agent_org_execution_inbox_task_bindings' )", [], |row| row.get::<_, bool>(0), @@ -202,10 +202,10 @@ mod tests { .query_row( "SELECT COUNT(*) FROM sqlite_master WHERE type='index' AND name IN ( - 'idx_agent_org_runtime_inbox_run_unread_recipient', - 'idx_agent_org_runtime_inbox_run_task_assignment_v4', - 'idx_agent_org_runtime_inbox_user_message_once', - 'idx_agent_org_runtime_inbox_causation_recipient_once' + 'idx_agent_org_execution_inbox_run_unread_recipient', + 'idx_agent_org_execution_inbox_run_task_assignment_v4', + 'idx_agent_org_execution_inbox_user_message_once', + 'idx_agent_org_execution_inbox_causation_recipient_once' )", [], |row| row.get(0), diff --git a/src-tauri/crates/agent-core/src/core/coordination/agent_inbox/store_drain.rs b/src-tauri/crates/agent-core/src/core/coordination/agent_inbox/store_drain.rs index c72e2ea3c5..567529ca0c 100644 --- a/src-tauri/crates/agent-core/src/core/coordination/agent_inbox/store_drain.rs +++ b/src-tauri/crates/agent-core/src/core/coordination/agent_inbox/store_drain.rs @@ -18,7 +18,7 @@ use super::{AgentInboxStore, MAX_INBOX_DRAIN_PAYLOAD_BYTES, MAX_INBOX_DRAIN_ROWS fn ensure_inbox_claim_allowed(conn: &Connection, org_run_id: &str) -> Result<(), String> { let status: Option = conn .query_row( - "SELECT status FROM agent_org_runtime_runs WHERE id=?1", + "SELECT status FROM agent_org_execution_runs WHERE id=?1", [org_run_id], |row| row.get(0), ) @@ -77,8 +77,8 @@ impl AgentInboxStore { inbox.request_id, inbox.created_at, inbox.read_at - FROM agent_org_runtime_inbox inbox - JOIN agent_org_runtime_tasks task + FROM agent_org_execution_inbox inbox + JOIN agent_org_execution_tasks task ON task.org_run_id=inbox.org_run_id AND task.id=?3 AND task.owner=?1 @@ -87,7 +87,7 @@ impl AgentInboxStore { AND inbox.delivery_class='formal_work' AND inbox.read_at IS NULL AND NOT EXISTS ( - SELECT 1 FROM agent_org_runtime_inbox_delivery_resolutions resolution + SELECT 1 FROM agent_org_execution_inbox_delivery_resolutions resolution WHERE resolution.inbox_id=inbox.id ) AND ( @@ -110,8 +110,8 @@ impl AgentInboxStore { AND json_type(inbox.payload_json,'$.request_id')='text' AND EXISTS ( SELECT 1 - FROM agent_org_runtime_plan_revisions revision - JOIN agent_org_runtime_plan_decisions decision + FROM agent_org_execution_plan_revisions revision + JOIN agent_org_execution_plan_decisions decision ON decision.plan_revision_id=revision.plan_revision_id WHERE revision.org_run_id=?2 AND revision.source_task_id=?3 @@ -157,7 +157,7 @@ impl AgentInboxStore { request_id, created_at, read_at - FROM agent_org_runtime_inbox + FROM agent_org_execution_inbox WHERE id=?1 AND org_run_id=?2 AND delivery_class='formal_work'", params![inbox_id, org_run_id], row_to_record, @@ -196,14 +196,14 @@ impl AgentInboxStore { let conn = get_connection().map_err(|err| err.to_string())?; conn.query_row( "SELECT EXISTS( - SELECT 1 FROM agent_org_runtime_inbox + SELECT 1 FROM agent_org_execution_inbox WHERE recipient_member_id = ?1 AND org_run_id = ?2 AND delivery_class='formal_work' AND read_at IS NULL AND NOT EXISTS ( - SELECT 1 FROM agent_org_runtime_inbox_delivery_resolutions resolution - WHERE resolution.inbox_id=agent_org_runtime_inbox.id + SELECT 1 FROM agent_org_execution_inbox_delivery_resolutions resolution + WHERE resolution.inbox_id=agent_org_execution_inbox.id ) )", params![recipient_member_id, org_run_id], @@ -231,14 +231,14 @@ impl AgentInboxStore { request_id, created_at, read_at - FROM agent_org_runtime_inbox + FROM agent_org_execution_inbox WHERE recipient_member_id = ?1 AND org_run_id = ?2 AND delivery_class='formal_work' AND read_at IS NULL AND NOT EXISTS ( - SELECT 1 FROM agent_org_runtime_inbox_delivery_resolutions resolution - WHERE resolution.inbox_id=agent_org_runtime_inbox.id + SELECT 1 FROM agent_org_execution_inbox_delivery_resolutions resolution + WHERE resolution.inbox_id=agent_org_execution_inbox.id ) ORDER BY id ASC", ) @@ -262,14 +262,14 @@ impl AgentInboxStore { ) -> Result, String> { let conn = get_connection().map_err(|err| err.to_string())?; conn.query_row( - "SELECT MAX(id) FROM agent_org_runtime_inbox + "SELECT MAX(id) FROM agent_org_execution_inbox WHERE recipient_member_id=?1 AND org_run_id=?2 AND delivery_class='formal_work' AND read_at IS NULL AND NOT EXISTS ( - SELECT 1 FROM agent_org_runtime_inbox_delivery_resolutions resolution - WHERE resolution.inbox_id=agent_org_runtime_inbox.id + SELECT 1 FROM agent_org_execution_inbox_delivery_resolutions resolution + WHERE resolution.inbox_id=agent_org_execution_inbox.id )", params![recipient_member_id, org_run_id], |row| row.get(0), @@ -288,15 +288,15 @@ impl AgentInboxStore { let conn = get_connection().map_err(|err| err.to_string())?; let count: i64 = conn .query_row( - "SELECT COUNT(*) FROM agent_org_runtime_inbox + "SELECT COUNT(*) FROM agent_org_execution_inbox WHERE recipient_member_id=?1 AND org_run_id=?2 AND id<=?3 AND delivery_class='formal_work' AND read_at IS NULL AND NOT EXISTS ( - SELECT 1 FROM agent_org_runtime_inbox_delivery_resolutions resolution - WHERE resolution.inbox_id=agent_org_runtime_inbox.id + SELECT 1 FROM agent_org_execution_inbox_delivery_resolutions resolution + WHERE resolution.inbox_id=agent_org_execution_inbox.id )", params![recipient_member_id, org_run_id, boundary_id], |row| row.get(0), @@ -340,14 +340,14 @@ impl AgentInboxStore { request_id, created_at, read_at - FROM agent_org_runtime_inbox + FROM agent_org_execution_inbox WHERE recipient_member_id = ?1 AND org_run_id = ?2 AND delivery_class='formal_work' AND read_at IS NULL AND NOT EXISTS ( - SELECT 1 FROM agent_org_runtime_inbox_delivery_resolutions resolution - WHERE resolution.inbox_id=agent_org_runtime_inbox.id + SELECT 1 FROM agent_org_execution_inbox_delivery_resolutions resolution + WHERE resolution.inbox_id=agent_org_execution_inbox.id ) ORDER BY id ASC LIMIT ?3", @@ -435,12 +435,12 @@ impl AgentInboxStore { ) ) END, request_id,created_at,read_at - FROM agent_org_runtime_inbox + FROM agent_org_execution_inbox WHERE id=?1 AND recipient_member_id='coordinator' AND org_run_id=?3 AND delivery_class='formal_work' AND read_at IS NULL AND NOT EXISTS ( - SELECT 1 FROM agent_org_runtime_inbox_delivery_resolutions resolution - WHERE resolution.inbox_id=agent_org_runtime_inbox.id + SELECT 1 FROM agent_org_execution_inbox_delivery_resolutions resolution + WHERE resolution.inbox_id=agent_org_execution_inbox.id )", ) .map_err(|error| error.to_string())?; @@ -528,8 +528,8 @@ impl AgentInboxStore { let mut status_stmt = tx .prepare( "SELECT inbox.org_run_id,run.status - FROM agent_org_runtime_inbox inbox - LEFT JOIN agent_org_runtime_runs run ON run.id=inbox.org_run_id + FROM agent_org_execution_inbox inbox + LEFT JOIN agent_org_execution_runs run ON run.id=inbox.org_run_id WHERE inbox.id=?1", ) .map_err(|err| err.to_string())?; @@ -568,14 +568,14 @@ impl AgentInboxStore { let unsettled_assignment_status: Option = tx .query_row( "SELECT task.status - FROM agent_org_runtime_inbox inbox - JOIN agent_org_runtime_tasks task + FROM agent_org_execution_inbox inbox + JOIN agent_org_execution_tasks task ON task.org_run_id=inbox.org_run_id AND task.id=json_extract(inbox.payload_json,'$.task_id') WHERE inbox.id=?1 AND inbox.payload_kind='task_assigned' AND NOT EXISTS ( SELECT 1 - FROM agent_org_runtime_inbox_delivery_resolutions resolution + FROM agent_org_execution_inbox_delivery_resolutions resolution WHERE resolution.inbox_id=inbox.id )", [id], @@ -612,16 +612,16 @@ impl AgentInboxStore { "SELECT read_at, EXISTS( SELECT 1 - FROM agent_org_runtime_inbox_materializations receipt - WHERE receipt.inbox_id=agent_org_runtime_inbox.id + FROM agent_org_execution_inbox_materializations receipt + WHERE receipt.inbox_id=agent_org_execution_inbox.id AND receipt.session_id=?2 ), EXISTS( SELECT 1 - FROM agent_org_runtime_inbox_delivery_resolutions resolution - WHERE resolution.inbox_id=agent_org_runtime_inbox.id + FROM agent_org_execution_inbox_delivery_resolutions resolution + WHERE resolution.inbox_id=agent_org_execution_inbox.id ) - FROM agent_org_runtime_inbox WHERE id=?1", + FROM agent_org_execution_inbox WHERE id=?1", ) .map_err(|err| err.to_string())?; for id in ids { @@ -639,16 +639,16 @@ impl AgentInboxStore { } let mut stmt = tx .prepare( - "UPDATE agent_org_runtime_inbox + "UPDATE agent_org_execution_inbox SET read_at=?1 WHERE id=?2 AND read_at IS NULL AND NOT EXISTS ( - SELECT 1 FROM agent_org_runtime_inbox_delivery_resolutions resolution - WHERE resolution.inbox_id=agent_org_runtime_inbox.id + SELECT 1 FROM agent_org_execution_inbox_delivery_resolutions resolution + WHERE resolution.inbox_id=agent_org_execution_inbox.id ) AND EXISTS ( - SELECT 1 FROM agent_org_runtime_inbox_materializations receipt - WHERE receipt.inbox_id=agent_org_runtime_inbox.id + SELECT 1 FROM agent_org_execution_inbox_materializations receipt + WHERE receipt.inbox_id=agent_org_execution_inbox.id AND receipt.session_id=?3 )", ) @@ -656,7 +656,7 @@ impl AgentInboxStore { for id in ids { let org_run_id = tx .query_row( - "SELECT org_run_id FROM agent_org_runtime_inbox WHERE id=?1 AND read_at IS NULL", + "SELECT org_run_id FROM agent_org_execution_inbox WHERE id=?1 AND read_at IS NULL", params![id], |row| row.get::<_, Option>(0), ) @@ -676,19 +676,19 @@ impl AgentInboxStore { } else { let mut stmt = tx .prepare( - "UPDATE agent_org_runtime_inbox + "UPDATE agent_org_execution_inbox SET read_at=?1 WHERE id=?2 AND read_at IS NULL AND NOT EXISTS ( - SELECT 1 FROM agent_org_runtime_inbox_delivery_resolutions resolution - WHERE resolution.inbox_id=agent_org_runtime_inbox.id + SELECT 1 FROM agent_org_execution_inbox_delivery_resolutions resolution + WHERE resolution.inbox_id=agent_org_execution_inbox.id )", ) .map_err(|err| err.to_string())?; for id in ids { let org_run_id = tx .query_row( - "SELECT org_run_id FROM agent_org_runtime_inbox WHERE id=?1 AND read_at IS NULL", + "SELECT org_run_id FROM agent_org_execution_inbox WHERE id=?1 AND read_at IS NULL", params![id], |row| row.get::<_, Option>(0), ) @@ -711,7 +711,7 @@ impl AgentInboxStore { if let Some(session_id) = materialization_session_id { let mut stmt = tx .prepare( - "DELETE FROM agent_org_runtime_inbox_materializations + "DELETE FROM agent_org_execution_inbox_materializations WHERE inbox_id=?1 AND session_id=?2", ) .map_err(|err| err.to_string())?; @@ -721,7 +721,7 @@ impl AgentInboxStore { } } else { let mut stmt = tx - .prepare("DELETE FROM agent_org_runtime_inbox_materializations WHERE inbox_id=?1") + .prepare("DELETE FROM agent_org_execution_inbox_materializations WHERE inbox_id=?1") .map_err(|err| err.to_string())?; for id in ids { stmt.execute(params![id]).map_err(|err| err.to_string())?; @@ -756,7 +756,7 @@ fn task_status_is_pending( task_id: &str, ) -> Result { conn.query_row( - "SELECT status='pending' FROM agent_org_runtime_tasks + "SELECT status='pending' FROM agent_org_execution_tasks WHERE org_run_id=?1 AND id=?2", params![org_run_id, task_id], |row| row.get(0), @@ -778,27 +778,27 @@ fn resume_continuation_owns_assignment( .query_row( "SELECT EXISTS( SELECT 1 - FROM agent_org_runtime_pause_handoffs handoff - JOIN agent_org_runtime_pause_episodes episode + FROM agent_org_execution_pause_handoffs handoff + JOIN agent_org_execution_pause_episodes episode ON episode.episode_id=handoff.episode_id - JOIN agent_org_runtime_runs run ON run.id=handoff.org_run_id - JOIN agent_org_runtime_turn_contexts continuation + JOIN agent_org_execution_runs run ON run.id=handoff.org_run_id + JOIN agent_org_execution_turn_contexts continuation ON continuation.session_id=handoff.session_id AND continuation.turn_intent_id=handoff.continuation_turn_intent_id - JOIN agent_org_runtime_turn_contexts original + JOIN agent_org_execution_turn_contexts original ON original.session_id=handoff.session_id AND original.turn_intent_id=handoff.original_turn_intent_id JOIN session_turn_intents intent ON intent.session_id=handoff.session_id AND intent.turn_intent_id=handoff.continuation_turn_intent_id - JOIN agent_org_runtime_tasks task + JOIN agent_org_execution_tasks task ON task.org_run_id=handoff.org_run_id AND task.id=handoff.task_id - JOIN agent_org_runtime_inbox inbox + JOIN agent_org_execution_inbox inbox ON inbox.id=?3 AND inbox.org_run_id=handoff.org_run_id AND inbox.recipient_member_id=handoff.participant_id - JOIN agent_org_runtime_inbox_materializations materialization + JOIN agent_org_execution_inbox_materializations materialization ON materialization.inbox_id=inbox.id AND materialization.session_id=handoff.session_id WHERE handoff.session_id=?1 @@ -826,7 +826,7 @@ fn resume_continuation_owns_assignment( AND json_extract(inbox.payload_json,'$.task_id')=handoff.task_id AND NOT EXISTS ( SELECT 1 - FROM agent_org_runtime_inbox_delivery_resolutions resolution + FROM agent_org_execution_inbox_delivery_resolutions resolution WHERE resolution.inbox_id=inbox.id ) )", @@ -841,25 +841,25 @@ fn resume_continuation_owns_assignment( conn.query_row( "SELECT EXISTS( SELECT 1 - FROM agent_org_runtime_member_interventions intervention - JOIN agent_org_runtime_runs run ON run.id=intervention.org_run_id - JOIN agent_org_runtime_turn_contexts continuation + FROM agent_org_execution_member_interventions intervention + JOIN agent_org_execution_runs run ON run.id=intervention.org_run_id + JOIN agent_org_execution_turn_contexts continuation ON continuation.session_id=intervention.session_id AND continuation.turn_intent_id=intervention.continuation_turn_intent_id - JOIN agent_org_runtime_turn_contexts original + JOIN agent_org_execution_turn_contexts original ON original.session_id=intervention.session_id AND original.turn_intent_id=intervention.original_turn_intent_id JOIN session_turn_intents intent ON intent.session_id=intervention.session_id AND intent.turn_intent_id=intervention.continuation_turn_intent_id - JOIN agent_org_runtime_tasks task + JOIN agent_org_execution_tasks task ON task.org_run_id=intervention.org_run_id AND task.id=intervention.original_task_id - JOIN agent_org_runtime_inbox inbox + JOIN agent_org_execution_inbox inbox ON inbox.id=?3 AND inbox.org_run_id=intervention.org_run_id AND inbox.recipient_member_id=intervention.member_id - JOIN agent_org_runtime_inbox_materializations materialization + JOIN agent_org_execution_inbox_materializations materialization ON materialization.inbox_id=inbox.id AND materialization.session_id=intervention.session_id WHERE intervention.session_id=?1 @@ -888,7 +888,7 @@ fn resume_continuation_owns_assignment( AND json_extract(inbox.payload_json,'$.task_id')=intervention.original_task_id AND NOT EXISTS ( SELECT 1 - FROM agent_org_runtime_inbox_delivery_resolutions resolution + FROM agent_org_execution_inbox_delivery_resolutions resolution WHERE resolution.inbox_id=inbox.id ) )", @@ -905,12 +905,12 @@ fn turn_is_resume_continuation( ) -> Result { conn.query_row( "SELECT EXISTS( - SELECT 1 FROM agent_org_runtime_pause_handoffs + SELECT 1 FROM agent_org_execution_pause_handoffs WHERE session_id=?1 AND continuation_turn_intent_id=?2 AND continuation_status='dispatched' UNION ALL - SELECT 1 FROM agent_org_runtime_member_interventions + SELECT 1 FROM agent_org_execution_member_interventions WHERE session_id=?1 AND continuation_turn_intent_id=?2 AND status='cleared' diff --git a/src-tauri/crates/agent-core/src/core/coordination/agent_inbox/store_read.rs b/src-tauri/crates/agent-core/src/core/coordination/agent_inbox/store_read.rs index 230401bfae..5f1f4fef8b 100644 --- a/src-tauri/crates/agent-core/src/core/coordination/agent_inbox/store_read.rs +++ b/src-tauri/crates/agent-core/src/core/coordination/agent_inbox/store_read.rs @@ -33,13 +33,13 @@ pub(super) const UNREAD_COUNTS_BY_RECIPIENT_SQL: &str = "SELECT recipient_agent_ recipient_member_id, COUNT(*) AS unread_count, MAX(id) AS max_unread_id - FROM agent_org_runtime_inbox INDEXED BY idx_agent_org_runtime_inbox_run_unread_recipient + FROM agent_org_execution_inbox INDEXED BY idx_agent_org_execution_inbox_run_unread_recipient WHERE org_run_id = ?1 AND delivery_class='formal_work' AND read_at IS NULL AND NOT EXISTS ( - SELECT 1 FROM agent_org_runtime_inbox_delivery_resolutions resolution - WHERE resolution.inbox_id=agent_org_runtime_inbox.id + SELECT 1 FROM agent_org_execution_inbox_delivery_resolutions resolution + WHERE resolution.inbox_id=agent_org_execution_inbox.id ) GROUP BY recipient_member_id, recipient_agent_id ORDER BY recipient_member_id ASC, recipient_agent_id ASC"; @@ -102,14 +102,14 @@ fn repair_eligibility_with_connection( "SELECT inbox.recipient_member_id,inbox.sender_member_id, inbox.delivery_class,inbox.payload_kind,inbox.read_at, EXISTS( - SELECT 1 FROM agent_org_runtime_inbox_delivery_resolutions resolution + SELECT 1 FROM agent_org_execution_inbox_delivery_resolutions resolution WHERE resolution.inbox_id=inbox.id ), EXISTS( - SELECT 1 FROM agent_org_runtime_inbox_task_bindings binding + SELECT 1 FROM agent_org_execution_inbox_task_bindings binding WHERE binding.inbox_id=inbox.id ) - FROM agent_org_runtime_inbox inbox + FROM agent_org_execution_inbox inbox WHERE inbox.org_run_id=?1 AND inbox.id=?2 LIMIT 1", params![org_run_id, inbox_id], @@ -204,7 +204,7 @@ fn load_delivery_resolution( "SELECT inbox_id, org_run_id, resolution_kind, resolved_by_member_id, reason, replacement_inbox_id, replacement_task_id, created_at - FROM agent_org_runtime_inbox_delivery_resolutions + FROM agent_org_execution_inbox_delivery_resolutions WHERE inbox_id=?1 AND org_run_id=?2 LIMIT 1", params![inbox_id, org_run_id], @@ -268,7 +268,7 @@ impl AgentInboxStore { request_id, created_at, read_at - FROM agent_org_runtime_inbox + FROM agent_org_execution_inbox WHERE org_run_id = ?1 ORDER BY id ASC", ) @@ -328,7 +328,7 @@ impl AgentInboxStore { CASE WHEN request_id IS NULL THEN NULL ELSE substr(request_id,1,1000) END, substr(created_at,1,64), CASE WHEN read_at IS NULL THEN NULL ELSE substr(read_at,1,64) END - FROM agent_org_runtime_inbox + FROM agent_org_execution_inbox WHERE org_run_id=?1 AND id>?2 ORDER BY id ASC LIMIT ?3", @@ -386,7 +386,7 @@ impl AgentInboxStore { let conn = get_connection().map_err(|err| err.to_string())?; let count: i64 = conn .query_row( - "SELECT COUNT(*) FROM agent_org_runtime_inbox WHERE org_run_id=?1", + "SELECT COUNT(*) FROM agent_org_execution_inbox WHERE org_run_id=?1", params![org_run_id], |row| row.get(0), ) @@ -440,7 +440,7 @@ impl AgentInboxStore { CASE WHEN request_id IS NULL THEN NULL ELSE substr(request_id,1,1000) END, substr(created_at,1,64), CASE WHEN read_at IS NULL THEN NULL ELSE substr(read_at,1,64) END - FROM agent_org_runtime_inbox + FROM agent_org_execution_inbox WHERE org_run_id=?1 AND id=?2 LIMIT 1", params![ @@ -589,7 +589,7 @@ impl AgentInboxStore { let source: Option<(Option, Option)> = conn .query_row( "SELECT recipient_member_id, read_at - FROM agent_org_runtime_inbox + FROM agent_org_execution_inbox WHERE id=?1 AND org_run_id=?2 AND delivery_class='formal_work' LIMIT 1", params![params.inbox_id, ¶ms.org_run_id], @@ -654,13 +654,13 @@ impl AgentInboxStore { inbox.read_at, EXISTS( SELECT 1 - FROM agent_org_runtime_inbox_delivery_resolutions resolution + FROM agent_org_execution_inbox_delivery_resolutions resolution WHERE resolution.inbox_id=inbox.id ), inbox.delivery_class, inbox.payload_kind, inbox.sender_member_id - FROM agent_org_runtime_inbox inbox + FROM agent_org_execution_inbox inbox WHERE inbox.id=?1 AND inbox.org_run_id=?2 AND inbox.delivery_class='formal_work' LIMIT 1", @@ -715,7 +715,7 @@ impl AgentInboxStore { let has_binding: bool = conn .query_row( "SELECT EXISTS( - SELECT 1 FROM agent_org_runtime_inbox_task_bindings + SELECT 1 FROM agent_org_execution_inbox_task_bindings WHERE inbox_id=?1 AND org_run_id=?2 )", params![replacement_inbox_id, ¶ms.org_run_id], @@ -733,7 +733,7 @@ impl AgentInboxStore { let replacement_exists: bool = conn .query_row( "SELECT EXISTS( - SELECT 1 FROM agent_org_runtime_tasks + SELECT 1 FROM agent_org_execution_tasks WHERE id=?1 AND org_run_id=?2 )", params![replacement_task_id, ¶ms.org_run_id], @@ -750,7 +750,7 @@ impl AgentInboxStore { let created_at = chrono::Utc::now().to_rfc3339(); conn.execute( - "INSERT INTO agent_org_runtime_inbox_delivery_resolutions ( + "INSERT INTO agent_org_execution_inbox_delivery_resolutions ( inbox_id, org_run_id, resolution_kind, resolved_by_member_id, reason, replacement_inbox_id, replacement_task_id, created_at @@ -771,7 +771,7 @@ impl AgentInboxStore { // not later acknowledge it as delivered. The guarded mark-read // path also rechecks the resolution table. conn.execute( - "DELETE FROM agent_org_runtime_inbox_materializations WHERE inbox_id=?1", + "DELETE FROM agent_org_execution_inbox_materializations WHERE inbox_id=?1", params![params.inbox_id], ) .map_err(|err| storage(err.to_string()))?; @@ -837,7 +837,7 @@ impl AgentInboxStore { request_id, created_at, read_at - FROM agent_org_runtime_inbox + FROM agent_org_execution_inbox WHERE org_run_id = ?1 ORDER BY id DESC LIMIT ?2 @@ -948,11 +948,11 @@ impl AgentInboxStore { ELSE NULL END AS display_preview, ( SELECT resolution.resolution_kind - FROM agent_org_runtime_inbox_delivery_resolutions resolution - WHERE resolution.inbox_id=agent_org_runtime_inbox.id + FROM agent_org_execution_inbox_delivery_resolutions resolution + WHERE resolution.inbox_id=agent_org_execution_inbox.id LIMIT 1 ) AS delivery_resolution - FROM agent_org_runtime_inbox + FROM agent_org_execution_inbox WHERE org_run_id = ?1 ORDER BY id DESC LIMIT ?2 @@ -1001,11 +1001,11 @@ impl AgentInboxStore { SUM(CASE WHEN delivery_class='formal_work' AND read_at IS NULL AND NOT EXISTS ( SELECT 1 - FROM agent_org_runtime_inbox_delivery_resolutions resolution - WHERE resolution.inbox_id=agent_org_runtime_inbox.id + FROM agent_org_execution_inbox_delivery_resolutions resolution + WHERE resolution.inbox_id=agent_org_execution_inbox.id ) THEN 1 ELSE 0 END) AS unread_count - FROM agent_org_runtime_inbox + FROM agent_org_execution_inbox WHERE org_run_id = ?1 GROUP BY recipient_member_id, recipient_agent_id ORDER BY recipient_member_id ASC, recipient_agent_id ASC", @@ -1078,14 +1078,14 @@ impl AgentInboxStore { let (max_id, count): (Option, i64) = conn .query_row( "SELECT MAX(id), COUNT(*) - FROM agent_org_runtime_inbox + FROM agent_org_execution_inbox WHERE recipient_member_id=?1 AND org_run_id=?2 AND delivery_class='formal_work' AND read_at IS NULL AND NOT EXISTS ( - SELECT 1 FROM agent_org_runtime_inbox_delivery_resolutions resolution - WHERE resolution.inbox_id=agent_org_runtime_inbox.id + SELECT 1 FROM agent_org_execution_inbox_delivery_resolutions resolution + WHERE resolution.inbox_id=agent_org_execution_inbox.id )", params![recipient_member_id, org_run_id], |row| Ok((row.get(0)?, row.get(1)?)), diff --git a/src-tauri/crates/agent-core/src/core/coordination/agent_inbox/store_write.rs b/src-tauri/crates/agent-core/src/core/coordination/agent_inbox/store_write.rs index a3f1a236ac..6ca2f91b8b 100644 --- a/src-tauri/crates/agent-core/src/core/coordination/agent_inbox/store_write.rs +++ b/src-tauri/crates/agent-core/src/core/coordination/agent_inbox/store_write.rs @@ -17,11 +17,11 @@ pub(super) fn active_episode_task_counts( "SELECT COUNT(*), COALESCE(SUM(CASE WHEN task.status IN ('pending','in_progress') THEN 1 ELSE 0 END),0) - FROM agent_org_runtime_tasks task - JOIN agent_org_runtime_work_episode_tasks episode_task + FROM agent_org_execution_tasks task + JOIN agent_org_execution_work_episode_tasks episode_task ON episode_task.org_run_id=task.org_run_id AND episode_task.task_id=task.id - JOIN agent_org_runtime_work_episodes episode + JOIN agent_org_execution_work_episodes episode ON episode.id=episode_task.work_episode_id AND episode.org_run_id=episode_task.org_run_id WHERE task.org_run_id=?1 AND episode.status='active'", @@ -38,7 +38,7 @@ pub(super) fn exact_member_turn_task_id( source_turn_intent_id: &str, ) -> Result, String> { conn.query_row( - "SELECT task_id FROM agent_org_runtime_turn_contexts + "SELECT task_id FROM agent_org_execution_turn_contexts WHERE org_run_id=?1 AND participant_id=?2 AND turn_kind='task_execution' AND turn_intent_id=?3", params![run_id, member_id, source_turn_intent_id], @@ -109,7 +109,7 @@ impl AgentInboxStore { .map_err(|err| err.to_string())?; let run_running: bool = tx .query_row( - "SELECT EXISTS(SELECT 1 FROM agent_org_runtime_runs + "SELECT EXISTS(SELECT 1 FROM agent_org_execution_runs WHERE id=?1 AND status='running')", params![&run_id], |row| row.get(0), @@ -127,7 +127,7 @@ impl AgentInboxStore { // Metadata only: retain the exact caller's execution, never infer // the source from whichever Turn happens to be running now. tx.execute( - "UPDATE agent_org_runtime_inbox SET source_turn_intent_id=?2 WHERE id=?1", + "UPDATE agent_org_execution_inbox SET source_turn_intent_id=?2 WHERE id=?1", params![record.id, source_turn_intent_id], ) .map_err(|e| e.to_string())?; @@ -277,7 +277,7 @@ impl AgentInboxStore { if let Some(org_run_id) = params.org_run_id.as_deref() { let status: Option = conn .query_row( - "SELECT status FROM agent_org_runtime_runs WHERE id=?1", + "SELECT status FROM agent_org_execution_runs WHERE id=?1", [org_run_id], |row| row.get(0), ) @@ -305,7 +305,7 @@ impl AgentInboxStore { let now = chrono::Utc::now().to_rfc3339(); let insert_sql = if causation_inbox_id.is_some() { - "INSERT OR IGNORE INTO agent_org_runtime_inbox ( + "INSERT OR IGNORE INTO agent_org_execution_inbox ( recipient_agent_id, recipient_member_id, sender_agent_id, @@ -319,7 +319,7 @@ impl AgentInboxStore { causation_inbox_id ) VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9, NULL, ?10)" } else { - "INSERT INTO agent_org_runtime_inbox ( + "INSERT INTO agent_org_execution_inbox ( recipient_agent_id, recipient_member_id, sender_agent_id, @@ -368,7 +368,7 @@ impl AgentInboxStore { request_id, created_at, read_at - FROM agent_org_runtime_inbox + FROM agent_org_execution_inbox WHERE causation_inbox_id = ?1 AND payload_kind = ?2 AND recipient_agent_id = ?3 @@ -409,7 +409,7 @@ impl AgentInboxStore { } = ¶ms.message { let raw: Option = conn.query_row( - "SELECT output_json FROM agent_org_runtime_tasks WHERE org_run_id=?1 AND id=?2", + "SELECT output_json FROM agent_org_execution_tasks WHERE org_run_id=?1 AND id=?2", params![org_run_id, task_id], |row| row.get(0)) .optional().map_err(|e| e.to_string())?.flatten(); raw.map(|raw| serde_json::from_str::(&raw) @@ -433,7 +433,7 @@ impl AgentInboxStore { )?; if suppress_self_wake { conn.execute( - "UPDATE agent_org_runtime_inbox + "UPDATE agent_org_execution_inbox SET read_at=?2 WHERE id=?1 AND read_at IS NULL", rusqlite::params![id, chrono::Utc::now().to_rfc3339()], ) diff --git a/src-tauri/crates/agent-core/src/core/coordination/agent_inbox/store_write_tests.rs b/src-tauri/crates/agent-core/src/core/coordination/agent_inbox/store_write_tests.rs index 86908ad570..1c9b30e0b8 100644 --- a/src-tauri/crates/agent-core/src/core/coordination/agent_inbox/store_write_tests.rs +++ b/src-tauri/crates/agent-core/src/core/coordination/agent_inbox/store_write_tests.rs @@ -6,23 +6,23 @@ use super::store_write::{active_episode_task_counts, exact_member_turn_task_id}; fn final_member_exit_counts_the_active_episode_across_resume_generations() { let conn = Connection::open_in_memory().expect("in-memory database"); conn.execute_batch( - "CREATE TABLE agent_org_runtime_tasks( + "CREATE TABLE agent_org_execution_tasks( id TEXT NOT NULL,org_run_id TEXT NOT NULL,activation_generation INTEGER NOT NULL, status TEXT NOT NULL,PRIMARY KEY(org_run_id,id) ); - CREATE TABLE agent_org_runtime_work_episodes( + CREATE TABLE agent_org_execution_work_episodes( id TEXT PRIMARY KEY,org_run_id TEXT NOT NULL,status TEXT NOT NULL ); - CREATE TABLE agent_org_runtime_work_episode_tasks( + CREATE TABLE agent_org_execution_work_episode_tasks( org_run_id TEXT NOT NULL,work_episode_id TEXT NOT NULL,task_id TEXT NOT NULL ); - INSERT INTO agent_org_runtime_work_episodes VALUES + INSERT INTO agent_org_execution_work_episodes VALUES ('episode-active','run','active'),('episode-old','run','certified'); - INSERT INTO agent_org_runtime_tasks VALUES + INSERT INTO agent_org_execution_tasks VALUES ('task-one','run',2,'completed'), ('task-two','run',2,'completed'), ('task-old','run',1,'pending'); - INSERT INTO agent_org_runtime_work_episode_tasks VALUES + INSERT INTO agent_org_execution_work_episode_tasks VALUES ('run','episode-active','task-one'), ('run','episode-active','task-two'), ('run','episode-old','task-old');", @@ -40,12 +40,12 @@ fn final_member_exit_counts_the_active_episode_across_resume_generations() { fn member_idle_keeps_the_exact_producing_turn_instead_of_guessing_latest() { let conn = Connection::open_in_memory().expect("in-memory database"); conn.execute_batch( - "CREATE TABLE agent_org_runtime_turn_contexts( + "CREATE TABLE agent_org_execution_turn_contexts( context_id INTEGER PRIMARY KEY AUTOINCREMENT, org_run_id TEXT NOT NULL,participant_id TEXT NOT NULL, turn_kind TEXT NOT NULL,turn_intent_id TEXT NOT NULL,task_id TEXT ); - INSERT INTO agent_org_runtime_turn_contexts + INSERT INTO agent_org_execution_turn_contexts (org_run_id,participant_id,turn_kind,turn_intent_id,task_id) VALUES ('run','member','task_execution','turn-before-pause','task-one'), ('run','member','task_execution','turn-after-resume','task-two');", diff --git a/src-tauri/crates/agent-core/src/core/coordination/agent_inbox/task_bindings.rs b/src-tauri/crates/agent-core/src/core/coordination/agent_inbox/task_bindings.rs index da0f2de56a..d1330b6cbb 100644 --- a/src-tauri/crates/agent-core/src/core/coordination/agent_inbox/task_bindings.rs +++ b/src-tauri/crates/agent-core/src/core/coordination/agent_inbox/task_bindings.rs @@ -52,12 +52,12 @@ pub(crate) fn preflight_coordinator_task_message_in_tx( .query_row( "SELECT EXISTS( SELECT 1 - FROM agent_org_runtime_tasks task - JOIN agent_org_runtime_runs run + FROM agent_org_execution_tasks task + JOIN agent_org_execution_runs run ON run.id=task.org_run_id AND run.status='running' AND run.activation_generation=task.activation_generation - JOIN agent_org_runtime_turn_contexts source_context + JOIN agent_org_execution_turn_contexts source_context ON source_context.org_run_id=task.org_run_id AND source_context.turn_intent_id=?4 AND source_context.participant_id='coordinator' @@ -74,7 +74,7 @@ pub(crate) fn preflight_coordinator_task_message_in_tx( CASE WHEN json_valid(task.blocked_by_json) THEN task.blocked_by_json ELSE '[]' END ) edge - LEFT JOIN agent_org_runtime_tasks dependency + LEFT JOIN agent_org_execution_tasks dependency ON dependency.org_run_id=task.org_run_id AND dependency.id=CAST(edge.value AS TEXT) WHERE edge.type<>'text' @@ -107,7 +107,7 @@ pub(crate) fn preflight_coordinator_task_message_in_tx( pub(crate) fn create_task_message_binding_schema(conn: &Connection) -> rusqlite::Result<()> { conn.execute_batch( - "CREATE TABLE IF NOT EXISTS agent_org_runtime_inbox_task_bindings ( + "CREATE TABLE IF NOT EXISTS agent_org_execution_inbox_task_bindings ( inbox_id INTEGER PRIMARY KEY, org_run_id TEXT NOT NULL, task_id TEXT NOT NULL, @@ -116,12 +116,12 @@ pub(crate) fn create_task_message_binding_schema(conn: &Connection) -> rusqlite: source_turn_intent_id TEXT NOT NULL, created_at TEXT NOT NULL, FOREIGN KEY(inbox_id) - REFERENCES agent_org_runtime_inbox(id) ON DELETE CASCADE, + REFERENCES agent_org_execution_inbox(id) ON DELETE CASCADE, FOREIGN KEY(org_run_id,task_id) - REFERENCES agent_org_runtime_tasks(org_run_id,id) ON DELETE CASCADE + REFERENCES agent_org_execution_tasks(org_run_id,id) ON DELETE CASCADE ); - CREATE INDEX IF NOT EXISTS idx_agent_org_runtime_inbox_task_bindings_wake - ON agent_org_runtime_inbox_task_bindings( + CREATE INDEX IF NOT EXISTS idx_agent_org_execution_inbox_task_bindings_wake + ON agent_org_execution_inbox_task_bindings( org_run_id,recipient_member_id,task_id,inbox_id );", ) @@ -143,23 +143,23 @@ impl AgentInboxStore { let now = chrono::Utc::now().to_rfc3339(); let inserted = conn .execute( - "INSERT INTO agent_org_runtime_inbox_task_bindings ( + "INSERT INTO agent_org_execution_inbox_task_bindings ( inbox_id,org_run_id,task_id,recipient_member_id,binding_kind, source_turn_intent_id,created_at ) SELECT inbox.id,inbox.org_run_id,task.id,inbox.recipient_member_id, ?7,source_context.turn_intent_id,?6 - FROM agent_org_runtime_inbox inbox - JOIN agent_org_runtime_tasks task + FROM agent_org_execution_inbox inbox + JOIN agent_org_execution_tasks task ON task.org_run_id=inbox.org_run_id AND task.id=?3 AND task.owner=?4 AND task.status IN ('pending','in_progress') - JOIN agent_org_runtime_runs run + JOIN agent_org_execution_runs run ON run.id=task.org_run_id AND run.status='running' AND run.activation_generation=task.activation_generation - JOIN agent_org_runtime_turn_contexts source_context + JOIN agent_org_execution_turn_contexts source_context ON source_context.org_run_id=inbox.org_run_id AND source_context.turn_intent_id=?5 AND source_context.participant_id='coordinator' @@ -204,18 +204,18 @@ pub(crate) fn oldest_unread_task_message_binding_with_connection( ) -> Result, String> { conn.query_row( "SELECT inbox.id,binding.task_id - FROM agent_org_runtime_inbox_task_bindings binding - JOIN agent_org_runtime_inbox inbox ON inbox.id=binding.inbox_id - JOIN agent_org_runtime_tasks task + FROM agent_org_execution_inbox_task_bindings binding + JOIN agent_org_execution_inbox inbox ON inbox.id=binding.inbox_id + JOIN agent_org_execution_tasks task ON task.org_run_id=binding.org_run_id AND task.id=binding.task_id AND task.owner=binding.recipient_member_id AND task.status='in_progress' - JOIN agent_org_runtime_runs run + JOIN agent_org_execution_runs run ON run.id=task.org_run_id AND run.status='running' AND run.activation_generation=task.activation_generation - JOIN agent_org_runtime_turn_contexts source_context + JOIN agent_org_execution_turn_contexts source_context ON source_context.org_run_id=binding.org_run_id AND source_context.turn_intent_id=binding.source_turn_intent_id AND source_context.participant_id='coordinator' @@ -233,17 +233,17 @@ pub(crate) fn oldest_unread_task_message_binding_with_connection( AND inbox.payload_kind='plain' AND inbox.read_at IS NULL AND NOT EXISTS ( - SELECT 1 FROM agent_org_task_execution_leases lease + SELECT 1 FROM agent_org_execution_task_execution_leases lease JOIN session_turn_intents intent USING(session_id,turn_intent_id) WHERE lease.continuation_receipt_id='inbox:' || inbox.id AND intent.status NOT IN ('queued','running','optimistic') ) AND NOT EXISTS ( - SELECT 1 FROM agent_org_runtime_inbox_delivery_resolutions resolution + SELECT 1 FROM agent_org_execution_inbox_delivery_resolutions resolution WHERE resolution.inbox_id=inbox.id ) AND EXISTS ( - SELECT 1 FROM agent_org_runtime_turn_contexts task_context + SELECT 1 FROM agent_org_execution_turn_contexts task_context WHERE task_context.org_run_id=task.org_run_id AND task_context.participant_id=task.owner AND task_context.turn_kind='task_execution' @@ -269,8 +269,8 @@ mod tests { let conn = Connection::open_in_memory().expect("open SQLite"); conn.execute_batch( "PRAGMA foreign_keys=ON; - CREATE TABLE agent_org_runtime_inbox(id INTEGER PRIMARY KEY); - CREATE TABLE agent_org_runtime_tasks( + CREATE TABLE agent_org_execution_inbox(id INTEGER PRIMARY KEY); + CREATE TABLE agent_org_execution_tasks( org_run_id TEXT NOT NULL,id TEXT NOT NULL, PRIMARY KEY(org_run_id,id) );", diff --git a/src-tauri/crates/agent-core/src/core/coordination/agent_inbox/tests.rs b/src-tauri/crates/agent-core/src/core/coordination/agent_inbox/tests.rs index 366c1d8af9..934263b5bb 100644 --- a/src-tauri/crates/agent-core/src/core/coordination/agent_inbox/tests.rs +++ b/src-tauri/crates/agent-core/src/core/coordination/agent_inbox/tests.rs @@ -25,7 +25,7 @@ fn task_assignment_ids_by_run(org_run_id: &str) -> Result, Strin let mut stmt = conn .prepare( "SELECT DISTINCT json_extract(payload_json, '$.task_id') - FROM agent_org_runtime_inbox + FROM agent_org_execution_inbox WHERE org_run_id=?1 AND payload_kind='task_assigned' AND json_valid(payload_json) @@ -113,7 +113,7 @@ fn inbox_history_pages_are_cursor_bounded_without_gaps() { let now = chrono::Utc::now().to_rfc3339(); for _ in 0..205 { tx.execute( - "INSERT INTO agent_org_runtime_inbox ( + "INSERT INTO agent_org_execution_inbox ( recipient_agent_id, recipient_member_id, sender_agent_id, sender_member_id, org_run_id, payload_kind, payload_json, request_id, created_at, read_at, causation_inbox_id @@ -174,7 +174,7 @@ fn recent_run_snapshot_is_bounded_and_counts_do_not_load_payloads() { // write boundary no longer permits creating new ones. let conn = get_connection().expect("open inbox database for legacy fixture"); conn.execute( - "INSERT INTO agent_org_runtime_inbox ( + "INSERT INTO agent_org_execution_inbox ( recipient_agent_id, recipient_member_id, sender_agent_id, sender_member_id, org_run_id, payload_kind, payload_json, request_id, created_at, read_at, causation_inbox_id @@ -246,7 +246,7 @@ fn recent_run_snapshot_is_bounded_and_counts_do_not_load_payloads() { assert!( details .iter() - .any(|detail| detail.contains("idx_agent_org_runtime_inbox_run_unread_recipient")), + .any(|detail| detail.contains("idx_agent_org_execution_inbox_run_unread_recipient")), "watchdog/run-view unread aggregation must stay on the partial unread index: {details:?}" ); assert!( @@ -296,7 +296,7 @@ fn run_preview_omits_large_plan_payload() { database::db::get_connection() .expect("sandbox DB") .execute( - "INSERT INTO agent_org_runtime_runs ( + "INSERT INTO agent_org_execution_runs ( id,org_id,coordinator_agent_id,root_session_id,entry_mode,status, activation_generation,has_initial_work,created_at,updated_at ) VALUES (?1,'org-preview','coordinator-agent','root-preview', @@ -391,7 +391,7 @@ fn preview_and_assignment_scan_tolerate_corrupt_historical_payloads() { ("task_assigned", "also-not-json"), ] { conn.execute( - "INSERT INTO agent_org_runtime_inbox ( + "INSERT INTO agent_org_execution_inbox ( recipient_agent_id, recipient_member_id, sender_agent_id, org_run_id, payload_kind, payload_json, created_at ) VALUES ('worker', 'member-worker', 'sender', ?1, ?2, ?3, ?4)", @@ -399,7 +399,7 @@ fn preview_and_assignment_scan_tolerate_corrupt_historical_payloads() { ) .expect("seed corrupt historical inbox row"); } - conn.execute_batch("DROP INDEX idx_agent_org_runtime_inbox_run_task_assignment_v4") + conn.execute_batch("DROP INDEX idx_agent_org_execution_inbox_run_task_assignment_v4") .expect("drop assignment index to simulate upgrade"); init_schema(&conn).expect("schema upgrade tolerates corrupt historical payloads"); AgentInboxStore::insert(InsertInboxParams { @@ -445,7 +445,7 @@ fn task_execution_drain_claims_exactly_one_bound_assignment() { let now = chrono::Utc::now().to_rfc3339(); for task_id in ["task-one", "task-two"] { conn.execute( - "INSERT INTO agent_org_runtime_tasks + "INSERT INTO agent_org_execution_tasks (id, org_run_id, activation_generation, subject, description, status, owner, execution_mode, blocked_by_json, created_by_participant_id, source_turn_intent_id, created_at, updated_at) @@ -537,7 +537,7 @@ fn task_execution_drain_materializes_exact_bound_coordinator_reply() { let run_id = format!("run-reply-{}", uuid::Uuid::new_v4()); let now = chrono::Utc::now().to_rfc3339(); conn.execute( - "INSERT INTO agent_org_runtime_runs ( + "INSERT INTO agent_org_execution_runs ( id,org_id,coordinator_agent_id,root_session_id,entry_mode,status, activation_generation,created_at,updated_at ) VALUES (?1,'org-reply','coordinator-agent','root-session', @@ -546,7 +546,7 @@ fn task_execution_drain_materializes_exact_bound_coordinator_reply() { ) .expect("running Team"); conn.execute( - "INSERT INTO agent_org_runtime_tasks ( + "INSERT INTO agent_org_execution_tasks ( id,org_run_id,activation_generation,subject,owner,status,execution_mode, created_by_participant_id,source_turn_intent_id,created_at,updated_at ) VALUES ('task-reply',?1,1,'Reply task','member-worker','in_progress', @@ -564,7 +564,7 @@ fn task_execution_drain_materializes_exact_bound_coordinator_reply() { ) .expect("source Turns"); conn.execute( - "INSERT INTO agent_org_runtime_turn_contexts ( + "INSERT INTO agent_org_execution_turn_contexts ( session_id,turn_intent_id,org_run_id,participant_id,turn_kind, task_id,owner_member_id,dispatch_member_id,member_dispatch_sequence, source_kind,source_id,activation_generation,created_at @@ -888,7 +888,7 @@ fn stale_session_cannot_ack_another_sessions_materialization() { .expect("insert inbox row"); let conn = get_connection().expect("db"); conn.execute( - "INSERT INTO agent_org_runtime_inbox_materializations + "INSERT INTO agent_org_execution_inbox_materializations (inbox_id, session_id, transcript_message_id, transcript_intent_id, materialized_at) VALUES (?1, 'new-session', 'message', 'intent', ?2)", params![row.id, chrono::Utc::now().to_rfc3339()], diff --git a/src-tauri/crates/agent-core/src/core/coordination/agent_member_interventions.rs b/src-tauri/crates/agent-core/src/core/coordination/agent_member_interventions.rs index 9eb90880c7..de82b95184 100644 --- a/src-tauri/crates/agent-core/src/core/coordination/agent_member_interventions.rs +++ b/src-tauri/crates/agent-core/src/core/coordination/agent_member_interventions.rs @@ -257,7 +257,7 @@ impl AgentMemberInterventionStore { .query_row( "SELECT intervention_receipt_id,member_dispatch_sequence, dispatch_content,display_content,status - FROM agent_org_runtime_member_intervention_turns + FROM agent_org_execution_member_intervention_turns WHERE session_id=?1 AND turn_intent_id=?2", params![¶ms.session_id, ¶ms.turn_intent_id], |row| { @@ -277,7 +277,7 @@ impl AgentMemberInterventionStore { let queued_count: i64 = tx .query_row( "SELECT COUNT(*) - FROM agent_org_runtime_turn_contexts context + FROM agent_org_execution_turn_contexts context JOIN session_turn_intents intent ON intent.session_id=context.session_id AND intent.turn_intent_id=context.turn_intent_id @@ -372,7 +372,7 @@ impl AgentMemberInterventionStore { .query_row( &format!( "SELECT intervention_receipt_id - FROM agent_org_runtime_member_interventions + FROM agent_org_execution_member_interventions WHERE org_run_id=?1 AND member_id=?2 AND status IN ({ACTIVE_STATUSES_SQL})" ), @@ -390,7 +390,7 @@ impl AgentMemberInterventionStore { let agent_id: String = tx .query_row( "SELECT agent_id - FROM agent_org_runtime_member_materializations + FROM agent_org_execution_member_materializations WHERE org_run_id=?1 AND member_id=?2 AND session_id=?3 AND status='succeeded' ORDER BY generation DESC LIMIT 1", @@ -409,7 +409,7 @@ impl AgentMemberInterventionStore { .map(|value| (Some(value.0), Some(value.1), Some(value.2))) .unwrap_or((None, None, None)); tx.execute( - "INSERT INTO agent_org_runtime_member_interventions ( + "INSERT INTO agent_org_execution_member_interventions ( intervention_receipt_id,org_run_id,member_id,agent_id,session_id, status,source_event_id,original_task_id,original_turn_intent_id, original_member_dispatch_sequence,entered_at,last_user_activity_at, @@ -438,14 +438,14 @@ impl AgentMemberInterventionStore { let chain_position: i64 = tx .query_row( "SELECT COALESCE(MAX(chain_position),0)+1 - FROM agent_org_runtime_member_intervention_turns + FROM agent_org_execution_member_intervention_turns WHERE intervention_receipt_id=?1", [&receipt_id], |row| row.get(0), ) .map_err(|error| error.to_string())?; tx.execute( - "INSERT INTO agent_org_runtime_member_intervention_turns ( + "INSERT INTO agent_org_execution_member_intervention_turns ( intervention_receipt_id,session_id,turn_intent_id,source_event_id, dispatch_content,display_content,member_dispatch_sequence, chain_position,status,enqueued_at @@ -464,7 +464,7 @@ impl AgentMemberInterventionStore { ) .map_err(|error| error.to_string())?; tx.execute( - "UPDATE agent_org_runtime_member_interventions + "UPDATE agent_org_execution_member_interventions SET last_user_activity_at=?2,updated_at=?2 WHERE intervention_receipt_id=?1", params![&receipt_id, &now], @@ -500,7 +500,7 @@ impl AgentMemberInterventionStore { let conn = get_connection().map_err(|error| error.to_string())?; let now = chrono::Utc::now().to_rfc3339(); conn.execute( - "UPDATE agent_org_runtime_member_interventions + "UPDATE agent_org_execution_member_interventions SET runtime_lease_id=?3,dialog_turn_generation=?4, yield_requested_at=COALESCE(yield_requested_at,?5),updated_at=?5 WHERE intervention_receipt_id=?1 @@ -529,7 +529,7 @@ impl AgentMemberInterventionStore { let conn = get_connection().map_err(|error| error.to_string())?; conn.query_row( "SELECT intervention_receipt_id - FROM agent_org_runtime_member_interventions + FROM agent_org_execution_member_interventions WHERE session_id=?1 AND original_turn_intent_id=?2 AND runtime_lease_id=?3 AND dialog_turn_generation=?4 AND status='yield_requested'", @@ -552,7 +552,7 @@ impl AgentMemberInterventionStore { let conn = get_connection().map_err(|error| error.to_string())?; conn.query_row( "SELECT intervention_receipt_id - FROM agent_org_runtime_member_interventions + FROM agent_org_execution_member_interventions WHERE session_id=?1 AND original_turn_intent_id=?2 AND status='yield_requested'", params![session_id, original_turn_intent_id], @@ -569,7 +569,7 @@ impl AgentMemberInterventionStore { let conn = get_connection().map_err(|error| error.to_string())?; conn.query_row( "SELECT intervention_receipt_id - FROM agent_org_runtime_member_interventions + FROM agent_org_execution_member_interventions WHERE session_id=?1 AND original_turn_intent_id=?2 AND status IN ('yield_requested','active','return_requested')", params![session_id, original_turn_intent_id], @@ -588,7 +588,7 @@ impl AgentMemberInterventionStore { let conn = get_connection().map_err(|error| error.to_string())?; let now = chrono::Utc::now().to_rfc3339(); conn.execute( - "UPDATE agent_org_runtime_member_interventions + "UPDATE agent_org_execution_member_interventions SET status='active',yield_released_at=?4, yield_timed_out_at=CASE WHEN yield_requested_at IS NOT NULL @@ -637,7 +637,7 @@ impl AgentMemberInterventionStore { let conn = get_connection().map_err(|error| error.to_string())?; let now = chrono::Utc::now().to_rfc3339(); conn.execute( - "UPDATE agent_org_runtime_member_interventions + "UPDATE agent_org_execution_member_interventions SET yield_timed_out_at=COALESCE(yield_timed_out_at,?2),updated_at=?2 WHERE intervention_receipt_id=?1 AND status='yield_requested'", params![receipt_id, now], @@ -675,17 +675,17 @@ impl AgentMemberInterventionStore { let now = chrono::Utc::now().to_rfc3339(); let changed = conn .execute( - "UPDATE agent_org_runtime_member_intervention_turns AS chain + "UPDATE agent_org_execution_member_intervention_turns AS chain SET status='running',started_at=COALESCE(started_at,?3) WHERE chain.session_id=?1 AND chain.turn_intent_id=?2 AND chain.status='queued' AND EXISTS ( - SELECT 1 FROM agent_org_runtime_member_interventions intervention + SELECT 1 FROM agent_org_execution_member_interventions intervention WHERE intervention.intervention_receipt_id=chain.intervention_receipt_id AND intervention.status='active' ) AND NOT EXISTS ( - SELECT 1 FROM agent_org_runtime_member_intervention_turns earlier + SELECT 1 FROM agent_org_execution_member_intervention_turns earlier WHERE earlier.intervention_receipt_id=chain.intervention_receipt_id AND earlier.member_dispatch_sequenceCOALESCE(?1,0) @@ -866,8 +866,8 @@ impl AgentMemberInterventionStore { AND intent.status='rejected' AND EXISTS ( SELECT 1 - FROM agent_org_runtime_member_intervention_turns chain - JOIN agent_org_runtime_member_interventions intervention + FROM agent_org_execution_member_intervention_turns chain + JOIN agent_org_execution_member_interventions intervention ON intervention.intervention_receipt_id=chain.intervention_receipt_id WHERE chain.session_id=intent.session_id AND chain.turn_intent_id=intent.turn_intent_id @@ -896,8 +896,8 @@ impl AgentMemberInterventionStore { let turn_intent_id: Option = tx .query_row( "SELECT chain.turn_intent_id - FROM agent_org_runtime_member_intervention_turns chain - JOIN agent_org_runtime_member_interventions intervention + FROM agent_org_execution_member_intervention_turns chain + JOIN agent_org_execution_member_interventions intervention ON intervention.intervention_receipt_id=chain.intervention_receipt_id WHERE chain.session_id=?1 AND chain.status='queued' AND intervention.status IN ('yield_requested','active','return_requested') @@ -914,7 +914,7 @@ impl AgentMemberInterventionStore { let now = chrono::Utc::now().to_rfc3339(); let changed = tx .execute( - "UPDATE agent_org_runtime_member_intervention_turns + "UPDATE agent_org_execution_member_intervention_turns SET status='cancelled',terminal_at=?3,failure_reason='user_stop' WHERE session_id=?1 AND turn_intent_id=?2 AND status='queued'", params![session_id, &turn_intent_id, &now], @@ -951,8 +951,8 @@ impl AgentMemberInterventionStore { let status: Option = tx .query_row( "SELECT chain.status - FROM agent_org_runtime_member_intervention_turns chain - JOIN agent_org_runtime_member_interventions intervention + FROM agent_org_execution_member_intervention_turns chain + JOIN agent_org_execution_member_interventions intervention ON intervention.intervention_receipt_id=chain.intervention_receipt_id WHERE chain.session_id=?1 AND chain.turn_intent_id=?2 AND chain.status IN ('queued','running') @@ -976,7 +976,7 @@ impl AgentMemberInterventionStore { let now = chrono::Utc::now().to_rfc3339(); let changed = tx .execute( - "UPDATE agent_org_runtime_member_intervention_turns + "UPDATE agent_org_execution_member_intervention_turns SET status='cancelled',terminal_at=?3,failure_reason='user_stop' WHERE session_id=?1 AND turn_intent_id=?2 AND status IN ('queued','running')", @@ -1056,7 +1056,7 @@ impl AgentMemberInterventionStore { let active_direct_count: i64 = tx .query_row( "SELECT COUNT(*) - FROM agent_org_runtime_member_intervention_turns + FROM agent_org_execution_member_intervention_turns WHERE intervention_receipt_id=?1 AND status IN ('queued','running')", [receipt_id], |row| row.get(0), @@ -1077,7 +1077,7 @@ impl AgentMemberInterventionStore { let run: Option<(String, i64)> = tx .query_row( "SELECT status,activation_generation - FROM agent_org_runtime_runs WHERE id=?1", + FROM agent_org_execution_runs WHERE id=?1", [&receipt.org_run_id], |row| Ok((row.get(0)?, row.get(1)?)), ) @@ -1090,7 +1090,7 @@ impl AgentMemberInterventionStore { })?; tx.execute( - "UPDATE agent_org_runtime_member_interventions + "UPDATE agent_org_execution_member_interventions SET status='return_requested',return_request_id=?2,updated_at=?3 WHERE intervention_receipt_id=?1 AND status IN ('yield_requested','active','return_requested')", @@ -1114,7 +1114,7 @@ impl AgentMemberInterventionStore { let still_owned_open: bool = tx .query_row( "SELECT EXISTS( - SELECT 1 FROM agent_org_runtime_tasks + SELECT 1 FROM agent_org_execution_tasks WHERE org_run_id=?1 AND id=?2 AND owner=?3 AND status IN ('pending','in_progress') )", @@ -1155,7 +1155,7 @@ impl AgentMemberInterventionStore { let cleared_revision: i64 = tx .query_row( "SELECT COALESCE(MAX(cleared_revision),0)+1 - FROM agent_org_runtime_member_interventions WHERE org_run_id=?1", + FROM agent_org_execution_member_interventions WHERE org_run_id=?1", [&receipt.org_run_id], |row| row.get(0), ) @@ -1163,7 +1163,7 @@ impl AgentMemberInterventionStore { let now = chrono::Utc::now().to_rfc3339(); let updated = tx .execute( - "UPDATE agent_org_runtime_member_interventions + "UPDATE agent_org_execution_member_interventions SET status='cleared',return_outcome=?3, continuation_turn_intent_id=?4,cleared_revision=?5, cleared_at=?6,updated_at=?6 @@ -1211,7 +1211,7 @@ impl AgentMemberInterventionStore { conn.query_row( "SELECT EXISTS( SELECT 1 - FROM agent_org_runtime_member_interventions intervention + FROM agent_org_execution_member_interventions intervention JOIN session_turn_intents intent ON intent.session_id=intervention.session_id AND intent.turn_intent_id=intervention.continuation_turn_intent_id @@ -1270,7 +1270,7 @@ impl AgentMemberInterventionStore { WHERE intent.session_id=?1 AND intent.turn_intent_id=?2 AND intent.status='rejected' AND EXISTS ( - SELECT 1 FROM agent_org_runtime_member_interventions intervention + SELECT 1 FROM agent_org_execution_member_interventions intervention WHERE intervention.session_id=intent.session_id AND intervention.continuation_turn_intent_id=intent.turn_intent_id AND intervention.status='cleared' @@ -1386,14 +1386,14 @@ impl AgentMemberInterventionStore { let revision: i64 = conn .query_row( "SELECT COALESCE(MAX(cleared_revision),0)+1 - FROM agent_org_runtime_member_interventions WHERE org_run_id=?1", + FROM agent_org_execution_member_interventions WHERE org_run_id=?1", [org_run_id], |row| row.get(0), ) .map_err(|error| error.to_string())?; conn.execute( &format!( - "UPDATE agent_org_runtime_member_interventions + "UPDATE agent_org_execution_member_interventions SET status='cleared',cleared_revision=?3,cleared_at=?4,updated_at=?4 WHERE org_run_id=?1 AND member_id=?2 AND status IN ({ACTIVE_STATUSES_SQL})" @@ -1421,7 +1421,7 @@ impl AgentMemberInterventionStore { let receipt_id = format!("test_intervention_{}", uuid::Uuid::new_v4()); let now = chrono::Utc::now().to_rfc3339(); conn.execute( - "INSERT INTO agent_org_runtime_member_interventions ( + "INSERT INTO agent_org_execution_member_interventions ( intervention_receipt_id,org_run_id,member_id,agent_id,session_id,status, source_event_id,entered_at,last_user_activity_at,updated_at ) VALUES (?1,?2,?3,?4,?5,'active',?6,?7,?7,?7)", @@ -1534,7 +1534,7 @@ fn running_formal_turn( let mut statement = conn .prepare( "SELECT context.task_id,context.turn_intent_id,context.member_dispatch_sequence - FROM agent_org_runtime_turn_contexts context + FROM agent_org_execution_turn_contexts context JOIN session_turn_intents intent ON intent.session_id=context.session_id AND intent.turn_intent_id=context.turn_intent_id @@ -1596,7 +1596,7 @@ pub(crate) fn update_chain_status_with_connection( let now = chrono::Utc::now().to_rfc3339(); let changed = conn .execute( - "UPDATE agent_org_runtime_member_intervention_turns + "UPDATE agent_org_execution_member_intervention_turns SET status=?4,terminal_at=?3,failure_reason=?5 WHERE session_id=?1 AND turn_intent_id=?2 AND status IN ('queued','running')", params![session_id, turn_intent_id, now, status, failure_reason], @@ -1618,7 +1618,7 @@ pub(crate) fn update_chain_status_with_connection( ) .map_err(|error| error.to_string())?; conn.execute( - "UPDATE agent_org_member_turn_admissions + "UPDATE agent_org_execution_member_turn_admissions SET status='rejected',reason_code=?3,terminal_at=?4,updated_at=?4 WHERE session_id=?1 AND turn_intent_id=?2 AND status='prepared'", params![ @@ -1637,11 +1637,11 @@ pub(crate) fn update_chain_status_with_connection( "user_directed_turn_failed" }; conn.execute( - "UPDATE agent_org_runtime_member_interventions + "UPDATE agent_org_execution_member_interventions SET failure_reason=?3,updated_at=?4 WHERE intervention_receipt_id=( SELECT intervention_receipt_id - FROM agent_org_runtime_member_intervention_turns + FROM agent_org_execution_member_intervention_turns WHERE session_id=?1 AND turn_intent_id=?2 )", params![session_id, turn_intent_id, failure_code, now], @@ -1658,7 +1658,7 @@ fn prepare_runtime_admission_with_connection( let existing: Option<(String, String, String)> = conn .query_row( "SELECT status,reservation_id,runtime_lease_id - FROM agent_org_member_turn_admissions + FROM agent_org_execution_member_turn_admissions WHERE session_id=?1 AND turn_intent_id=?2", params![¶ms.session_id, ¶ms.turn_intent_id], |row| Ok((row.get(0)?, row.get(1)?, row.get(2)?)), @@ -1669,7 +1669,7 @@ fn prepare_runtime_admission_with_connection( match existing { None => { conn.execute( - "INSERT INTO agent_org_member_turn_admissions ( + "INSERT INTO agent_org_execution_member_turn_admissions ( session_id,turn_intent_id,org_run_id,member_id, reservation_id,runtime_lease_id,status,prepared_at,updated_at ) VALUES (?1,?2,?3,?4,?5,?6,'prepared',?7,?7)", @@ -1691,7 +1691,7 @@ fn prepare_runtime_admission_with_connection( || runtime_lease_id != params.runtime_lease_id { conn.execute( - "UPDATE agent_org_member_turn_admissions + "UPDATE agent_org_execution_member_turn_admissions SET reservation_id=?3,runtime_lease_id=?4,updated_at=?5 WHERE session_id=?1 AND turn_intent_id=?2 AND status='prepared'", params![ @@ -1720,8 +1720,8 @@ fn notify_run_for_turn(session_id: &str, turn_intent_id: &str) { let run_id = get_connection().ok().and_then(|conn| { conn.query_row( "SELECT intervention.org_run_id - FROM agent_org_runtime_member_intervention_turns chain - JOIN agent_org_runtime_member_interventions intervention + FROM agent_org_execution_member_intervention_turns chain + JOIN agent_org_execution_member_interventions intervention ON intervention.intervention_receipt_id=chain.intervention_receipt_id WHERE chain.session_id=?1 AND chain.turn_intent_id=?2", params![session_id, turn_intent_id], diff --git a/src-tauri/crates/agent-core/src/core/coordination/agent_member_interventions/continuation.rs b/src-tauri/crates/agent-core/src/core/coordination/agent_member_interventions/continuation.rs index e56fe944bf..55939985b0 100644 --- a/src-tauri/crates/agent-core/src/core/coordination/agent_member_interventions/continuation.rs +++ b/src-tauri/crates/agent-core/src/core/coordination/agent_member_interventions/continuation.rs @@ -10,7 +10,7 @@ pub(crate) fn continuation_nudge_for_turn( let returned: Option<(String, String, String)> = conn .query_row( "SELECT intervention.org_run_id,intervention.member_id,intervention.original_task_id - FROM agent_org_runtime_member_interventions intervention + FROM agent_org_execution_member_interventions intervention JOIN session_turn_intents intent ON intent.session_id=intervention.session_id AND intent.turn_intent_id=intervention.continuation_turn_intent_id diff --git a/src-tauri/crates/agent-core/src/core/coordination/agent_member_interventions/continuation_tests.rs b/src-tauri/crates/agent-core/src/core/coordination/agent_member_interventions/continuation_tests.rs index 5e8edc797c..757fe5ddb4 100644 --- a/src-tauri/crates/agent-core/src/core/coordination/agent_member_interventions/continuation_tests.rs +++ b/src-tauri/crates/agent-core/src/core/coordination/agent_member_interventions/continuation_tests.rs @@ -27,7 +27,12 @@ fn explicit_return_supplies_bound_task_instruction_without_new_input_rows() { let (fixture, task_id, original, continuation) = returned_task("return-input"); let conn = get_connection().expect("database"); let counts = || { - ["events", "agent_org_runtime_inbox", "session_turn_intents"].map(|table| { + [ + "events", + "agent_org_execution_inbox", + "session_turn_intents", + ] + .map(|table| { conn.query_row(&format!("SELECT COUNT(*) FROM {table}"), [], |row| { row.get::<_, i64>(0) }) @@ -103,24 +108,24 @@ fn return_instruction_revalidates_generation_and_task_before_provider() { let (fixture, task_id, _, continuation) = returned_task("return-stale-input"); let conn = get_connection().expect("database"); conn.execute( - "UPDATE agent_org_runtime_runs SET activation_generation=2 WHERE id=?1", + "UPDATE agent_org_execution_runs SET activation_generation=2 WHERE id=?1", [&fixture.run_id], ) .unwrap(); assert!(continuation_nudge_for_turn(&fixture.member_session_id, &continuation).is_err()); conn.execute( - "UPDATE agent_org_runtime_runs SET activation_generation=1 WHERE id=?1", + "UPDATE agent_org_execution_runs SET activation_generation=1 WHERE id=?1", [&fixture.run_id], ) .unwrap(); conn.execute( - "UPDATE agent_org_runtime_tasks SET status='completed',output_json='{}' WHERE org_run_id=?1 AND id=?2", + "UPDATE agent_org_execution_tasks SET status='completed',output_json='{}' WHERE org_run_id=?1 AND id=?2", params![fixture.run_id, task_id], ) .unwrap(); assert!(continuation_nudge_for_turn(&fixture.member_session_id, &continuation).is_err()); conn.execute( - "UPDATE agent_org_runtime_tasks SET status='in_progress',output_json=NULL WHERE org_run_id=?1 AND id=?2", + "UPDATE agent_org_execution_tasks SET status='in_progress',output_json=NULL WHERE org_run_id=?1 AND id=?2", params![fixture.run_id, task_id], ) .unwrap(); @@ -130,7 +135,7 @@ fn return_instruction_revalidates_generation_and_task_before_provider() { .unwrap() .is_none() ); - conn.execute_batch("DROP TABLE agent_org_runtime_member_interventions") + conn.execute_batch("DROP TABLE agent_org_execution_member_interventions") .unwrap(); assert!( continuation_nudge_for_turn(&fixture.member_session_id, &continuation).is_err(), diff --git a/src-tauri/crates/agent-core/src/core/coordination/agent_member_interventions/persistence.rs b/src-tauri/crates/agent-core/src/core/coordination/agent_member_interventions/persistence.rs index c2e120784a..7b7656a1e3 100644 --- a/src-tauri/crates/agent-core/src/core/coordination/agent_member_interventions/persistence.rs +++ b/src-tauri/crates/agent-core/src/core/coordination/agent_member_interventions/persistence.rs @@ -4,7 +4,7 @@ use super::{AgentMemberInterventionRecord, AppliedReturnToWorkOutcome, MemberInt pub(crate) fn create_schema(conn: &Connection) -> SqliteResult<()> { conn.execute_batch( - "CREATE TABLE IF NOT EXISTS agent_org_runtime_member_interventions ( + "CREATE TABLE IF NOT EXISTS agent_org_execution_member_interventions ( intervention_receipt_id TEXT PRIMARY KEY, org_run_id TEXT NOT NULL, member_id TEXT NOT NULL CHECK(length(trim(member_id)) > 0), @@ -33,27 +33,27 @@ pub(crate) fn create_schema(conn: &Connection) -> SqliteResult<()> { cleared_at TEXT, failure_reason TEXT, updated_at TEXT NOT NULL, - FOREIGN KEY(org_run_id) REFERENCES agent_org_runtime_runs(id) ON DELETE CASCADE, + FOREIGN KEY(org_run_id) REFERENCES agent_org_execution_runs(id) ON DELETE CASCADE, CHECK((runtime_lease_id IS NULL) = (dialog_turn_generation IS NULL)), CHECK((original_task_id IS NULL) = (original_turn_intent_id IS NULL)), CHECK((cleared_at IS NULL) = (status NOT IN ('cleared','failed'))) ); - CREATE UNIQUE INDEX IF NOT EXISTS idx_agent_org_member_intervention_active - ON agent_org_runtime_member_interventions(org_run_id, member_id) + CREATE UNIQUE INDEX IF NOT EXISTS idx_agent_org_execution_member_intervention_active + ON agent_org_execution_member_interventions(org_run_id, member_id) WHERE status IN ('yield_requested','active','return_requested'); - CREATE INDEX IF NOT EXISTS idx_agent_org_member_intervention_session - ON agent_org_runtime_member_interventions(session_id, status, updated_at); - CREATE UNIQUE INDEX IF NOT EXISTS idx_agent_org_member_intervention_return_request - ON agent_org_runtime_member_interventions(org_run_id, return_request_id) + CREATE INDEX IF NOT EXISTS idx_agent_org_execution_member_intervention_session + ON agent_org_execution_member_interventions(session_id, status, updated_at); + CREATE UNIQUE INDEX IF NOT EXISTS idx_agent_org_execution_member_intervention_return_request + ON agent_org_execution_member_interventions(org_run_id, return_request_id) WHERE return_request_id IS NOT NULL; - CREATE UNIQUE INDEX IF NOT EXISTS idx_agent_org_member_intervention_continuation - ON agent_org_runtime_member_interventions(session_id, continuation_turn_intent_id) + CREATE UNIQUE INDEX IF NOT EXISTS idx_agent_org_execution_member_intervention_continuation + ON agent_org_execution_member_interventions(session_id, continuation_turn_intent_id) WHERE continuation_turn_intent_id IS NOT NULL; - CREATE INDEX IF NOT EXISTS idx_agent_org_member_intervention_public_timeline - ON agent_org_runtime_member_interventions( + CREATE INDEX IF NOT EXISTS idx_agent_org_execution_member_intervention_public_timeline + ON agent_org_execution_member_interventions( org_run_id,cleared_at,intervention_receipt_id ) WHERE status='cleared'; - CREATE TABLE IF NOT EXISTS agent_org_runtime_member_intervention_turns ( + CREATE TABLE IF NOT EXISTS agent_org_execution_member_intervention_turns ( intervention_receipt_id TEXT NOT NULL, session_id TEXT NOT NULL, turn_intent_id TEXT NOT NULL, @@ -71,14 +71,14 @@ pub(crate) fn create_schema(conn: &Connection) -> SqliteResult<()> { UNIQUE(intervention_receipt_id, chain_position), UNIQUE(source_event_id), FOREIGN KEY(intervention_receipt_id) - REFERENCES agent_org_runtime_member_interventions(intervention_receipt_id) + REFERENCES agent_org_execution_member_interventions(intervention_receipt_id) ON DELETE CASCADE, FOREIGN KEY(session_id, turn_intent_id) REFERENCES session_turn_intents(session_id, turn_intent_id) ON DELETE CASCADE ); - CREATE INDEX IF NOT EXISTS idx_agent_org_member_intervention_turn_queue - ON agent_org_runtime_member_intervention_turns( + CREATE INDEX IF NOT EXISTS idx_agent_org_execution_member_intervention_turn_queue + ON agent_org_execution_member_intervention_turns( intervention_receipt_id, status, member_dispatch_sequence );", )?; @@ -90,7 +90,7 @@ pub(crate) fn create_schema(conn: &Connection) -> SqliteResult<()> { /// table on every startup and older builds safely preserve it. pub(crate) fn create_runtime_admission_schema(conn: &Connection) -> SqliteResult<()> { conn.execute_batch( - "CREATE TABLE IF NOT EXISTS agent_org_member_turn_admissions ( + "CREATE TABLE IF NOT EXISTS agent_org_execution_member_turn_admissions ( session_id TEXT NOT NULL, turn_intent_id TEXT NOT NULL, org_run_id TEXT NOT NULL, @@ -111,15 +111,15 @@ pub(crate) fn create_runtime_admission_schema(conn: &Connection) -> SqliteResult REFERENCES session_turn_intents(session_id, turn_intent_id) ON DELETE CASCADE, FOREIGN KEY(org_run_id) - REFERENCES agent_org_runtime_runs(id) ON DELETE CASCADE, + REFERENCES agent_org_execution_runs(id) ON DELETE CASCADE, CHECK( (status='prepared' AND committed_at IS NULL AND terminal_at IS NULL) OR (status='committed' AND committed_at IS NOT NULL AND terminal_at IS NULL) OR (status IN ('rejected','unknown') AND terminal_at IS NOT NULL) ) ); - CREATE INDEX IF NOT EXISTS idx_agent_org_member_turn_admission_recovery - ON agent_org_member_turn_admissions(status, updated_at);", + CREATE INDEX IF NOT EXISTS idx_agent_org_execution_member_turn_admission_recovery + ON agent_org_execution_member_turn_admissions(status, updated_at);", ) } @@ -136,7 +136,7 @@ pub(super) const INTERVENTION_SELECT: &str = "SELECT intervention.original_member_dispatch_sequence, intervention.runtime_lease_id, intervention.dialog_turn_generation, - (SELECT COUNT(*) FROM agent_org_runtime_member_intervention_turns chain + (SELECT COUNT(*) FROM agent_org_execution_member_intervention_turns chain WHERE chain.intervention_receipt_id=intervention.intervention_receipt_id AND chain.status IN ('queued','running')), intervention.entered_at, @@ -150,7 +150,7 @@ pub(super) const INTERVENTION_SELECT: &str = "SELECT intervention.cleared_revision, intervention.cleared_at, intervention.failure_reason - FROM agent_org_runtime_member_interventions intervention"; + FROM agent_org_execution_member_interventions intervention"; pub(super) fn row_to_intervention( row: &rusqlite::Row<'_>, diff --git a/src-tauri/crates/agent-core/src/core/coordination/agent_member_interventions_tests.rs b/src-tauri/crates/agent-core/src/core/coordination/agent_member_interventions_tests.rs index 7da949d9f9..07bb288c76 100644 --- a/src-tauri/crates/agent-core/src/core/coordination/agent_member_interventions_tests.rs +++ b/src-tauri/crates/agent-core/src/core/coordination/agent_member_interventions_tests.rs @@ -165,7 +165,7 @@ fn create_fixture(prefix: &str, status: AgentOrgRunStatus) -> DirectFixture { let conn = get_connection().expect("test sqlite connection"); conn.execute( - "INSERT INTO agent_org_runtime_member_materializations ( + "INSERT INTO agent_org_execution_member_materializations ( org_run_id,member_id,agent_id,generation,session_id, authority_class,status,created_at,updated_at ) VALUES (?1,?2,?3,1,?4,'formal','succeeded',?5,?5)", @@ -182,7 +182,7 @@ fn create_fixture(prefix: &str, status: AgentOrgRunStatus) -> DirectFixture { match status { AgentOrgRunStatus::Archived => { conn.execute( - "UPDATE agent_org_runtime_runs + "UPDATE agent_org_execution_runs SET status='archived',archived_at=?2,archive_receipt_id=?3,updated_at=?2 WHERE id=?1", params![&run.id, &now, format!("archive-{prefix}")], @@ -191,7 +191,7 @@ fn create_fixture(prefix: &str, status: AgentOrgRunStatus) -> DirectFixture { } other => { conn.execute( - "UPDATE agent_org_runtime_runs SET status=?2,updated_at=?3 WHERE id=?1", + "UPDATE agent_org_execution_runs SET status=?2,updated_at=?3 WHERE id=?1", params![&run.id, other.as_str(), &now], ) .expect("set fixture Team status"); @@ -237,7 +237,7 @@ fn grant_direct_member_writer(fixture: &DirectFixture) { let conn = get_connection().expect("writer snapshot connection"); let mut snapshot: crate::definitions::orgs::AgentOrgLaunchSnapshot = conn .query_row( - "SELECT org_snapshot_json FROM agent_org_runtime_runs WHERE id=?1", + "SELECT org_snapshot_json FROM agent_org_execution_runs WHERE id=?1", [&fixture.run_id], |row| row.get::<_, String>(0), ) @@ -245,7 +245,7 @@ fn grant_direct_member_writer(fixture: &DirectFixture) { .expect("load launch snapshot"); snapshot.additional_task_graph_writer_member_ids = vec![MEMBER_ID.to_string()]; conn.execute( - "UPDATE agent_org_runtime_runs SET org_snapshot_json=?2 WHERE id=?1", + "UPDATE agent_org_execution_runs SET org_snapshot_json=?2 WHERE id=?1", params![ &fixture.run_id, serde_json::to_string(&snapshot).expect("encode launch snapshot") @@ -419,13 +419,13 @@ fn admission_atomically_persists_source_context_sequence_receipt_and_chain() { (SELECT COUNT(*) FROM events WHERE id='event-atomic'), (SELECT COUNT(*) FROM session_turn_intents WHERE session_id=?1 AND turn_intent_id='turn-atomic' AND status='queued'), - (SELECT COUNT(*) FROM agent_org_runtime_turn_contexts + (SELECT COUNT(*) FROM agent_org_execution_turn_contexts WHERE session_id=?1 AND turn_intent_id='turn-atomic' AND source_kind='direct_member' AND source_id='event-atomic'), - (SELECT COUNT(*) FROM agent_org_runtime_member_intervention_turns + (SELECT COUNT(*) FROM agent_org_execution_member_intervention_turns WHERE session_id=?1 AND turn_intent_id='turn-atomic' AND member_dispatch_sequence=1 AND chain_position=1), - (SELECT COUNT(*) FROM agent_org_member_turn_admissions + (SELECT COUNT(*) FROM agent_org_execution_member_turn_admissions WHERE session_id=?1 AND turn_intent_id='turn-atomic' AND reservation_id='reservation-turn-atomic' AND runtime_lease_id='runtime-lease-test' AND status='prepared')", @@ -568,8 +568,8 @@ fn exact_replay_returns_the_same_receipt_and_never_allocates_again() { .query_row( "SELECT (SELECT COUNT(*) FROM session_turn_intents WHERE session_id=?1), - (SELECT COUNT(*) FROM agent_org_runtime_turn_contexts WHERE session_id=?1), - (SELECT COUNT(*) FROM agent_org_runtime_member_intervention_turns WHERE session_id=?1)", + (SELECT COUNT(*) FROM agent_org_execution_turn_contexts WHERE session_id=?1), + (SELECT COUNT(*) FROM agent_org_execution_member_intervention_turns WHERE session_id=?1)", [&fixture.member_session_id], |row| Ok((row.get(0)?, row.get(1)?, row.get(2)?)), ) @@ -632,7 +632,7 @@ fn failed_dispatch_replay_stays_terminal_and_is_not_startup_recoverable() { let admission_status: String = get_connection() .expect("read failed runtime admission") .query_row( - "SELECT status FROM agent_org_member_turn_admissions + "SELECT status FROM agent_org_execution_member_turn_admissions WHERE session_id=?1 AND turn_intent_id='turn-dispatch-failed'", [&fixture.member_session_id], |row| row.get(0), @@ -764,8 +764,8 @@ fn queue_cap_rejects_n_plus_one_and_keeps_the_user_event_only() { "SELECT (SELECT COUNT(*) FROM events WHERE session_id=?1), (SELECT COUNT(*) FROM session_turn_intents WHERE session_id=?1), - (SELECT COUNT(*) FROM agent_org_runtime_turn_contexts WHERE session_id=?1), - (SELECT COUNT(*) FROM agent_org_runtime_member_intervention_turns WHERE session_id=?1)", + (SELECT COUNT(*) FROM agent_org_execution_turn_contexts WHERE session_id=?1), + (SELECT COUNT(*) FROM agent_org_execution_member_intervention_turns WHERE session_id=?1)", [&fixture.member_session_id], |row| Ok((row.get(0)?, row.get(1)?, row.get(2)?, row.get(3)?)), ) @@ -781,7 +781,7 @@ fn receipt_or_chain_failure_rolls_back_turn_context_and_sequence() { let conn = get_connection().expect("test sqlite connection"); conn.execute_batch( "CREATE TRIGGER fail_direct_chain_fixture - BEFORE INSERT ON agent_org_runtime_member_intervention_turns + BEFORE INSERT ON agent_org_execution_member_intervention_turns BEGIN SELECT RAISE(ABORT,'fixture chain failure'); END;", ) .expect("install transaction fault"); @@ -795,11 +795,11 @@ fn receipt_or_chain_failure_rolls_back_turn_context_and_sequence() { .query_row( "SELECT (SELECT COUNT(*) FROM session_turn_intents WHERE session_id=?1), - (SELECT COUNT(*) FROM agent_org_runtime_turn_contexts WHERE session_id=?1), - (SELECT COUNT(*) FROM agent_org_runtime_member_interventions WHERE session_id=?1), - (SELECT COUNT(*) FROM agent_org_runtime_member_dispatch_allocators + (SELECT COUNT(*) FROM agent_org_execution_turn_contexts WHERE session_id=?1), + (SELECT COUNT(*) FROM agent_org_execution_member_interventions WHERE session_id=?1), + (SELECT COUNT(*) FROM agent_org_execution_member_dispatch_allocators WHERE org_run_id=?2 AND member_id=?3), - (SELECT COUNT(*) FROM agent_org_member_turn_admissions + (SELECT COUNT(*) FROM agent_org_execution_member_turn_admissions WHERE session_id=?1)", params![&fixture.member_session_id, &fixture.run_id, MEMBER_ID], |row| { @@ -868,7 +868,7 @@ fn fifty_concurrent_direct_turns_share_one_receipt_and_one_fifo() { let prepared_admissions: i64 = get_connection() .expect("read concurrent runtime admissions") .query_row( - "SELECT COUNT(*) FROM agent_org_member_turn_admissions + "SELECT COUNT(*) FROM agent_org_execution_member_turn_admissions WHERE session_id=?1 AND status='prepared'", [&fixture.member_session_id], |row| row.get(0), @@ -1116,7 +1116,7 @@ fn return_restores_one_exact_continuation_and_never_duplicates_it() { ) .expect("start original formal Turn"); conn.execute( - "INSERT INTO agent_org_runtime_inbox_materializations ( + "INSERT INTO agent_org_execution_inbox_materializations ( inbox_id,session_id,transcript_message_id,transcript_intent_id,materialized_at ) VALUES (?1,?2,'task-restore-source','turn-original',?3)", params![ @@ -1192,7 +1192,7 @@ fn return_restores_one_exact_continuation_and_never_duplicates_it() { let conn = get_connection().expect("test sqlite connection"); let continuation_count: i64 = conn .query_row( - "SELECT COUNT(*) FROM agent_org_runtime_turn_contexts + "SELECT COUNT(*) FROM agent_org_execution_turn_contexts WHERE session_id=?1 AND task_id='task-restore' AND turn_intent_id<> 'turn-original'", [&fixture.member_session_id], @@ -1292,13 +1292,13 @@ fn return_restores_one_exact_continuation_and_never_duplicates_it() { .query_row( "SELECT inbox.read_at, (SELECT COUNT(*) - FROM agent_org_runtime_inbox_delivery_resolutions resolution + FROM agent_org_execution_inbox_delivery_resolutions resolution WHERE resolution.inbox_id=inbox.id AND resolution.reason='task_completed'), (SELECT COUNT(*) - FROM agent_org_runtime_inbox_materializations materialization + FROM agent_org_execution_inbox_materializations materialization WHERE materialization.inbox_id=inbox.id) - FROM agent_org_runtime_inbox inbox WHERE inbox.id=?1", + FROM agent_org_execution_inbox inbox WHERE inbox.id=?1", [assignment.id], |row| Ok((row.get(0)?, row.get(1)?, row.get(2)?)), ) @@ -1356,13 +1356,13 @@ fn return_binds_one_continuation_to_the_current_activation_generation() { create_recoverable_formal_intervention("return-current-generation"); let conn = get_connection().expect("test sqlite connection"); conn.execute( - "UPDATE agent_org_runtime_runs + "UPDATE agent_org_execution_runs SET activation_generation=2,updated_at=?2 WHERE id=?1", params![&fixture.run_id, chrono::Utc::now().to_rfc3339()], ) .expect("advance Team activation generation"); conn.execute( - "UPDATE agent_org_runtime_tasks + "UPDATE agent_org_execution_tasks SET activation_generation=2,updated_at=?3 WHERE org_run_id=?1 AND id=?2 AND owner=?4", params![ @@ -1390,7 +1390,7 @@ fn return_binds_one_continuation_to_the_current_activation_generation() { let continuations: Vec<(String, i64)> = conn .prepare( "SELECT turn_intent_id,activation_generation - FROM agent_org_runtime_turn_contexts + FROM agent_org_execution_turn_contexts WHERE session_id=?1 AND task_id=?2 AND turn_intent_id<>?3 ORDER BY context_id ASC", ) @@ -1419,7 +1419,7 @@ fn return_binds_one_continuation_to_the_current_activation_generation() { let conn = get_connection().expect("test sqlite connection"); let continuation_count: i64 = conn .query_row( - "SELECT COUNT(*) FROM agent_org_runtime_turn_contexts + "SELECT COUNT(*) FROM agent_org_execution_turn_contexts WHERE session_id=?1 AND task_id=?2 AND turn_intent_id<>?3", params![&fixture.member_session_id, &task_id, &formal_turn_id], |row| row.get(0), @@ -1441,19 +1441,19 @@ fn return_does_not_restore_completed_cancelled_or_reassigned_work() { let conn = get_connection().expect("test sqlite connection"); match mutation { "completed" => conn.execute( - "UPDATE agent_org_runtime_tasks + "UPDATE agent_org_execution_tasks SET status='completed',output_json='{}',updated_at=?3 WHERE org_run_id=?1 AND id=?2", params![&fixture.run_id, &task_id, chrono::Utc::now().to_rfc3339()], ), "cancelled" => conn.execute( - "UPDATE agent_org_runtime_tasks + "UPDATE agent_org_execution_tasks SET status='cancelled',cancel_reason_json='{\"code\":\"test\"}',updated_at=?3 WHERE org_run_id=?1 AND id=?2", params![&fixture.run_id, &task_id, chrono::Utc::now().to_rfc3339()], ), "reassigned" => conn.execute( - "UPDATE agent_org_runtime_tasks SET owner='different-member',updated_at=?3 + "UPDATE agent_org_execution_tasks SET owner='different-member',updated_at=?3 WHERE org_run_id=?1 AND id=?2", params![&fixture.run_id, &task_id, chrono::Utc::now().to_rfc3339()], ), @@ -1479,7 +1479,7 @@ fn return_does_not_restore_completed_cancelled_or_reassigned_work() { let conn = get_connection().expect("test sqlite connection"); let continuation_count: i64 = conn .query_row( - "SELECT COUNT(*) FROM agent_org_runtime_turn_contexts + "SELECT COUNT(*) FROM agent_org_execution_turn_contexts WHERE session_id=?1 AND task_id=?2 AND turn_intent_id<>?3", params![&fixture.member_session_id, &task_id, &formal_turn_id], |row| row.get(0), @@ -1601,7 +1601,7 @@ fn stop_persists_one_exact_terminal_turn_and_return_waits_for_formal_yield() { let conn = get_connection().expect("read exact Stop evidence"); let status: String = conn .query_row( - "SELECT status FROM agent_org_runtime_member_intervention_turns + "SELECT status FROM agent_org_execution_member_intervention_turns WHERE session_id=?1 AND turn_intent_id='turn-stop-direct'", [&fixture.member_session_id], |row| row.get(0), @@ -1667,9 +1667,9 @@ fn restart_recovers_only_pending_direct_turns_and_never_replays_started_work() { let admission_statuses: (String, String) = conn .query_row( "SELECT - (SELECT status FROM agent_org_member_turn_admissions + (SELECT status FROM agent_org_execution_member_turn_admissions WHERE turn_intent_id='turn-restart-started'), - (SELECT status FROM agent_org_member_turn_admissions + (SELECT status FROM agent_org_execution_member_turn_admissions WHERE turn_intent_id='turn-restart-pending')", [], |row| Ok((row.get(0)?, row.get(1)?)), @@ -1679,11 +1679,11 @@ fn restart_recovers_only_pending_direct_turns_and_never_replays_started_work() { let statuses: (String, String, String, String) = conn .query_row( "SELECT - (SELECT status FROM agent_org_runtime_member_intervention_turns + (SELECT status FROM agent_org_execution_member_intervention_turns WHERE turn_intent_id='turn-restart-started'), (SELECT status FROM session_turn_intents WHERE turn_intent_id='turn-restart-started'), - (SELECT status FROM agent_org_runtime_member_intervention_turns + (SELECT status FROM agent_org_execution_member_intervention_turns WHERE turn_intent_id='turn-restart-pending'), (SELECT status FROM session_turn_intents WHERE turn_intent_id='turn-restart-pending')", diff --git a/src-tauri/crates/agent-core/src/core/coordination/agent_org_archive.rs b/src-tauri/crates/agent-core/src/core/coordination/agent_org_archive.rs index 4ac98728e5..b0520f41fb 100644 --- a/src-tauri/crates/agent-core/src/core/coordination/agent_org_archive.rs +++ b/src-tauri/crates/agent-core/src/core/coordination/agent_org_archive.rs @@ -93,7 +93,7 @@ pub(crate) struct ArchiveTeardownTarget { pub(super) fn create_schema(conn: &Connection) -> rusqlite::Result<()> { conn.execute_batch( - "CREATE TABLE IF NOT EXISTS agent_org_runtime_archive_episodes ( + "CREATE TABLE IF NOT EXISTS agent_org_execution_archive_episodes ( archive_receipt_id TEXT PRIMARY KEY CHECK(length(trim(archive_receipt_id)) > 0), org_run_id TEXT NOT NULL UNIQUE, archive_request_id TEXT NOT NULL CHECK(length(trim(archive_request_id)) > 0), @@ -118,7 +118,7 @@ pub(super) fn create_schema(conn: &Connection) -> rusqlite::Result<()> { updated_at TEXT NOT NULL, quiesced_at TEXT, UNIQUE(org_run_id, archive_request_id), - FOREIGN KEY(org_run_id) REFERENCES agent_org_runtime_runs(id) ON DELETE CASCADE, + FOREIGN KEY(org_run_id) REFERENCES agent_org_execution_runs(id) ON DELETE CASCADE, CHECK( (teardown_status='quiesced' AND quiesced_at IS NOT NULL AND retained_runtime_count=0) @@ -126,10 +126,10 @@ pub(super) fn create_schema(conn: &Connection) -> rusqlite::Result<()> { (teardown_status<>'quiesced' AND quiesced_at IS NULL) ) ); - CREATE INDEX IF NOT EXISTS idx_agent_org_runtime_archive_pending - ON agent_org_runtime_archive_episodes(teardown_status, deadline_at); + CREATE INDEX IF NOT EXISTS idx_agent_org_execution_archive_pending + ON agent_org_execution_archive_episodes(teardown_status, deadline_at); - CREATE TABLE IF NOT EXISTS agent_org_runtime_archive_teardowns ( + CREATE TABLE IF NOT EXISTS agent_org_execution_archive_teardowns ( teardown_id TEXT PRIMARY KEY CHECK(length(trim(teardown_id)) > 0), archive_receipt_id TEXT NOT NULL, org_run_id TEXT NOT NULL, @@ -148,8 +148,8 @@ pub(super) fn create_schema(conn: &Connection) -> rusqlite::Result<()> { updated_at TEXT NOT NULL, UNIQUE(archive_receipt_id, session_id), FOREIGN KEY(archive_receipt_id) - REFERENCES agent_org_runtime_archive_episodes(archive_receipt_id) ON DELETE CASCADE, - FOREIGN KEY(org_run_id) REFERENCES agent_org_runtime_runs(id) ON DELETE CASCADE, + REFERENCES agent_org_execution_archive_episodes(archive_receipt_id) ON DELETE CASCADE, + FOREIGN KEY(org_run_id) REFERENCES agent_org_execution_runs(id) ON DELETE CASCADE, CHECK( (teardown_status='quiesced' AND released_at IS NOT NULL) OR @@ -160,8 +160,8 @@ pub(super) fn create_schema(conn: &Connection) -> rusqlite::Result<()> { OR runtime_lease_id IS NOT NULL ) ); - CREATE INDEX IF NOT EXISTS idx_agent_org_runtime_archive_teardown_pending - ON agent_org_runtime_archive_teardowns( + CREATE INDEX IF NOT EXISTS idx_agent_org_execution_archive_teardown_pending + ON agent_org_execution_archive_teardowns( archive_receipt_id, teardown_status, session_id );", ) @@ -186,7 +186,7 @@ pub(crate) fn archive_run_commit(run_id: &str, request_id: &str) -> Result = tx .query_row( "SELECT status,activation_generation - FROM agent_org_runtime_runs WHERE id=?1", + FROM agent_org_execution_runs WHERE id=?1", [run_id], |row| Ok((row.get(0)?, row.get(1)?)), ) @@ -225,7 +225,7 @@ pub(crate) fn archive_run_commit(run_id: &str, request_id: &str) -> Result Result Result Result Result Result Result Result Result Result Result = tx .query_row( "SELECT teardown_status,teardown_attempt_count - FROM agent_org_runtime_archive_episodes + FROM agent_org_execution_archive_episodes WHERE archive_receipt_id=?1 AND org_run_id=?2", params![&target.receipt_id, &target.run_id], |row| Ok((row.get(0)?, row.get(1)?)), @@ -480,7 +480,7 @@ pub(crate) fn record_teardown_attempt( }; let changed = tx .execute( - "UPDATE agent_org_runtime_archive_teardowns + "UPDATE agent_org_execution_archive_teardowns SET teardown_status=?4,attempt_count=?5,runtime_lease_id=?6, dialog_turn_generation=?7,last_error=?8, released_at=CASE WHEN ?4='quiesced' THEN ?9 ELSE NULL END, @@ -521,7 +521,7 @@ pub(crate) fn mark_deadline_expired(receipt_id: &str) -> Result Result, String> { let conn = database::db::get_connection().map_err(|error| error.to_string())?; let mut statement = conn .prepare( - "SELECT archive_receipt_id FROM agent_org_runtime_archive_episodes + "SELECT archive_receipt_id FROM agent_org_execution_archive_episodes WHERE teardown_status='pending' ORDER BY archived_at ASC LIMIT ?1", ) @@ -578,7 +578,7 @@ pub(crate) fn summary_for_run_with_connection( ) -> Result, String> { let receipt_id: Option = conn .query_row( - "SELECT archive_receipt_id FROM agent_org_runtime_archive_episodes + "SELECT archive_receipt_id FROM agent_org_execution_archive_episodes WHERE org_run_id=?1", [run_id], |row| row.get(0), @@ -602,7 +602,7 @@ fn recompute_archive_summary( SUM(CASE WHEN teardown_status='pending' THEN 1 ELSE 0 END), SUM(CASE WHEN teardown_status='retained_runtime' THEN 1 ELSE 0 END), COALESCE(MAX(attempt_count),0) - FROM agent_org_runtime_archive_teardowns + FROM agent_org_execution_archive_teardowns WHERE archive_receipt_id=?1", [receipt_id], |row| Ok((row.get(0)?, row.get(1)?, row.get(2)?)), @@ -616,7 +616,7 @@ fn recompute_archive_summary( ArchiveTeardownStatus::Quiesced }; conn.execute( - "UPDATE agent_org_runtime_archive_episodes + "UPDATE agent_org_execution_archive_episodes SET teardown_status=?2,teardown_attempt_count=?3, retained_runtime_count=?4,last_error=COALESCE(?5,last_error), quiesced_at=CASE WHEN ?2='quiesced' THEN ?6 ELSE NULL END, @@ -647,7 +647,7 @@ fn outcome_for_request( approval_cancel_count,intervention_cancel_count, pause_continuation_cancel_count,teardown_status, teardown_attempt_count,retained_runtime_count,deadline_at - FROM agent_org_runtime_archive_episodes + FROM agent_org_execution_archive_episodes WHERE org_run_id=?1 AND archive_request_id=?2", params![run_id, request_id], |row| { @@ -691,7 +691,7 @@ fn outcome_for_request( fn load_summary(conn: &Connection, receipt_id: &str) -> Result { conn.query_row( "SELECT teardown_status,teardown_attempt_count,retained_runtime_count,deadline_at - FROM agent_org_runtime_archive_episodes WHERE archive_receipt_id=?1", + FROM agent_org_execution_archive_episodes WHERE archive_receipt_id=?1", [receipt_id], |row| { let status_raw: String = row.get(0)?; diff --git a/src-tauri/crates/agent-core/src/core/coordination/agent_org_archive_tests.rs b/src-tauri/crates/agent-core/src/core/coordination/agent_org_archive_tests.rs index 8e67d8fc47..606def6248 100644 --- a/src-tauri/crates/agent-core/src/core/coordination/agent_org_archive_tests.rs +++ b/src-tauri/crates/agent-core/src/core/coordination/agent_org_archive_tests.rs @@ -66,7 +66,7 @@ fn seed_run(run_id: &str, root_session_id: &str, status: &str, generation: i64) database::db::get_connection() .expect("sandbox DB") .execute( - "INSERT INTO agent_org_runtime_runs ( + "INSERT INTO agent_org_execution_runs ( id,org_id,coordinator_agent_id,root_session_id,org_snapshot_json,entry_mode, status,activation_generation,created_at,updated_at ) VALUES (?1,'org-archive-test','coordinator-agent',?2,?3, @@ -99,7 +99,7 @@ fn assert_archive_failure_rolled_back(run_id: &str, expected_error: &str) { ); assert_eq!( scalar_string( - "SELECT status FROM agent_org_runtime_runs WHERE id=?1", + "SELECT status FROM agent_org_execution_runs WHERE id=?1", run_id ), "running" @@ -107,7 +107,7 @@ fn assert_archive_failure_rolled_back(run_id: &str, expected_error: &str) { let receipt_count: i64 = database::db::get_connection() .expect("sandbox DB") .query_row( - "SELECT COUNT(*) FROM agent_org_runtime_archive_episodes WHERE org_run_id=?1", + "SELECT COUNT(*) FROM agent_org_execution_archive_episodes WHERE org_run_id=?1", [run_id], |row| row.get(0), ) @@ -127,7 +127,7 @@ fn archive_fence_cancels_open_work_and_is_request_idempotent() { seed_run(run_id, root, "running", 1); let conn = database::db::get_connection().expect("sandbox DB"); conn.execute( - "INSERT INTO agent_org_runtime_tasks ( + "INSERT INTO agent_org_execution_tasks ( id,org_run_id,activation_generation,subject,description,owner,status,execution_mode, blocked_by_json,created_by_participant_id,source_turn_intent_id, created_at,updated_at @@ -144,7 +144,7 @@ fn archive_fence_cancels_open_work_and_is_request_idempotent() { ) .expect("seed Turn"); conn.execute( - "INSERT INTO agent_org_runtime_inbox ( + "INSERT INTO agent_org_execution_inbox ( recipient_agent_id,recipient_member_id,sender_agent_id,sender_member_id, org_run_id,payload_kind,payload_json,created_at ) VALUES ('worker-agent','worker','coordinator-agent','coordinator',?1, @@ -154,14 +154,14 @@ fn archive_fence_cancels_open_work_and_is_request_idempotent() { .expect("seed Inbox"); let inbox_id = conn.last_insert_rowid(); conn.execute( - "INSERT INTO agent_org_runtime_inbox_materializations ( + "INSERT INTO agent_org_execution_inbox_materializations ( inbox_id,session_id,transcript_message_id,transcript_intent_id,materialized_at ) VALUES (?1,?2,'materialized-message','materialized-intent',?3)", params![inbox_id, member, "2026-08-23T00:00:00Z"], ) .expect("seed Inbox materialization"); conn.execute( - "INSERT INTO agent_org_runtime_plan_revisions ( + "INSERT INTO agent_org_execution_plan_revisions ( plan_revision_id,org_run_id,source_task_id,source_member_id, source_session_id,source_turn_intent_id,root_session_id, revision_number,plan_title,plan_path,plan_content,content_digest,created_at @@ -173,14 +173,14 @@ fn archive_fence_cancels_open_work_and_is_request_idempotent() { ) .expect("seed Plan revision"); conn.execute( - "INSERT INTO agent_org_runtime_plan_decisions ( + "INSERT INTO agent_org_execution_plan_decisions ( approval_id,plan_revision_id,request_id,policy,status,created_at ) VALUES ('approval-open','revision-open','approval-request','user','pending',?1)", params!["2026-08-23T00:00:00Z"], ) .expect("seed Plan decision"); conn.execute( - "INSERT INTO agent_org_runtime_turn_contexts ( + "INSERT INTO agent_org_execution_turn_contexts ( session_id,turn_intent_id,org_run_id,participant_id,turn_kind,task_id, owner_member_id,dispatch_member_id,member_dispatch_sequence, source_kind,source_id,activation_generation,created_at @@ -190,7 +190,7 @@ fn archive_fence_cancels_open_work_and_is_request_idempotent() { ) .expect("seed Turn context"); conn.execute( - "INSERT INTO agent_org_runtime_pause_episodes ( + "INSERT INTO agent_org_execution_pause_episodes ( episode_id,org_run_id,pause_request_id,pause_generation,status, teardown_owner_id,created_at,updated_at ) VALUES ('pause-open',?1,'pause-request',2,'active','pause-owner',?2,?2)", @@ -198,7 +198,7 @@ fn archive_fence_cancels_open_work_and_is_request_idempotent() { ) .expect("seed Pause episode"); conn.execute( - "INSERT INTO agent_org_runtime_pause_handoffs ( + "INSERT INTO agent_org_execution_pause_handoffs ( handoff_id,episode_id,org_run_id,session_id,original_turn_intent_id, turn_kind,participant_id,task_id,original_owner_member_id, original_activation_generation,original_intent_status,drain_status, @@ -212,7 +212,7 @@ fn archive_fence_cancels_open_work_and_is_request_idempotent() { ) .expect("seed queued Pause continuation"); conn.execute( - "INSERT INTO agent_org_runtime_member_interventions ( + "INSERT INTO agent_org_execution_member_interventions ( intervention_receipt_id,org_run_id,member_id,agent_id,session_id, status,source_event_id,entered_at,last_user_activity_at,updated_at ) VALUES ('intervention-open',?1,'worker','worker-agent',?2, @@ -256,14 +256,14 @@ fn archive_fence_cancels_open_work_and_is_request_idempotent() { assert!(wire["teardown"].get("lastError").is_none()); assert_eq!( scalar_string( - "SELECT status FROM agent_org_runtime_runs WHERE id=?1", + "SELECT status FROM agent_org_execution_runs WHERE id=?1", run_id ), "archived" ); assert_eq!( scalar_string( - "SELECT status FROM agent_org_runtime_tasks WHERE org_run_id=?1", + "SELECT status FROM agent_org_execution_tasks WHERE org_run_id=?1", run_id ), "cancelled" @@ -278,8 +278,8 @@ fn archive_fence_cancels_open_work_and_is_request_idempotent() { assert_eq!( scalar_string( "SELECT decision.status - FROM agent_org_runtime_plan_decisions decision - JOIN agent_org_runtime_plan_revisions revision + FROM agent_org_execution_plan_decisions decision + JOIN agent_org_execution_plan_revisions revision ON revision.plan_revision_id=decision.plan_revision_id WHERE revision.org_run_id=?1", run_id @@ -288,7 +288,7 @@ fn archive_fence_cancels_open_work_and_is_request_idempotent() { ); assert_eq!( scalar_string( - "SELECT continuation_status FROM agent_org_runtime_pause_handoffs WHERE org_run_id=?1", + "SELECT continuation_status FROM agent_org_execution_pause_handoffs WHERE org_run_id=?1", run_id ), "skipped" @@ -296,7 +296,7 @@ fn archive_fence_cancels_open_work_and_is_request_idempotent() { let materialization_count: i64 = database::db::get_connection() .expect("sandbox DB") .query_row( - "SELECT COUNT(*) FROM agent_org_runtime_inbox_materializations WHERE inbox_id=?1", + "SELECT COUNT(*) FROM agent_org_execution_inbox_materializations WHERE inbox_id=?1", [inbox_id], |row| row.get(0), ) @@ -323,7 +323,7 @@ fn archive_fence_cancels_open_work_and_is_request_idempotent() { let teardown_count: i64 = database::db::get_connection() .expect("sandbox DB") .query_row( - "SELECT COUNT(*) FROM agent_org_runtime_archive_teardowns WHERE org_run_id=?1", + "SELECT COUNT(*) FROM agent_org_execution_archive_teardowns WHERE org_run_id=?1", [run_id], |row| row.get(0), ) @@ -392,7 +392,7 @@ fn concurrent_different_archive_requests_transition_exactly_once() { assert_eq!( scalar_string( "SELECT CAST(activation_generation AS TEXT) - FROM agent_org_runtime_runs WHERE id=?1", + FROM agent_org_execution_runs WHERE id=?1", run_id ), "2" @@ -431,7 +431,7 @@ fn archive_accepts_only_documented_source_states() { assert!(error.starts_with("team_not_ready:")); assert_eq!( scalar_string( - "SELECT status FROM agent_org_runtime_runs WHERE id=?1", + "SELECT status FROM agent_org_execution_runs WHERE id=?1", "archive-starting-run" ), "starting" @@ -448,7 +448,7 @@ fn archive_rolls_back_the_fence_when_a_cancellation_write_fails() { seed_run(run_id, root, "running", 1); let conn = database::db::get_connection().expect("sandbox DB"); conn.execute( - "INSERT INTO agent_org_runtime_tasks ( + "INSERT INTO agent_org_execution_tasks ( id,org_run_id,activation_generation,subject,description,status,execution_mode,blocked_by_json, created_by_participant_id,source_turn_intent_id,created_at,updated_at ) VALUES ('task-rollback',?1,1,'Open work','','pending','build','[]', @@ -458,7 +458,7 @@ fn archive_rolls_back_the_fence_when_a_cancellation_write_fails() { .expect("seed Task"); conn.execute_batch( "CREATE TRIGGER abort_archive_task_cancel - BEFORE UPDATE OF status ON agent_org_runtime_tasks + BEFORE UPDATE OF status ON agent_org_execution_tasks WHEN NEW.status='cancelled' BEGIN SELECT RAISE(ABORT,'injected Archive cancellation failure'); END;", ) @@ -468,7 +468,7 @@ fn archive_rolls_back_the_fence_when_a_cancellation_write_fails() { assert_archive_failure_rolled_back(run_id, "injected Archive cancellation failure"); assert_eq!( scalar_string( - "SELECT status FROM agent_org_runtime_tasks WHERE org_run_id=?1", + "SELECT status FROM agent_org_execution_tasks WHERE org_run_id=?1", run_id ), "pending" @@ -514,7 +514,7 @@ fn archive_rolls_back_at_every_non_task_transaction_boundary() { } "inbox" => { conn.execute( - "INSERT INTO agent_org_runtime_inbox ( + "INSERT INTO agent_org_execution_inbox ( recipient_agent_id,recipient_member_id,sender_agent_id, sender_member_id,org_run_id,payload_kind,payload_json,created_at ) VALUES ('coordinator-agent','coordinator','worker-agent','worker', @@ -526,7 +526,7 @@ fn archive_rolls_back_at_every_non_task_transaction_boundary() { "approval" => { let task_id = format!("{run_id}-task"); conn.execute( - "INSERT INTO agent_org_runtime_tasks ( + "INSERT INTO agent_org_execution_tasks ( id,org_run_id,activation_generation,subject,description,status,execution_mode, blocked_by_json,created_by_participant_id, source_turn_intent_id,created_at,updated_at @@ -541,7 +541,7 @@ fn archive_rolls_back_at_every_non_task_transaction_boundary() { ) .expect("seed approval source Task"); conn.execute( - "INSERT INTO agent_org_runtime_plan_revisions ( + "INSERT INTO agent_org_execution_plan_revisions ( plan_revision_id,org_run_id,source_task_id,source_member_id, source_session_id,source_turn_intent_id,root_session_id, revision_number,plan_title,plan_path,plan_content, @@ -560,7 +560,7 @@ fn archive_rolls_back_at_every_non_task_transaction_boundary() { ) .expect("seed Plan revision"); conn.execute( - "INSERT INTO agent_org_runtime_plan_decisions ( + "INSERT INTO agent_org_execution_plan_decisions ( approval_id,plan_revision_id,request_id,policy,status,created_at ) VALUES (?1,?2,?3,'user','pending',?4)", params![ @@ -574,7 +574,7 @@ fn archive_rolls_back_at_every_non_task_transaction_boundary() { } "intervention" => { conn.execute( - "INSERT INTO agent_org_runtime_member_interventions ( + "INSERT INTO agent_org_execution_member_interventions ( intervention_receipt_id,org_run_id,member_id,agent_id, session_id,status,source_event_id,entered_at, last_user_activity_at,updated_at @@ -601,7 +601,7 @@ fn archive_rolls_back_at_every_non_task_transaction_boundary() { ) .expect("seed Pause Turn intent"); conn.execute( - "INSERT INTO agent_org_runtime_turn_contexts ( + "INSERT INTO agent_org_execution_turn_contexts ( session_id,turn_intent_id,org_run_id,participant_id, turn_kind,source_kind,source_id,activation_generation,created_at ) VALUES (?1,?2,?3,'coordinator','coordinator','root_turn',?2,1,?4)", @@ -609,7 +609,7 @@ fn archive_rolls_back_at_every_non_task_transaction_boundary() { ) .expect("seed Pause Turn context"); conn.execute( - "INSERT INTO agent_org_runtime_pause_episodes ( + "INSERT INTO agent_org_execution_pause_episodes ( episode_id,org_run_id,pause_request_id,pause_generation,status, teardown_owner_id,created_at,updated_at ) VALUES (?1,?2,?3,2,'active',?4,?5,?5)", @@ -623,7 +623,7 @@ fn archive_rolls_back_at_every_non_task_transaction_boundary() { ) .expect("seed Pause episode"); conn.execute( - "INSERT INTO agent_org_runtime_pause_handoffs ( + "INSERT INTO agent_org_execution_pause_handoffs ( handoff_id,episode_id,org_run_id,session_id, original_turn_intent_id,turn_kind,participant_id, original_activation_generation,original_intent_status, @@ -649,19 +649,19 @@ fn archive_rolls_back_at_every_non_task_transaction_boundary() { let trigger = match boundary { "fence" => format!( "CREATE TRIGGER fault_archive_fence_{boundary} - BEFORE UPDATE OF status ON agent_org_runtime_runs + BEFORE UPDATE OF status ON agent_org_execution_runs WHEN NEW.id='{run_id}' AND NEW.status='archived' BEGIN SELECT RAISE(ABORT,'fault_archive_fence'); END;" ), "episode" => format!( "CREATE TRIGGER fault_archive_episode_{boundary} - BEFORE INSERT ON agent_org_runtime_archive_episodes + BEFORE INSERT ON agent_org_execution_archive_episodes WHEN NEW.org_run_id='{run_id}' BEGIN SELECT RAISE(ABORT,'fault_archive_episode'); END;" ), "teardown" => format!( "CREATE TRIGGER fault_archive_teardown_{boundary} - BEFORE INSERT ON agent_org_runtime_archive_teardowns + BEFORE INSERT ON agent_org_execution_archive_teardowns WHEN NEW.org_run_id='{run_id}' BEGIN SELECT RAISE(ABORT,'fault_archive_teardown'); END;" ), @@ -673,34 +673,34 @@ fn archive_rolls_back_at_every_non_task_transaction_boundary() { ), "inbox" => format!( "CREATE TRIGGER fault_archive_inbox_{boundary} - BEFORE INSERT ON agent_org_runtime_inbox_delivery_resolutions + BEFORE INSERT ON agent_org_execution_inbox_delivery_resolutions WHEN NEW.org_run_id='{run_id}' BEGIN SELECT RAISE(ABORT,'fault_archive_inbox'); END;" ), "approval" => format!( "CREATE TRIGGER fault_archive_approval_{boundary} - BEFORE UPDATE OF status ON agent_org_runtime_plan_decisions + BEFORE UPDATE OF status ON agent_org_execution_plan_decisions WHEN NEW.plan_revision_id IN ( - SELECT plan_revision_id FROM agent_org_runtime_plan_revisions + SELECT plan_revision_id FROM agent_org_execution_plan_revisions WHERE org_run_id='{run_id}' ) AND NEW.status='cancelled' BEGIN SELECT RAISE(ABORT,'fault_archive_approval'); END;" ), "intervention" => format!( "CREATE TRIGGER fault_archive_intervention_{boundary} - BEFORE UPDATE OF cleared_at ON agent_org_runtime_member_interventions + BEFORE UPDATE OF cleared_at ON agent_org_execution_member_interventions WHEN NEW.org_run_id='{run_id}' AND NEW.cleared_at IS NOT NULL BEGIN SELECT RAISE(ABORT,'fault_archive_intervention'); END;" ), "pause_continuation" => format!( "CREATE TRIGGER fault_archive_pause_{boundary} - BEFORE UPDATE OF continuation_status ON agent_org_runtime_pause_handoffs + BEFORE UPDATE OF continuation_status ON agent_org_execution_pause_handoffs WHEN NEW.org_run_id='{run_id}' AND NEW.continuation_status='skipped' BEGIN SELECT RAISE(ABORT,'fault_archive_pause'); END;" ), "receipt_finalize" => format!( "CREATE TRIGGER fault_archive_receipt_{boundary} - BEFORE UPDATE OF task_cancel_count ON agent_org_runtime_archive_episodes + BEFORE UPDATE OF task_cancel_count ON agent_org_execution_archive_episodes WHEN NEW.org_run_id='{run_id}' BEGIN SELECT RAISE(ABORT,'fault_archive_receipt'); END;" ), @@ -733,7 +733,7 @@ fn archive_rejects_generation_overflow_without_mutation() { assert!(error.contains("generation overflow")); assert_eq!( scalar_string( - "SELECT status FROM agent_org_runtime_runs WHERE id=?1", + "SELECT status FROM agent_org_execution_runs WHERE id=?1", "archive-overflow-run" ), "running" diff --git a/src-tauri/crates/agent-core/src/core/coordination/agent_org_final_summary/context.rs b/src-tauri/crates/agent-core/src/core/coordination/agent_org_final_summary/context.rs index 03396497e4..8efb5c23ad 100644 --- a/src-tauri/crates/agent-core/src/core/coordination/agent_org_final_summary/context.rs +++ b/src-tauri/crates/agent-core/src/core/coordination/agent_org_final_summary/context.rs @@ -13,8 +13,8 @@ pub(crate) fn summary_context_for_turn( let source: Option<(String, String, String)> = conn .query_row( "SELECT receipt.org_run_id,receipt.certificate_id,receipt.evidence_digest - FROM agent_org_runtime_final_summary_receipts receipt - JOIN agent_org_runtime_run_completion_certificates certificate + FROM agent_org_execution_final_summary_receipts receipt + JOIN agent_org_execution_run_completion_certificates certificate ON certificate.id=receipt.certificate_id WHERE receipt.coordinator_session_id=?1 AND receipt.turn_intent_id=?2 AND receipt.status IN ('running','persisting')", diff --git a/src-tauri/crates/agent-core/src/core/coordination/agent_org_final_summary/mod.rs b/src-tauri/crates/agent-core/src/core/coordination/agent_org_final_summary/mod.rs index 090cfd142c..ddafe33f8f 100644 --- a/src-tauri/crates/agent-core/src/core/coordination/agent_org_final_summary/mod.rs +++ b/src-tauri/crates/agent-core/src/core/coordination/agent_org_final_summary/mod.rs @@ -25,7 +25,7 @@ pub(crate) fn is_finalizing_with_connection( ) -> Result { conn.query_row( "SELECT EXISTS( - SELECT 1 FROM agent_org_runtime_final_summary_receipts + SELECT 1 FROM agent_org_execution_final_summary_receipts WHERE org_run_id=?1 AND status IN ('pending','running','persisting') )", [org_run_id], diff --git a/src-tauri/crates/agent-core/src/core/coordination/agent_org_final_summary/schema.rs b/src-tauri/crates/agent-core/src/core/coordination/agent_org_final_summary/schema.rs index a85e1fda85..1ce18ec096 100644 --- a/src-tauri/crates/agent-core/src/core/coordination/agent_org_final_summary/schema.rs +++ b/src-tauri/crates/agent-core/src/core/coordination/agent_org_final_summary/schema.rs @@ -2,7 +2,7 @@ use rusqlite::Connection; pub(super) fn create_schema(conn: &Connection) -> rusqlite::Result<()> { conn.execute_batch( - "CREATE TABLE IF NOT EXISTS agent_org_runtime_final_summary_receipts ( + "CREATE TABLE IF NOT EXISTS agent_org_execution_final_summary_receipts ( receipt_id TEXT PRIMARY KEY, org_run_id TEXT NOT NULL, activation_generation INTEGER NOT NULL CHECK(activation_generation >= 1), @@ -23,9 +23,9 @@ pub(super) fn create_schema(conn: &Connection) -> rusqlite::Result<()> { updated_at TEXT NOT NULL, UNIQUE(certificate_id,attempt), UNIQUE(certificate_id,retry_request_id), - FOREIGN KEY(org_run_id) REFERENCES agent_org_runtime_runs(id) ON DELETE CASCADE, + FOREIGN KEY(org_run_id) REFERENCES agent_org_execution_runs(id) ON DELETE CASCADE, FOREIGN KEY(certificate_id) - REFERENCES agent_org_runtime_run_completion_certificates(id) + REFERENCES agent_org_execution_run_completion_certificates(id) ON DELETE CASCADE, CHECK((status='pending' AND turn_intent_id IS NULL AND started_at IS NULL) OR (status IN ('running','persisting','persisted','failed') @@ -34,19 +34,19 @@ pub(super) fn create_schema(conn: &Connection) -> rusqlite::Result<()> { CHECK((status='persisted')=(event_id IS NOT NULL)), CHECK((status='failed')=(typed_error IS NOT NULL)) ); - CREATE UNIQUE INDEX IF NOT EXISTS idx_agent_org_final_summary_one_active - ON agent_org_runtime_final_summary_receipts(certificate_id) + CREATE UNIQUE INDEX IF NOT EXISTS idx_agent_org_execution_final_summary_one_active + ON agent_org_execution_final_summary_receipts(certificate_id) WHERE status IN ('pending','running','persisting'); - CREATE INDEX IF NOT EXISTS idx_agent_org_final_summary_run_current - ON agent_org_runtime_final_summary_receipts( + CREATE INDEX IF NOT EXISTS idx_agent_org_execution_final_summary_run_current + ON agent_org_execution_final_summary_receipts( org_run_id,activation_generation,attempt DESC ); - CREATE UNIQUE INDEX IF NOT EXISTS idx_agent_org_final_summary_turn - ON agent_org_runtime_final_summary_receipts( + CREATE UNIQUE INDEX IF NOT EXISTS idx_agent_org_execution_final_summary_turn + ON agent_org_execution_final_summary_receipts( coordinator_session_id,turn_intent_id ) WHERE turn_intent_id IS NOT NULL; - CREATE INDEX IF NOT EXISTS idx_agent_org_final_summary_public_timeline - ON agent_org_runtime_final_summary_receipts(org_run_id,terminal_at,receipt_id) + CREATE INDEX IF NOT EXISTS idx_agent_org_execution_final_summary_public_timeline + ON agent_org_execution_final_summary_receipts(org_run_id,terminal_at,receipt_id) WHERE status IN ('persisted','failed');", ) } diff --git a/src-tauri/crates/agent-core/src/core/coordination/agent_org_final_summary/store.rs b/src-tauri/crates/agent-core/src/core/coordination/agent_org_final_summary/store.rs index 9b6bd60081..95ac9ac6de 100644 --- a/src-tauri/crates/agent-core/src/core/coordination/agent_org_final_summary/store.rs +++ b/src-tauri/crates/agent-core/src/core/coordination/agent_org_final_summary/store.rs @@ -78,7 +78,7 @@ pub(crate) fn create_initial_for_certificate_in_tx( let receipt_id = stable_receipt_id(&certificate.id, 1); let now = chrono::Utc::now().to_rfc3339(); tx.execute( - "INSERT INTO agent_org_runtime_final_summary_receipts ( + "INSERT INTO agent_org_execution_final_summary_receipts ( receipt_id,org_run_id,activation_generation,certificate_id, evidence_digest,attempt,status,coordinator_session_id, turn_intent_id,retry_request_id,started_at,terminal_at,event_id, @@ -135,7 +135,7 @@ pub(crate) fn claim_pending_for_coordinator_turn_in_tx( let pending: Option<(String, String)> = tx .query_row( "SELECT receipt_id,coordinator_session_id - FROM agent_org_runtime_final_summary_receipts + FROM agent_org_execution_final_summary_receipts WHERE org_run_id=?1 AND status='pending' ORDER BY attempt DESC LIMIT 1", [org_run_id], @@ -152,7 +152,7 @@ pub(crate) fn claim_pending_for_coordinator_turn_in_tx( let now = chrono::Utc::now().to_rfc3339(); let updated = tx .execute( - "UPDATE agent_org_runtime_final_summary_receipts + "UPDATE agent_org_execution_final_summary_receipts SET status='running',turn_intent_id=?2,started_at=?3,updated_at=?3 WHERE receipt_id=?1 AND status='pending'", params![&receipt_id, turn_intent_id, &now], @@ -163,7 +163,7 @@ pub(crate) fn claim_pending_for_coordinator_turn_in_tx( } let resolved_trigger = tx .execute( - "UPDATE agent_org_runtime_formal_trigger_receipts + "UPDATE agent_org_execution_formal_trigger_receipts SET status='resolved',doorbell_status='suppressed',resolved_at=?2,updated_at=?2 WHERE org_run_id=?1 AND trigger_kind='final_summary' AND trigger_id=?3 AND status='pending'", @@ -183,7 +183,7 @@ pub(crate) fn is_summary_turn_with_connection( ) -> Result { conn.query_row( "SELECT EXISTS( - SELECT 1 FROM agent_org_runtime_final_summary_receipts + SELECT 1 FROM agent_org_execution_final_summary_receipts WHERE coordinator_session_id=?1 AND turn_intent_id=?2 AND status IN ('running','persisting') )", @@ -200,7 +200,7 @@ pub(crate) fn has_summary_receipt_for_turn_with_connection( ) -> Result { conn.query_row( "SELECT EXISTS( - SELECT 1 FROM agent_org_runtime_final_summary_receipts + SELECT 1 FROM agent_org_execution_final_summary_receipts WHERE coordinator_session_id=?1 AND turn_intent_id=?2 )", params![session_id, turn_intent_id], @@ -221,7 +221,7 @@ pub(crate) fn status_for_turn( let conn = database::db::get_connection().map_err(|error| error.to_string())?; let raw: Option = conn .query_row( - "SELECT status FROM agent_org_runtime_final_summary_receipts + "SELECT status FROM agent_org_execution_final_summary_receipts WHERE coordinator_session_id=?1 AND turn_intent_id=?2", params![session_id, turn_intent_id], |row| row.get(0), @@ -240,7 +240,7 @@ pub(crate) fn certificate_for_turn( let certificate_id: Option = conn .query_row( "SELECT certificate_id - FROM agent_org_runtime_final_summary_receipts + FROM agent_org_execution_final_summary_receipts WHERE coordinator_session_id=?1 AND turn_intent_id=?2", params![session_id, turn_intent_id], |row| row.get(0), @@ -266,7 +266,7 @@ pub(crate) fn stable_event_id_for_turn( let receipt_id: Option = conn .query_row( "SELECT receipt_id - FROM agent_org_runtime_final_summary_receipts + FROM agent_org_execution_final_summary_receipts WHERE coordinator_session_id=?1 AND turn_intent_id=?2 AND status IN ('running','persisting')", params![session_id, turn_intent_id], @@ -354,7 +354,7 @@ fn settle_attempt_in_tx( typed_error: &str, ) -> Result { let receipt: Option = conn.query_row( - "SELECT receipt_id FROM agent_org_runtime_final_summary_receipts + "SELECT receipt_id FROM agent_org_execution_final_summary_receipts WHERE coordinator_session_id=?1 AND turn_intent_id=?2 AND status IN ('running','persisting')", params![session_id, turn_intent_id], |row| row.get(0)) .optional().map_err(|error| error.to_string())?; @@ -374,7 +374,7 @@ fn settle_attempt_in_tx( let now = chrono::Utc::now().to_rfc3339(); let changed = conn .execute( - "UPDATE agent_org_runtime_final_summary_receipts + "UPDATE agent_org_execution_final_summary_receipts SET status=?2,event_id=?3,typed_error=?4,terminal_at=?5,updated_at=?5 WHERE receipt_id=?1 AND status IN ('running','persisting')", params![ @@ -403,7 +403,7 @@ fn update_turn_status( let terminal = matches!(next, "persisted" | "failed"); let changed = conn .execute( - "UPDATE agent_org_runtime_final_summary_receipts + "UPDATE agent_org_execution_final_summary_receipts SET status=?4,event_id=?5,typed_error=?6, terminal_at=CASE WHEN ?7 THEN ?8 ELSE terminal_at END, updated_at=?8 @@ -432,7 +432,7 @@ pub(crate) fn active_for_run_with_connection( conn.query_row( &format!( "SELECT {RECEIPT_COLUMNS} - FROM agent_org_runtime_final_summary_receipts + FROM agent_org_execution_final_summary_receipts WHERE org_run_id=?1 AND activation_generation=?2 ORDER BY attempt DESC LIMIT 1" ), @@ -460,7 +460,7 @@ pub(crate) fn retry_failed( .query_row( &format!( "SELECT {RECEIPT_COLUMNS} - FROM agent_org_runtime_final_summary_receipts + FROM agent_org_execution_final_summary_receipts WHERE certificate_id=?1 AND retry_request_id=?2" ), params![certificate_id, request_id], @@ -485,7 +485,7 @@ pub(crate) fn retry_failed( } let current_attempt: i64 = tx .query_row( - "SELECT MAX(attempt) FROM agent_org_runtime_final_summary_receipts + "SELECT MAX(attempt) FROM agent_org_execution_final_summary_receipts WHERE certificate_id=?1", [certificate_id], |row| row.get(0), @@ -513,7 +513,7 @@ pub(crate) fn retry_failed( let now = chrono::Utc::now().to_rfc3339(); let reactivated = tx .execute( - "UPDATE agent_org_runtime_runs + "UPDATE agent_org_execution_runs SET status='running',idled_at=NULL,updated_at=?3 WHERE id=?1 AND status='idle' AND activation_generation=?2", params![ @@ -527,7 +527,7 @@ pub(crate) fn retry_failed( return Err("final_summary_retry_requires_idle_current_generation".to_string()); } tx.execute( - "INSERT INTO agent_org_runtime_final_summary_receipts ( + "INSERT INTO agent_org_execution_final_summary_receipts ( receipt_id,org_run_id,activation_generation,certificate_id, evidence_digest,attempt,status,coordinator_session_id, turn_intent_id,retry_request_id,started_at,terminal_at,event_id, @@ -577,7 +577,7 @@ pub(crate) fn reconcile_after_restart(conn: &Connection) -> Result Result Result(0), @@ -101,7 +101,7 @@ fn retry_rejects_changed_certified_evidence_without_reactivating() { .unwrap(); output["content"] = "Evidence changed after certification".into(); conn.execute( - "UPDATE agent_org_runtime_tasks SET output_json=?2 + "UPDATE agent_org_execution_tasks SET output_json=?2 WHERE org_run_id=?1 AND id='report-task'", params![&fixture.run_id, output.to_string()], ) diff --git a/src-tauri/crates/agent-core/src/core/coordination/agent_org_final_summary/tests/scale_tests.rs b/src-tauri/crates/agent-core/src/core/coordination/agent_org_final_summary/tests/scale_tests.rs index e7df233662..1298b7c9df 100644 --- a/src-tauri/crates/agent-core/src/core/coordination/agent_org_final_summary/tests/scale_tests.rs +++ b/src-tauri/crates/agent-core/src/core/coordination/agent_org_final_summary/tests/scale_tests.rs @@ -21,7 +21,7 @@ fn thousand_task_inbox_and_artifact_rows_do_not_expand_summary_context() { "producedAt": &now, }); tx.execute( - "INSERT INTO agent_org_runtime_tasks( + "INSERT INTO agent_org_execution_tasks( id,org_run_id,activation_generation,subject,description,owner,status, execution_mode,blocked_by_json,output_json,created_by_participant_id, source_turn_intent_id,created_at,updated_at @@ -38,7 +38,7 @@ fn thousand_task_inbox_and_artifact_rows_do_not_expand_summary_context() { ) .unwrap(); tx.execute( - "INSERT INTO agent_org_runtime_inbox( + "INSERT INTO agent_org_execution_inbox( recipient_agent_id,recipient_member_id,sender_agent_id,sender_member_id, org_run_id,payload_kind,payload_json,created_at,display_text ) VALUES ('coordinator-agent','coordinator','system','worker',?1, diff --git a/src-tauri/crates/agent-core/src/core/coordination/agent_org_final_summary/tests/state_tests.rs b/src-tauri/crates/agent-core/src/core/coordination/agent_org_final_summary/tests/state_tests.rs index 1adf67048f..5a0b90722a 100644 --- a/src-tauri/crates/agent-core/src/core/coordination/agent_org_final_summary/tests/state_tests.rs +++ b/src-tauri/crates/agent-core/src/core/coordination/agent_org_final_summary/tests/state_tests.rs @@ -59,7 +59,7 @@ fn summary_claim_requires_its_exact_formal_trigger_in_the_same_transaction() { let mut conn = database::db::get_connection().expect("summary database"); let tx = conn.transaction().expect("summary claim transaction"); tx.execute( - "DELETE FROM agent_org_runtime_formal_trigger_receipts + "DELETE FROM agent_org_execution_formal_trigger_receipts WHERE org_run_id=?1 AND trigger_kind='final_summary'", [&fixture.run_id], ) diff --git a/src-tauri/crates/agent-core/src/core/coordination/agent_org_finality.rs b/src-tauri/crates/agent-core/src/core/coordination/agent_org_finality.rs index ad3c4e5e89..9ed5fe6af6 100644 --- a/src-tauri/crates/agent-core/src/core/coordination/agent_org_finality.rs +++ b/src-tauri/crates/agent-core/src/core/coordination/agent_org_finality.rs @@ -147,7 +147,7 @@ pub struct ScopeRemovalReceipt { pub(crate) fn create_schema(conn: &Connection) -> rusqlite::Result<()> { conn.execute_batch( - "CREATE TABLE IF NOT EXISTS agent_org_task_execution_leases ( + "CREATE TABLE IF NOT EXISTS agent_org_execution_task_execution_leases ( lease_id TEXT PRIMARY KEY, org_run_id TEXT NOT NULL, work_episode_id TEXT NOT NULL, @@ -172,24 +172,24 @@ pub(crate) fn create_schema(conn: &Connection) -> rusqlite::Result<()> { UNIQUE(org_run_id, work_episode_id, task_id, activation_generation, execution_epoch), UNIQUE(continuation_receipt_id), FOREIGN KEY(org_run_id, task_id) - REFERENCES agent_org_runtime_tasks(org_run_id, id) ON DELETE CASCADE, + REFERENCES agent_org_execution_tasks(org_run_id, id) ON DELETE CASCADE, FOREIGN KEY(work_episode_id) - REFERENCES agent_org_runtime_work_episodes(id) ON DELETE CASCADE, + REFERENCES agent_org_execution_work_episodes(id) ON DELETE CASCADE, FOREIGN KEY(source_inbox_id) - REFERENCES agent_org_runtime_inbox(id) ON DELETE SET NULL, + REFERENCES agent_org_execution_inbox(id) ON DELETE SET NULL, FOREIGN KEY(prior_lease_id) - REFERENCES agent_org_task_execution_leases(lease_id) + REFERENCES agent_org_execution_task_execution_leases(lease_id) ); - CREATE UNIQUE INDEX IF NOT EXISTS idx_agent_org_task_execution_one_live - ON agent_org_task_execution_leases( + CREATE UNIQUE INDEX IF NOT EXISTS idx_agent_org_execution_task_execution_one_live + ON agent_org_execution_task_execution_leases( org_run_id,work_episode_id,task_id,activation_generation ) WHERE state='active'; - CREATE INDEX IF NOT EXISTS idx_agent_org_task_execution_turn - ON agent_org_task_execution_leases(session_id,turn_intent_id,state); - CREATE INDEX IF NOT EXISTS idx_agent_org_task_execution_task - ON agent_org_task_execution_leases(org_run_id,task_id,execution_epoch DESC); + CREATE INDEX IF NOT EXISTS idx_agent_org_execution_task_execution_turn + ON agent_org_execution_task_execution_leases(session_id,turn_intent_id,state); + CREATE INDEX IF NOT EXISTS idx_agent_org_execution_task_execution_task + ON agent_org_execution_task_execution_leases(org_run_id,task_id,execution_epoch DESC); - CREATE TABLE IF NOT EXISTS agent_org_task_execution_reconciliations ( + CREATE TABLE IF NOT EXISTS agent_org_execution_task_execution_reconciliations ( context_id INTEGER PRIMARY KEY, org_run_id TEXT NOT NULL, task_id TEXT NOT NULL, @@ -201,14 +201,14 @@ pub(crate) fn create_schema(conn: &Connection) -> rusqlite::Result<()> { reconciled_at TEXT NOT NULL, UNIQUE(session_id,turn_intent_id), FOREIGN KEY(context_id) - REFERENCES agent_org_runtime_turn_contexts(context_id) ON DELETE CASCADE + REFERENCES agent_org_execution_turn_contexts(context_id) ON DELETE CASCADE ); - CREATE INDEX IF NOT EXISTS idx_agent_org_task_execution_reconciliation_task - ON agent_org_task_execution_reconciliations( + CREATE INDEX IF NOT EXISTS idx_agent_org_execution_task_execution_reconciliation_task + ON agent_org_execution_task_execution_reconciliations( org_run_id,task_id,activation_generation ); - CREATE TABLE IF NOT EXISTS agent_org_scope_removal_receipts ( + CREATE TABLE IF NOT EXISTS agent_org_execution_scope_removal_receipts ( receipt_id TEXT PRIMARY KEY, org_run_id TEXT NOT NULL, work_episode_id TEXT NOT NULL, @@ -224,14 +224,14 @@ pub(crate) fn create_schema(conn: &Connection) -> rusqlite::Result<()> { UNIQUE(org_run_id, request_id), UNIQUE(root_user_event_id), FOREIGN KEY(org_run_id, target_task_id) - REFERENCES agent_org_runtime_tasks(org_run_id, id) ON DELETE CASCADE, + REFERENCES agent_org_execution_tasks(org_run_id, id) ON DELETE CASCADE, FOREIGN KEY(work_episode_id) - REFERENCES agent_org_runtime_work_episodes(id) ON DELETE CASCADE + REFERENCES agent_org_execution_work_episodes(id) ON DELETE CASCADE ); - CREATE INDEX IF NOT EXISTS idx_agent_org_scope_removal_episode - ON agent_org_scope_removal_receipts(org_run_id,work_episode_id,target_task_id); + CREATE INDEX IF NOT EXISTS idx_agent_org_execution_scope_removal_episode + ON agent_org_execution_scope_removal_receipts(org_run_id,work_episode_id,target_task_id); - CREATE TABLE IF NOT EXISTS agent_org_scope_resolution_receipts ( + CREATE TABLE IF NOT EXISTS agent_org_execution_scope_resolution_receipts ( resolution_id TEXT PRIMARY KEY, root_receipt_id TEXT NOT NULL, org_run_id TEXT NOT NULL, @@ -245,20 +245,20 @@ pub(crate) fn create_schema(conn: &Connection) -> rusqlite::Result<()> { created_at TEXT NOT NULL, UNIQUE(root_receipt_id,task_id,resolution_kind), FOREIGN KEY(root_receipt_id) - REFERENCES agent_org_scope_removal_receipts(receipt_id) ON DELETE CASCADE, + REFERENCES agent_org_execution_scope_removal_receipts(receipt_id) ON DELETE CASCADE, FOREIGN KEY(org_run_id,task_id) - REFERENCES agent_org_runtime_tasks(org_run_id,id) ON DELETE CASCADE, + REFERENCES agent_org_execution_tasks(org_run_id,id) ON DELETE CASCADE, FOREIGN KEY(work_episode_id) - REFERENCES agent_org_runtime_work_episodes(id) ON DELETE CASCADE, + REFERENCES agent_org_execution_work_episodes(id) ON DELETE CASCADE, CHECK( (resolution_kind='dependency_replaced' AND replacement_task_id IS NOT NULL) OR (resolution_kind<>'dependency_replaced' AND replacement_task_id IS NULL) ) ); - CREATE INDEX IF NOT EXISTS idx_agent_org_scope_resolution_episode - ON agent_org_scope_resolution_receipts(org_run_id,work_episode_id,task_id); + CREATE INDEX IF NOT EXISTS idx_agent_org_execution_scope_resolution_episode + ON agent_org_execution_scope_resolution_receipts(org_run_id,work_episode_id,task_id); - CREATE TABLE IF NOT EXISTS agent_org_coordinator_completion_rechecks ( + CREATE TABLE IF NOT EXISTS agent_org_execution_coordinator_completion_rechecks ( org_run_id TEXT NOT NULL, source_session_id TEXT NOT NULL, source_turn_intent_id TEXT NOT NULL, @@ -269,13 +269,13 @@ pub(crate) fn create_schema(conn: &Connection) -> rusqlite::Result<()> { created_at TEXT NOT NULL, updated_at TEXT NOT NULL, PRIMARY KEY(org_run_id,source_session_id,source_turn_intent_id), - FOREIGN KEY(inbox_id) REFERENCES agent_org_runtime_inbox(id) ON DELETE SET NULL + FOREIGN KEY(inbox_id) REFERENCES agent_org_execution_inbox(id) ON DELETE SET NULL ); - CREATE UNIQUE INDEX IF NOT EXISTS idx_agent_org_completion_recheck_inbox - ON agent_org_coordinator_completion_rechecks(inbox_id) + CREATE UNIQUE INDEX IF NOT EXISTS idx_agent_org_execution_completion_recheck_inbox + ON agent_org_execution_coordinator_completion_rechecks(inbox_id) WHERE inbox_id IS NOT NULL; - CREATE INDEX IF NOT EXISTS idx_agent_org_completion_recheck_pending - ON agent_org_coordinator_completion_rechecks(org_run_id,status,work_revision);", + CREATE INDEX IF NOT EXISTS idx_agent_org_execution_completion_recheck_pending + ON agent_org_execution_coordinator_completion_rechecks(org_run_id,status,work_revision);", ) } diff --git a/src-tauri/crates/agent-core/src/core/coordination/agent_org_finality/coordinator_recheck.rs b/src-tauri/crates/agent-core/src/core/coordination/agent_org_finality/coordinator_recheck.rs index ce6bb19100..2def448c47 100644 --- a/src-tauri/crates/agent-core/src/core/coordination/agent_org_finality/coordinator_recheck.rs +++ b/src-tauri/crates/agent-core/src/core/coordination/agent_org_finality/coordinator_recheck.rs @@ -23,8 +23,8 @@ pub(crate) fn record_task_mutation_in_tx( let source_session_id: Option = conn .query_row( "SELECT context.session_id - FROM agent_org_runtime_turn_contexts context - JOIN agent_org_runtime_runs run + FROM agent_org_execution_turn_contexts context + JOIN agent_org_execution_runs run ON run.id=context.org_run_id AND run.root_session_id=context.session_id WHERE context.org_run_id=?1 @@ -43,7 +43,7 @@ pub(crate) fn record_task_mutation_in_tx( }; let updated = conn .execute( - "UPDATE agent_org_runtime_turn_contexts + "UPDATE agent_org_execution_turn_contexts SET coordinator_work_revision=?4 WHERE org_run_id=?1 AND session_id=?2 AND turn_intent_id=?3 AND turn_kind='coordinator' @@ -56,7 +56,7 @@ pub(crate) fn record_task_mutation_in_tx( } let now = chrono::Utc::now().to_rfc3339(); conn.execute( - "INSERT INTO agent_org_coordinator_completion_rechecks ( + "INSERT INTO agent_org_execution_coordinator_completion_rechecks ( org_run_id,source_session_id,source_turn_intent_id, activation_generation,work_revision,status,created_at,updated_at ) VALUES (?1,?2,?3,?4,?5,'pending',?6,?6) @@ -64,9 +64,9 @@ pub(crate) fn record_task_mutation_in_tx( work_revision=excluded.work_revision, activation_generation=excluded.activation_generation, status=CASE - WHEN agent_org_coordinator_completion_rechecks.status='resolved' + WHEN agent_org_execution_coordinator_completion_rechecks.status='resolved' THEN 'pending' - ELSE agent_org_coordinator_completion_rechecks.status + ELSE agent_org_execution_coordinator_completion_rechecks.status END, updated_at=excluded.updated_at", params![ @@ -90,7 +90,7 @@ pub(crate) fn final_coordinator_revision_for_turn( let conn = database::db::get_connection().map_err(|error| error.to_string())?; conn.query_row( "SELECT org_run_id,coordinator_work_revision - FROM agent_org_runtime_turn_contexts + FROM agent_org_execution_turn_contexts WHERE session_id=?1 AND turn_intent_id=?2 AND turn_kind='coordinator' AND source_kind IN ('root_turn','group_root') @@ -136,7 +136,7 @@ fn terminal_turn_matches_status( conn.query_row( "SELECT EXISTS( SELECT 1 FROM session_turn_intents intent - JOIN agent_org_runtime_runs run ON run.id=?3 + JOIN agent_org_execution_runs run ON run.id=?3 WHERE intent.session_id=?1 AND intent.turn_intent_id=?2 AND (intent.status='running' OR intent.status=?5) AND (?4 IS NULL OR run.activation_generation=?4) @@ -228,7 +228,7 @@ pub(crate) fn finalize_turn_in_tx( &context.org_run_id, )? { conn.execute( - "UPDATE agent_org_coordinator_completion_rechecks SET status='resolved',updated_at=?3 + "UPDATE agent_org_execution_coordinator_completion_rechecks SET status='resolved',updated_at=?3 WHERE source_session_id=?1 AND source_turn_intent_id=?2 AND status='pending'", params![session_id, turn_intent_id, chrono::Utc::now().to_rfc3339()], ) @@ -247,9 +247,9 @@ pub(super) fn materialize_coordinator_recheck_in_tx( let pending: Option<(String, i64, i64)> = conn .query_row( "SELECT recheck.org_run_id,recheck.activation_generation,recheck.work_revision - FROM agent_org_coordinator_completion_rechecks recheck - JOIN agent_org_runtime_runs run ON run.id=recheck.org_run_id - JOIN agent_org_runtime_work_episodes episode + FROM agent_org_execution_coordinator_completion_rechecks recheck + JOIN agent_org_execution_runs run ON run.id=recheck.org_run_id + JOIN agent_org_execution_work_episodes episode ON episode.org_run_id=recheck.org_run_id AND episode.status='active' WHERE recheck.source_session_id=?1 AND recheck.source_turn_intent_id=?2 @@ -267,7 +267,7 @@ pub(super) fn materialize_coordinator_recheck_in_tx( let coordinator_agent_id: String = conn .query_row( "SELECT coordinator_agent_id - FROM agent_org_runtime_runs WHERE id=?1", + FROM agent_org_execution_runs WHERE id=?1", [&org_run_id], |row| row.get(0), ) @@ -310,7 +310,7 @@ pub(super) fn materialize_coordinator_recheck_in_tx( let now = chrono::Utc::now().to_rfc3339(); let updated = conn .execute( - "UPDATE agent_org_coordinator_completion_rechecks + "UPDATE agent_org_execution_coordinator_completion_rechecks SET status='materialized',inbox_id=?4,updated_at=?5 WHERE org_run_id=?1 AND source_session_id=?2 AND source_turn_intent_id=?3 AND status='pending'", diff --git a/src-tauri/crates/agent-core/src/core/coordination/agent_org_finality/execution_authority.rs b/src-tauri/crates/agent-core/src/core/coordination/agent_org_finality/execution_authority.rs index 3e7c92ac13..528e1a0fb4 100644 --- a/src-tauri/crates/agent-core/src/core/coordination/agent_org_finality/execution_authority.rs +++ b/src-tauri/crates/agent-core/src/core/coordination/agent_org_finality/execution_authority.rs @@ -36,7 +36,7 @@ pub(crate) fn claim_task_execution_in_tx( })?; let episode_id: String = conn .query_row( - "SELECT work_episode_id FROM agent_org_runtime_work_episode_tasks + "SELECT work_episode_id FROM agent_org_execution_work_episode_tasks WHERE org_run_id=?1 AND task_id=?2", params![&context.org_run_id, task_id], |row| row.get(0), @@ -53,7 +53,7 @@ pub(crate) fn claim_task_execution_in_tx( .query_row( "SELECT lease.lease_id,lease.session_id,lease.turn_intent_id, COALESCE(intent.status,'missing') - FROM agent_org_task_execution_leases lease + FROM agent_org_execution_task_execution_leases lease LEFT JOIN session_turn_intents intent ON intent.session_id=lease.session_id AND intent.turn_intent_id=lease.turn_intent_id @@ -84,7 +84,7 @@ pub(crate) fn claim_task_execution_in_tx( ) { let now = chrono::Utc::now().to_rfc3339(); conn.execute( - "UPDATE agent_org_task_execution_leases + "UPDATE agent_org_execution_task_execution_leases SET state='released',terminal_reason_code='terminal_intent_reconciled',terminal_at=?2 WHERE lease_id=?1 AND state='active'", params![lease_id, now], @@ -109,7 +109,7 @@ pub(crate) fn claim_task_execution_in_tx( let prior: Option<(String, i64)> = conn .query_row( "SELECT lease_id,execution_epoch - FROM agent_org_task_execution_leases + FROM agent_org_execution_task_execution_leases WHERE org_run_id=?1 AND work_episode_id=?2 AND task_id=?3 ORDER BY execution_epoch DESC LIMIT 1", params![&context.org_run_id, &episode_id, task_id], @@ -135,7 +135,7 @@ pub(crate) fn claim_task_execution_in_tx( let lease_id = format!("task-execution-{}", uuid::Uuid::new_v4()); let now = chrono::Utc::now().to_rfc3339(); conn.execute( - "INSERT INTO agent_org_task_execution_leases ( + "INSERT INTO agent_org_execution_task_execution_leases ( lease_id,org_run_id,work_episode_id,task_id,activation_generation, execution_epoch,owner_member_id,session_id,turn_intent_id,source_kind, continuation_receipt_id,source_inbox_id,prior_lease_id,state,created_at @@ -189,7 +189,7 @@ pub(crate) fn release_turn_lease_in_tx( ) -> Result { let now = chrono::Utc::now().to_rfc3339(); conn.execute( - "UPDATE agent_org_task_execution_leases + "UPDATE agent_org_execution_task_execution_leases SET state=?3,terminal_reason_code=?4,terminal_at=?5 WHERE session_id=?1 AND turn_intent_id=?2 AND state='active'", params![session_id, turn_intent_id, state, reason_code, now], @@ -206,7 +206,7 @@ pub(crate) fn release_task_leases_in_tx( ) -> Result { let now = chrono::Utc::now().to_rfc3339(); conn.execute( - "UPDATE agent_org_task_execution_leases + "UPDATE agent_org_execution_task_execution_leases SET state=?3,terminal_reason_code=?4,terminal_at=?5 WHERE org_run_id=?1 AND task_id=?2 AND state='active'", params![org_run_id, task_id, state, reason_code, now], @@ -222,7 +222,7 @@ pub(crate) fn freeze_run_generation_leases_in_tx( ) -> Result { let now = chrono::Utc::now().to_rfc3339(); conn.execute( - "UPDATE agent_org_task_execution_leases + "UPDATE agent_org_execution_task_execution_leases SET state='frozen',terminal_reason_code=?3,terminal_at=?4 WHERE org_run_id=?1 AND activation_generation=?2 AND state='active'", params![org_run_id, activation_generation, reason_code, now], diff --git a/src-tauri/crates/agent-core/src/core/coordination/agent_org_finality/restart_reconciliation.rs b/src-tauri/crates/agent-core/src/core/coordination/agent_org_finality/restart_reconciliation.rs index d732a674d1..6deedd8a37 100644 --- a/src-tauri/crates/agent-core/src/core/coordination/agent_org_finality/restart_reconciliation.rs +++ b/src-tauri/crates/agent-core/src/core/coordination/agent_org_finality/restart_reconciliation.rs @@ -13,7 +13,7 @@ fn settle_historical_inbox_in_tx( ) -> Result { let mut changed = conn .execute( - "INSERT OR IGNORE INTO agent_org_runtime_inbox_delivery_resolutions ( + "INSERT OR IGNORE INTO agent_org_execution_inbox_delivery_resolutions ( inbox_id,org_run_id,resolution_kind,resolved_by_member_id,reason, replacement_inbox_id,replacement_task_id,created_at ) VALUES (?1,?2,'cancelled','system:startup_repair',?3,NULL,NULL,?4)", @@ -22,17 +22,17 @@ fn settle_historical_inbox_in_tx( .map_err(|error| error.to_string())?; changed = changed.saturating_add( conn.execute( - "DELETE FROM agent_org_runtime_inbox_materializations WHERE inbox_id=?1", + "DELETE FROM agent_org_execution_inbox_materializations WHERE inbox_id=?1", [inbox_id], ) .map_err(|error| error.to_string())?, ); changed = changed.saturating_add( conn.execute( - "UPDATE agent_org_runtime_formal_trigger_attempts + "UPDATE agent_org_execution_formal_trigger_attempts SET status='resolved',terminal_at=COALESCE(terminal_at,?2),updated_at=?2 WHERE receipt_id IN ( - SELECT receipt_id FROM agent_org_runtime_formal_trigger_receipts + SELECT receipt_id FROM agent_org_execution_formal_trigger_receipts WHERE inbox_id=?1 ) AND status IN ('queued','running')", params![inbox_id, now], @@ -41,7 +41,7 @@ fn settle_historical_inbox_in_tx( ); changed = changed.saturating_add( conn.execute( - "UPDATE agent_org_runtime_formal_trigger_receipts + "UPDATE agent_org_execution_formal_trigger_receipts SET status='resolved',doorbell_status='suppressed', resolved_at=COALESCE(resolved_at,?2),updated_at=?2 WHERE inbox_id=?1 AND status IN ('pending','materialized')", @@ -59,7 +59,7 @@ pub(crate) fn reconcile_after_restart(conn: &Connection) -> Result Result Result Result Result Result Result = conn .query_row( "SELECT root.work_episode_id - FROM agent_org_scope_removal_receipts root - JOIN agent_org_runtime_work_episode_tasks task_episode + FROM agent_org_execution_scope_removal_receipts root + JOIN agent_org_execution_work_episode_tasks task_episode ON task_episode.org_run_id=root.org_run_id AND task_episode.work_episode_id=root.work_episode_id AND task_episode.task_id=?3 @@ -218,14 +218,14 @@ pub(crate) fn record_scope_resolution_in_tx( .map_err(|error| error.to_string())?; let episode_id = root.ok_or_else(|| "scope_resolution_root_or_episode_mismatch".to_string())?; conn.execute( - "INSERT INTO agent_org_scope_resolution_receipts ( + "INSERT INTO agent_org_execution_scope_resolution_receipts ( resolution_id,root_receipt_id,org_run_id,work_episode_id,task_id, resolution_kind,replacement_task_id,source_turn_intent_id,created_at ) VALUES (?1,?2,?3,?4,?5,?6,?7,?8,?9) ON CONFLICT(root_receipt_id,task_id,resolution_kind) DO UPDATE SET replacement_task_id=excluded.replacement_task_id, source_turn_intent_id=COALESCE( - agent_org_scope_resolution_receipts.source_turn_intent_id, + agent_org_execution_scope_resolution_receipts.source_turn_intent_id, excluded.source_turn_intent_id )", params![ @@ -260,7 +260,7 @@ pub(crate) fn record_scope_detachments_in_tx( let root_receipt_id: Option = conn .query_row( "SELECT json_extract(cancel_reason_json,'$.sourceEventId') - FROM agent_org_runtime_tasks + FROM agent_org_execution_tasks WHERE org_run_id=?1 AND id=?2 AND status='cancelled' AND json_valid(cancel_reason_json) AND json_extract(cancel_reason_json,'$.code') IN ( diff --git a/src-tauri/crates/agent-core/src/core/coordination/agent_org_finality/task_delivery_settlement.rs b/src-tauri/crates/agent-core/src/core/coordination/agent_org_finality/task_delivery_settlement.rs index bed14eb2ab..f5ea8edd53 100644 --- a/src-tauri/crates/agent-core/src/core/coordination/agent_org_finality/task_delivery_settlement.rs +++ b/src-tauri/crates/agent-core/src/core/coordination/agent_org_finality/task_delivery_settlement.rs @@ -40,16 +40,16 @@ pub(crate) fn settle_task_bound_deliveries_in_tx( let mut statement = conn .prepare( "SELECT DISTINCT inbox.id - FROM agent_org_runtime_inbox inbox - LEFT JOIN agent_org_runtime_inbox_task_bindings binding + FROM agent_org_execution_inbox inbox + LEFT JOIN agent_org_execution_inbox_task_bindings binding ON binding.inbox_id=inbox.id - LEFT JOIN agent_org_runtime_formal_trigger_receipts trigger + LEFT JOIN agent_org_execution_formal_trigger_receipts trigger ON trigger.inbox_id=inbox.id WHERE inbox.org_run_id=?1 AND inbox.delivery_class='formal_work' AND inbox.read_at IS NULL AND NOT EXISTS ( - SELECT 1 FROM agent_org_runtime_inbox_delivery_resolutions existing + SELECT 1 FROM agent_org_execution_inbox_delivery_resolutions existing WHERE existing.inbox_id=inbox.id ) AND ( @@ -65,8 +65,8 @@ pub(crate) fn settle_task_bound_deliveries_in_tx( AND json_valid(inbox.payload_json) AND EXISTS ( SELECT 1 - FROM agent_org_runtime_plan_decisions decision - JOIN agent_org_runtime_plan_revisions revision + FROM agent_org_execution_plan_decisions decision + JOIN agent_org_execution_plan_revisions revision ON revision.plan_revision_id=decision.plan_revision_id WHERE revision.org_run_id=?1 AND revision.source_task_id=?2 @@ -92,7 +92,7 @@ pub(crate) fn settle_task_bound_deliveries_in_tx( for inbox_id in &inbox_ids { inserted = inserted.saturating_add( conn.execute( - "INSERT OR IGNORE INTO agent_org_runtime_inbox_delivery_resolutions ( + "INSERT OR IGNORE INTO agent_org_execution_inbox_delivery_resolutions ( inbox_id,org_run_id,resolution_kind,resolved_by_member_id,reason, replacement_inbox_id,replacement_task_id,created_at ) VALUES (?1,?2,?3,?4,?5,NULL,?6,?7)", @@ -112,22 +112,22 @@ pub(crate) fn settle_task_bound_deliveries_in_tx( if !inbox_ids.is_empty() { for inbox_id in &inbox_ids { conn.execute( - "DELETE FROM agent_org_runtime_inbox_materializations WHERE inbox_id=?1", + "DELETE FROM agent_org_execution_inbox_materializations WHERE inbox_id=?1", [inbox_id], ) .map_err(|error| error.to_string())?; conn.execute( - "UPDATE agent_org_runtime_formal_trigger_attempts + "UPDATE agent_org_execution_formal_trigger_attempts SET status='resolved',terminal_at=COALESCE(terminal_at,?2),updated_at=?2 WHERE receipt_id IN ( - SELECT receipt_id FROM agent_org_runtime_formal_trigger_receipts + SELECT receipt_id FROM agent_org_execution_formal_trigger_receipts WHERE inbox_id=?1 ) AND status IN ('queued','running')", params![inbox_id, &now], ) .map_err(|error| error.to_string())?; conn.execute( - "UPDATE agent_org_runtime_formal_trigger_receipts + "UPDATE agent_org_execution_formal_trigger_receipts SET status='resolved',doorbell_status='suppressed', resolved_at=COALESCE(resolved_at,?2),updated_at=?2 WHERE inbox_id=?1 AND status IN ('pending','materialized')", @@ -159,7 +159,7 @@ pub(crate) fn settle_task_bound_deliveries_in_tx( if let Some(root_receipt_id) = scope_reason.source_event_id.as_deref() { let root_task_id: Option = conn .query_row( - "SELECT target_task_id FROM agent_org_scope_removal_receipts + "SELECT target_task_id FROM agent_org_execution_scope_removal_receipts WHERE receipt_id=?1 AND org_run_id=?2 AND status='recorded'", params![root_receipt_id, ¤t.org_run_id], |row| row.get(0), diff --git a/src-tauri/crates/agent-core/src/core/coordination/agent_org_formal_triggers/claim.rs b/src-tauri/crates/agent-core/src/core/coordination/agent_org_formal_triggers/claim.rs index be3579e6ef..8c0de321ce 100644 --- a/src-tauri/crates/agent-core/src/core/coordination/agent_org_formal_triggers/claim.rs +++ b/src-tauri/crates/agent-core/src/core/coordination/agent_org_formal_triggers/claim.rs @@ -45,10 +45,10 @@ pub(crate) fn claim_for_coordinator_turn( .prepare( "SELECT receipt.receipt_id,receipt.inbox_id, attempt.materialized_input_id - FROM agent_org_runtime_formal_trigger_attempts attempt - JOIN agent_org_runtime_formal_trigger_receipts receipt + FROM agent_org_execution_formal_trigger_attempts attempt + JOIN agent_org_execution_formal_trigger_receipts receipt ON receipt.receipt_id=attempt.receipt_id - JOIN agent_org_runtime_inbox inbox ON inbox.id=receipt.inbox_id + JOIN agent_org_execution_inbox inbox ON inbox.id=receipt.inbox_id WHERE attempt.session_id=?1 AND attempt.turn_intent_id=?2 AND attempt.status IN ('queued','running') AND receipt.org_run_id=?3 AND receipt.status='materialized' @@ -79,7 +79,7 @@ pub(crate) fn claim_for_coordinator_turn( } let now = chrono::Utc::now().to_rfc3339(); tx.execute( - "UPDATE agent_org_runtime_formal_trigger_attempts + "UPDATE agent_org_execution_formal_trigger_attempts SET status='running',started_at=COALESCE(started_at,?3),updated_at=?3 WHERE session_id=?1 AND turn_intent_id=?2 AND status='queued'", params![session_id, turn_intent_id, &now], @@ -88,7 +88,7 @@ pub(crate) fn claim_for_coordinator_turn( let has_more: bool = tx .query_row( "SELECT EXISTS( - SELECT 1 FROM agent_org_runtime_formal_trigger_receipts receipt + SELECT 1 FROM agent_org_execution_formal_trigger_receipts receipt WHERE receipt.org_run_id=?1 AND receipt.status='pending' AND receipt.doorbell_status IN ('missing','delivered') )", @@ -112,9 +112,9 @@ pub(crate) fn claim_for_coordinator_turn( length(CAST(inbox.payload_json AS BLOB)), attempt.attempt,attempt.session_id,attempt.turn_intent_id, attempt.materialized_input_id - FROM agent_org_runtime_formal_trigger_receipts receipt - JOIN agent_org_runtime_inbox inbox ON inbox.id=receipt.inbox_id - LEFT JOIN agent_org_runtime_formal_trigger_attempts attempt + FROM agent_org_execution_formal_trigger_receipts receipt + JOIN agent_org_execution_inbox inbox ON inbox.id=receipt.inbox_id + LEFT JOIN agent_org_execution_formal_trigger_attempts attempt ON attempt.receipt_id=receipt.receipt_id AND attempt.status IN ('queued','running') WHERE receipt.org_run_id=?1 AND receipt.status IN ('pending','materialized') @@ -122,7 +122,7 @@ pub(crate) fn claim_for_coordinator_turn( AND inbox.delivery_class='formal_work' AND inbox.read_at IS NULL AND NOT EXISTS ( - SELECT 1 FROM agent_org_runtime_inbox_delivery_resolutions resolution + SELECT 1 FROM agent_org_execution_inbox_delivery_resolutions resolution WHERE resolution.inbox_id=inbox.id ) AND attempt.receipt_id IS NULL @@ -194,13 +194,13 @@ pub(crate) fn claim_for_coordinator_turn( let attempt: i64 = tx .query_row( "SELECT current_attempt + 1 - FROM agent_org_runtime_formal_trigger_receipts WHERE receipt_id=?1", + FROM agent_org_execution_formal_trigger_receipts WHERE receipt_id=?1", [receipt_id], |row| row.get(0), ) .map_err(|error| error.to_string())?; tx.execute( - "INSERT INTO agent_org_runtime_formal_trigger_attempts ( + "INSERT INTO agent_org_execution_formal_trigger_attempts ( receipt_id,attempt,session_id,turn_intent_id,status, materialized_input_id,materialized_event_id,typed_error, queued_at,started_at,terminal_at,updated_at @@ -216,7 +216,7 @@ pub(crate) fn claim_for_coordinator_turn( ) .map_err(|error| error.to_string())?; tx.execute( - "UPDATE agent_org_runtime_formal_trigger_receipts + "UPDATE agent_org_execution_formal_trigger_receipts SET current_attempt=?2,status='materialized', materialized_input_id=?3,updated_at=?4 WHERE receipt_id=?1 AND status='pending'", @@ -260,8 +260,8 @@ pub(crate) fn resolve_inbox_receipts_in_tx( let active: Option<(String, i64)> = tx .query_row( "SELECT receipt.receipt_id,attempt.attempt - FROM agent_org_runtime_formal_trigger_receipts receipt - JOIN agent_org_runtime_formal_trigger_attempts attempt + FROM agent_org_execution_formal_trigger_receipts receipt + JOIN agent_org_execution_formal_trigger_attempts attempt ON attempt.receipt_id=receipt.receipt_id AND attempt.attempt=receipt.current_attempt WHERE receipt.inbox_id=?1 @@ -276,7 +276,7 @@ pub(crate) fn resolve_inbox_receipts_in_tx( continue; }; tx.execute( - "UPDATE agent_org_runtime_formal_trigger_attempts + "UPDATE agent_org_execution_formal_trigger_attempts SET status='resolved',materialized_event_id=?4,terminal_at=?5,updated_at=?5 WHERE receipt_id=?1 AND attempt=?2 AND session_id=?3 AND turn_intent_id=?6 @@ -293,7 +293,7 @@ pub(crate) fn resolve_inbox_receipts_in_tx( .map_err(|error| error.to_string())?; let changed = tx .execute( - "UPDATE agent_org_runtime_formal_trigger_receipts + "UPDATE agent_org_execution_formal_trigger_receipts SET status='resolved',materialized_event_id=?2,resolved_at=?3,updated_at=?3 WHERE receipt_id=?1 AND current_attempt=?4 AND status='materialized'", @@ -326,7 +326,7 @@ pub(crate) fn fail_attempt_for_turn( let now = chrono::Utc::now().to_rfc3339(); let changed = tx .execute( - "UPDATE agent_org_runtime_formal_trigger_attempts + "UPDATE agent_org_execution_formal_trigger_attempts SET status='failed',typed_error=?3,terminal_at=?4,updated_at=?4 WHERE session_id=?1 AND turn_intent_id=?2 AND status IN ('queued','running')", @@ -335,13 +335,13 @@ pub(crate) fn fail_attempt_for_turn( .map_err(|error| error.to_string())?; if changed > 0 { tx.execute( - "UPDATE agent_org_runtime_formal_trigger_receipts + "UPDATE agent_org_execution_formal_trigger_receipts SET status='pending',doorbell_status='missing', doorbell_delivered_at=NULL,materialized_event_id=NULL, resolved_at=NULL,updated_at=?3 WHERE receipt_id IN ( SELECT receipt_id - FROM agent_org_runtime_formal_trigger_attempts + FROM agent_org_execution_formal_trigger_attempts WHERE session_id=?1 AND turn_intent_id=?2 AND status='failed' AND terminal_at=?3 ) AND status='materialized'", diff --git a/src-tauri/crates/agent-core/src/core/coordination/agent_org_formal_triggers/schema.rs b/src-tauri/crates/agent-core/src/core/coordination/agent_org_formal_triggers/schema.rs index c7fc144a81..a06f117054 100644 --- a/src-tauri/crates/agent-core/src/core/coordination/agent_org_formal_triggers/schema.rs +++ b/src-tauri/crates/agent-core/src/core/coordination/agent_org_formal_triggers/schema.rs @@ -2,7 +2,7 @@ use rusqlite::Connection; pub(super) fn create_schema(conn: &Connection) -> rusqlite::Result<()> { conn.execute_batch( - "CREATE TABLE IF NOT EXISTS agent_org_runtime_formal_trigger_receipts ( + "CREATE TABLE IF NOT EXISTS agent_org_execution_formal_trigger_receipts ( receipt_id TEXT PRIMARY KEY, org_run_id TEXT NOT NULL, trigger_kind TEXT NOT NULL, @@ -29,22 +29,22 @@ pub(super) fn create_schema(conn: &Connection) -> rusqlite::Result<()> { updated_at TEXT NOT NULL, UNIQUE(org_run_id,trigger_kind,trigger_id,trigger_revision), UNIQUE(inbox_id), - FOREIGN KEY(org_run_id) REFERENCES agent_org_runtime_runs(id) ON DELETE CASCADE, - FOREIGN KEY(inbox_id) REFERENCES agent_org_runtime_inbox(id) ON DELETE CASCADE + FOREIGN KEY(org_run_id) REFERENCES agent_org_execution_runs(id) ON DELETE CASCADE, + FOREIGN KEY(inbox_id) REFERENCES agent_org_execution_inbox(id) ON DELETE CASCADE ); - CREATE INDEX IF NOT EXISTS idx_agent_org_formal_trigger_pending - ON agent_org_runtime_formal_trigger_receipts( + CREATE INDEX IF NOT EXISTS idx_agent_org_execution_formal_trigger_pending + ON agent_org_execution_formal_trigger_receipts( org_run_id,status,doorbell_status,created_at,receipt_id ); - CREATE INDEX IF NOT EXISTS idx_agent_org_formal_trigger_missing_doorbell - ON agent_org_runtime_formal_trigger_receipts( + CREATE INDEX IF NOT EXISTS idx_agent_org_execution_formal_trigger_missing_doorbell + ON agent_org_execution_formal_trigger_receipts( doorbell_status,status,org_run_id,created_at ) WHERE status='pending' AND doorbell_status='missing'; - CREATE INDEX IF NOT EXISTS idx_agent_org_formal_trigger_task - ON agent_org_runtime_formal_trigger_receipts(org_run_id,task_id,created_at) + CREATE INDEX IF NOT EXISTS idx_agent_org_execution_formal_trigger_task + ON agent_org_execution_formal_trigger_receipts(org_run_id,task_id,created_at) WHERE task_id IS NOT NULL; - CREATE TABLE IF NOT EXISTS agent_org_runtime_formal_trigger_attempts ( + CREATE TABLE IF NOT EXISTS agent_org_execution_formal_trigger_attempts ( receipt_id TEXT NOT NULL, attempt INTEGER NOT NULL CHECK(attempt >= 1), session_id TEXT NOT NULL, @@ -59,14 +59,14 @@ pub(super) fn create_schema(conn: &Connection) -> rusqlite::Result<()> { updated_at TEXT NOT NULL, PRIMARY KEY(receipt_id,attempt), FOREIGN KEY(receipt_id) - REFERENCES agent_org_runtime_formal_trigger_receipts(receipt_id) + REFERENCES agent_org_execution_formal_trigger_receipts(receipt_id) ON DELETE CASCADE ); - CREATE UNIQUE INDEX IF NOT EXISTS idx_agent_org_formal_trigger_one_active_attempt - ON agent_org_runtime_formal_trigger_attempts(receipt_id) + CREATE UNIQUE INDEX IF NOT EXISTS idx_agent_org_execution_formal_trigger_one_active_attempt + ON agent_org_execution_formal_trigger_attempts(receipt_id) WHERE status IN ('queued','running'); - CREATE INDEX IF NOT EXISTS idx_agent_org_formal_trigger_attempt_turn - ON agent_org_runtime_formal_trigger_attempts( + CREATE INDEX IF NOT EXISTS idx_agent_org_execution_formal_trigger_attempt_turn + ON agent_org_execution_formal_trigger_attempts( session_id,turn_intent_id,status,receipt_id );", ) diff --git a/src-tauri/crates/agent-core/src/core/coordination/agent_org_formal_triggers/store.rs b/src-tauri/crates/agent-core/src/core/coordination/agent_org_formal_triggers/store.rs index 6ab3107ca9..abf84a0eaf 100644 --- a/src-tauri/crates/agent-core/src/core/coordination/agent_org_formal_triggers/store.rs +++ b/src-tauri/crates/agent-core/src/core/coordination/agent_org_formal_triggers/store.rs @@ -148,7 +148,7 @@ pub(crate) fn record_trigger_in_tx( let run_is_running: bool = tx .query_row( "SELECT EXISTS( - SELECT 1 FROM agent_org_runtime_runs + SELECT 1 FROM agent_org_execution_runs WHERE id=?1 AND status='running' )", [org_run_id], @@ -175,7 +175,7 @@ pub(crate) fn record_trigger_in_tx( }; let resolved_at = source.initially_resolved.then_some(now.as_str()); tx.execute( - "INSERT INTO agent_org_runtime_formal_trigger_receipts ( + "INSERT INTO agent_org_execution_formal_trigger_receipts ( receipt_id,org_run_id,trigger_kind,trigger_id,trigger_revision, source_kind,target_member_id,inbox_id,task_id,owner_member_id, source_turn_intent_id,task_output_digest,plan_revision_id,status, @@ -290,7 +290,7 @@ pub(crate) fn mark_doorbell_delivered_with_connection( let now = chrono::Utc::now().to_rfc3339(); let updated = tx .execute( - "UPDATE agent_org_runtime_formal_trigger_receipts + "UPDATE agent_org_execution_formal_trigger_receipts SET doorbell_status='delivered',doorbell_delivered_at=?2,updated_at=?2 WHERE receipt_id=?1 AND status='pending' AND doorbell_status='missing'", params![receipt_id, &now], @@ -321,12 +321,12 @@ pub fn missing_doorbell_ids_for_run(org_run_id: &str, limit: usize) -> Result, String, i64) = conn .query_row( "SELECT status,doorbell_status,source_turn_intent_id,owner_member_id,inbox_id - FROM agent_org_runtime_formal_trigger_receipts + FROM agent_org_execution_formal_trigger_receipts WHERE source_kind='task_assignment'", [], |row| { @@ -96,8 +96,8 @@ fn external_assignment_materializes_a_separate_coordinator_fact_without_consumin let observation: (i64, String, String, String) = conn .query_row( "SELECT receipt.inbox_id,inbox.payload_kind,receipt.status,receipt.owner_member_id - FROM agent_org_runtime_formal_trigger_receipts receipt - JOIN agent_org_runtime_inbox inbox ON inbox.id=receipt.inbox_id + FROM agent_org_execution_formal_trigger_receipts receipt + JOIN agent_org_execution_inbox inbox ON inbox.id=receipt.inbox_id WHERE receipt.source_kind='task_assignment'", [], |row| Ok((row.get(0)?, row.get(1)?, row.get(2)?, row.get(3)?)), diff --git a/src-tauri/crates/agent-core/src/core/coordination/agent_org_formal_triggers/tests/claim_tests.rs b/src-tauri/crates/agent-core/src/core/coordination/agent_org_formal_triggers/tests/claim_tests.rs index 0b03c6ab47..000ea70912 100644 --- a/src-tauri/crates/agent-core/src/core/coordination/agent_org_formal_triggers/tests/claim_tests.rs +++ b/src-tauri/crates/agent-core/src/core/coordination/agent_org_formal_triggers/tests/claim_tests.rs @@ -33,7 +33,7 @@ fn same_turn_replays_the_exact_batch_and_leaves_later_facts_pending() { let conn = get_connection().expect("formal trigger database"); let later_status: String = conn .query_row( - "SELECT status FROM agent_org_runtime_formal_trigger_receipts WHERE inbox_id=?1", + "SELECT status FROM agent_org_execution_formal_trigger_receipts WHERE inbox_id=?1", [later.id], |row| row.get(0), ) @@ -78,7 +78,7 @@ fn known_failure_terminates_attempt_and_allows_one_new_attempt() { let attempts: Vec<(i64, String)> = { let mut stmt = conn .prepare( - "SELECT attempt,status FROM agent_org_runtime_formal_trigger_attempts + "SELECT attempt,status FROM agent_org_execution_formal_trigger_attempts ORDER BY attempt", ) .unwrap(); @@ -152,7 +152,7 @@ fn user_group_fact_replays_until_exact_provider_turn_acknowledges_it() { assert_eq!(replay, first); conn.execute( - "INSERT INTO agent_org_runtime_inbox_materializations( + "INSERT INTO agent_org_execution_inbox_materializations( inbox_id,session_id,transcript_message_id,transcript_intent_id,materialized_at ) VALUES (?1,'formal-root','group-transcript','turn-group',?2)", rusqlite::params![row.id, chrono::Utc::now().to_rfc3339()], @@ -174,8 +174,8 @@ fn user_group_fact_replays_until_exact_provider_turn_acknowledges_it() { let state: (String, bool, Option) = conn .query_row( "SELECT receipt.status,inbox.read_at IS NOT NULL,receipt.materialized_event_id - FROM agent_org_runtime_formal_trigger_receipts receipt - JOIN agent_org_runtime_inbox inbox ON inbox.id=receipt.inbox_id + FROM agent_org_execution_formal_trigger_receipts receipt + JOIN agent_org_execution_inbox inbox ON inbox.id=receipt.inbox_id WHERE inbox.id=?1", [row.id], |row| Ok((row.get(0)?, row.get(1)?, row.get(2)?)), diff --git a/src-tauri/crates/agent-core/src/core/coordination/agent_org_formal_triggers/tests/fixture.rs b/src-tauri/crates/agent-core/src/core/coordination/agent_org_formal_triggers/tests/fixture.rs index 9f60067ec1..5093a4457e 100644 --- a/src-tauri/crates/agent-core/src/core/coordination/agent_org_formal_triggers/tests/fixture.rs +++ b/src-tauri/crates/agent-core/src/core/coordination/agent_org_formal_triggers/tests/fixture.rs @@ -82,7 +82,7 @@ impl FormalFixture { ) .expect("Coordinator Session"); conn.execute( - "INSERT INTO agent_org_runtime_member_materializations( + "INSERT INTO agent_org_execution_member_materializations( org_run_id,member_id,agent_id,generation,session_id, authority_class,status,created_at,updated_at ) VALUES (?1,'coordinator','coordinator-agent',1,'formal-root', @@ -107,7 +107,7 @@ impl FormalFixture { ) .expect("Coordinator Turn intent"); conn.execute( - "INSERT INTO agent_org_runtime_turn_contexts( + "INSERT INTO agent_org_execution_turn_contexts( session_id,turn_intent_id,org_run_id,participant_id,turn_kind, source_kind,source_id,activation_generation,created_at ) VALUES ('formal-root',?1,?2,'coordinator','coordinator', diff --git a/src-tauri/crates/agent-core/src/core/coordination/agent_org_formal_triggers/tests/scale_tests.rs b/src-tauri/crates/agent-core/src/core/coordination/agent_org_formal_triggers/tests/scale_tests.rs index 962543ab89..acee807ac5 100644 --- a/src-tauri/crates/agent-core/src/core/coordination/agent_org_formal_triggers/tests/scale_tests.rs +++ b/src-tauri/crates/agent-core/src/core/coordination/agent_org_formal_triggers/tests/scale_tests.rs @@ -22,7 +22,7 @@ fn thousand_pending_facts_still_materialize_one_bounded_batch() { "SELECT SUM(CASE WHEN status='materialized' THEN 1 ELSE 0 END), SUM(CASE WHEN status='pending' THEN 1 ELSE 0 END) - FROM agent_org_runtime_formal_trigger_receipts + FROM agent_org_execution_formal_trigger_receipts WHERE org_run_id=?1", [&fixture.run_id], |row| Ok((row.get(0)?, row.get(1)?)), diff --git a/src-tauri/crates/agent-core/src/core/coordination/agent_org_formal_triggers/tests/store_tests.rs b/src-tauri/crates/agent-core/src/core/coordination/agent_org_formal_triggers/tests/store_tests.rs index d8ef19d658..e0caa23310 100644 --- a/src-tauri/crates/agent-core/src/core/coordination/agent_org_formal_triggers/tests/store_tests.rs +++ b/src-tauri/crates/agent-core/src/core/coordination/agent_org_formal_triggers/tests/store_tests.rs @@ -15,14 +15,14 @@ fn structured_fact_creates_one_exact_receipt_while_narration_creates_none() { let conn = get_connection().expect("formal trigger database"); let receipts: i64 = conn .query_row( - "SELECT COUNT(*) FROM agent_org_runtime_formal_trigger_receipts", + "SELECT COUNT(*) FROM agent_org_execution_formal_trigger_receipts", [], |row| row.get(0), ) .unwrap(); let inbox_id: i64 = conn .query_row( - "SELECT inbox_id FROM agent_org_runtime_formal_trigger_receipts", + "SELECT inbox_id FROM agent_org_execution_formal_trigger_receipts", [], |row| row.get(0), ) @@ -80,8 +80,8 @@ fn self_observed_coordinator_fact_is_resolved_without_a_follow_up_wake() { let state: (String, String, bool) = conn .query_row( "SELECT receipt.status,receipt.doorbell_status,inbox.read_at IS NOT NULL - FROM agent_org_runtime_formal_trigger_receipts receipt - JOIN agent_org_runtime_inbox inbox ON inbox.id=receipt.inbox_id + FROM agent_org_execution_formal_trigger_receipts receipt + JOIN agent_org_execution_inbox inbox ON inbox.id=receipt.inbox_id WHERE inbox.id=?1", [record.id], |row| Ok((row.get(0)?, row.get(1)?, row.get(2)?)), @@ -110,7 +110,7 @@ fn doorbell_acknowledgement_does_not_cover_rows_created_after_its_snapshot() { .map(|inbox_id| { conn.query_row( "SELECT doorbell_status - FROM agent_org_runtime_formal_trigger_receipts + FROM agent_org_execution_formal_trigger_receipts WHERE inbox_id=?1", [inbox_id], |row| row.get::<_, String>(0), diff --git a/src-tauri/crates/agent-core/src/core/coordination/agent_org_history.rs b/src-tauri/crates/agent-core/src/core/coordination/agent_org_history.rs index 04cd3b8e54..90a36c5045 100644 --- a/src-tauri/crates/agent-core/src/core/coordination/agent_org_history.rs +++ b/src-tauri/crates/agent-core/src/core/coordination/agent_org_history.rs @@ -66,12 +66,12 @@ fn coordinator_mail_wake( // attempt proves this is an inbox wake, including after it has resolved. conn.query_row( "SELECT EXISTS( - SELECT 1 FROM agent_org_runtime_formal_trigger_attempts attempt - JOIN agent_org_runtime_formal_trigger_receipts receipt USING(receipt_id) + SELECT 1 FROM agent_org_execution_formal_trigger_attempts attempt + JOIN agent_org_execution_formal_trigger_receipts receipt USING(receipt_id) WHERE attempt.session_id=?1 AND attempt.turn_intent_id=?2 AND receipt.org_run_id=?3 ) AND NOT EXISTS( - SELECT 1 FROM agent_org_runtime_initial_inputs + SELECT 1 FROM agent_org_execution_initial_inputs WHERE org_run_id=?3 AND turn_intent_id=?2 ) AND NOT EXISTS( SELECT 1 FROM session_turn_intents @@ -101,8 +101,8 @@ pub fn inbox_execution( .prepare( "SELECT inbox.sender_member_id, COUNT(*), (inbox.sender_member_id IS NULL AND inbox.sender_agent_id=?5) AS system_sender - FROM agent_org_runtime_inbox_materializations receipt - JOIN agent_org_runtime_inbox inbox ON inbox.id=receipt.inbox_id + FROM agent_org_execution_inbox_materializations receipt + JOIN agent_org_execution_inbox inbox ON inbox.id=receipt.inbox_id WHERE receipt.session_id=?1 AND receipt.transcript_message_id=?2 AND inbox.org_run_id=?3 AND inbox.recipient_member_id=?4 GROUP BY inbox.sender_member_id, system_sender diff --git a/src-tauri/crates/agent-core/src/core/coordination/agent_org_history_store/archive.rs b/src-tauri/crates/agent-core/src/core/coordination/agent_org_history_store/archive.rs new file mode 100644 index 0000000000..8c3cc6e3e0 --- /dev/null +++ b/src-tauri/crates/agent-core/src/core/coordination/agent_org_history_store/archive.rs @@ -0,0 +1,132 @@ +//! Copy raw values and original DDL before retiring any private object. +use rusqlite::{params, Connection}; + +use super::{capture, copies, quoted, table_exists}; + +const OLD_SCHEMA: &str = include_str!("../fixtures/official_v2_0_8_agent_org.sql"); +const LEGACY_TABLES: &[&str] = &[ + "agent_org_runs", + "agent_org_run_progress", + "agent_org_plan_approvals", + "agent_org_recovery_attempts", + "agent_org_tasks", + "agent_org_task_events", + "agent_org_task_run_schema_migrations", + "agent_inbox", + "agent_inbox_materializations", + "agent_inbox_delivery_resolutions", + "agent_member_interventions", +]; +const COMPANIONS: &[&str] = &[ + "agent_org_task_execution_leases", + "agent_org_task_execution_reconciliations", + "agent_org_scope_removal_receipts", + "agent_org_scope_resolution_receipts", + "agent_org_coordinator_completion_rechecks", + "agent_org_member_turn_admissions", +]; + +struct Object { + kind: String, + name: String, + table: String, + sql: Option, +} + +fn owns(table: &str) -> bool { + table.starts_with("agent_org_runtime_") + || LEGACY_TABLES.contains(&table) + || COMPANIONS.contains(&table) +} + +fn objects(conn: &Connection) -> rusqlite::Result> { + let mut stmt = + conn.prepare("SELECT type,name,tbl_name,sql FROM sqlite_master ORDER BY type,name")?; + let all = stmt + .query_map([], |row| { + Ok(Object { + kind: row.get(0)?, + name: row.get(1)?, + table: row.get(2)?, + sql: row.get(3)?, + }) + })? + .collect::>>()?; + Ok(all + .into_iter() + .filter(|object| owns(&object.table)) + .collect()) +} + +pub(super) fn retire_previous_execution(conn: &Connection, fresh: bool) -> rusqlite::Result<()> { + let objects = objects(conn)?; + let tables = objects + .iter() + .filter(|object| object.kind == "table") + .collect::>(); + let mut has_rows = false; + for table in &tables { + has_rows |= conn.query_row( + &format!( + "SELECT EXISTS(SELECT 1 FROM {} LIMIT 1)", + quoted(&table.name) + ), + [], + |row| row.get::<_, bool>(0), + )?; + } + // The fixed old area is normally empty. Checking its bounded object list + // never scans shared conversation bodies on a normal restart. + let expected = Connection::open_in_memory()?; + expected.execute_batch(OLD_SCHEMA)?; + let expected_objects = self::objects(&expected)?; + let same_schema = objects.len() == expected_objects.len() + && objects + .iter() + .zip(&expected_objects) + .all(|(a, b)| a.kind == b.kind && a.name == b.name && a.sql == b.sql); + if !fresh && !has_rows && same_schema { + return Ok(()); + } + if fresh || has_rows { + conn.execute("INSERT INTO org_history_archives DEFAULT VALUES", [])?; + let archive_id = conn.last_insert_rowid(); + for object in &objects { + let raw = (object.kind == "table") + .then(|| format!("org_history_raw_{archive_id}_{}", object.name)); + if let Some(raw) = &raw { + // CTAS intentionally carries no indexes, triggers, foreign keys, + // or execution constraints. SQLite copies BLOBs without decoding. + conn.execute_batch(&format!( + "CREATE TABLE {} AS SELECT rowid AS __source_rowid, * FROM {}", + quoted(raw), + quoted(&object.name), + ))?; + } + conn.execute( + "INSERT INTO org_history_schema_objects + (archive_id,name,object_type,table_name,original_sql,raw_table) + VALUES (?1,?2,?3,?4,?5,?6)", + params![ + archive_id, + object.name, + object.kind, + object.table, + object.sql, + raw + ], + )?; + } + capture::retired_sessions(conn, fresh)?; + capture::retired_items(conn)?; + copies::backfill_retired(conn)?; + } + // FK actions are disabled by the owning initializer, not by this helper. + // All schema/data changes and the completion marker share its transaction. + for table in tables { + conn.execute_batch(&format!("DROP TABLE {}", quoted(&table.name)))?; + } + conn.execute_batch(OLD_SCHEMA)?; + debug_assert!(table_exists(conn, "agent_org_runtime_runs")?); + Ok(()) +} diff --git a/src-tauri/crates/agent-core/src/core/coordination/agent_org_history_store/capture.rs b/src-tauri/crates/agent-core/src/core/coordination/agent_org_history_store/capture.rs new file mode 100644 index 0000000000..1fdce13b26 --- /dev/null +++ b/src-tauri/crates/agent-core/src/core/coordination/agent_org_history_store/capture.rs @@ -0,0 +1,301 @@ +//! Tolerant fact extraction: missing old fields stay unknown, never inferred states. +use rusqlite::{params, Connection}; +use serde_json::Value; + +use super::{optional_text as text, quoted, root_for_run, stable_id, table_exists}; + +pub(super) fn retired_sessions(conn: &Connection, fresh: bool) -> rusqlite::Result<()> { + for table in ["agent_org_runtime_runs", "agent_org_runs"] { + if !table_exists(conn, table)? { + continue; + } + let mut stmt = conn.prepare(&format!("SELECT * FROM {}", quoted(table)))?; + let mut rows = stmt.query([])?; + while let Some(row) = rows.next()? { + let Some(root) = text(row, "root_session_id") else { + continue; + }; + let snapshot = text(row, "org_snapshot_json") + .and_then(|raw| serde_json::from_str::(&raw).ok()); + let name = snapshot + .as_ref() + .and_then(|v| v.get("orgName").or_else(|| v.get("name"))) + .and_then(Value::as_str); + let run_id = text(row, "id"); + conn.execute( + "INSERT OR IGNORE INTO org_history_sessions + (session_id,root_session_id,run_id,member_name,title,source_table,original_status) + VALUES (?1,?1,?2,?3,?3,?4,?5)", + params![root, run_id, name, table, text(row, "status")], + )?; + capture_roster(conn, table, run_id.as_deref(), &root, snapshot.as_ref())?; + } + } + if table_exists(conn, "agent_sessions")? { + // First cutover also captures orphaned member sessions whose execution + // table is missing. On re-upgrade, exclude current execution identities. + let current_filter = if fresh { + "1" + } else { + "NOT EXISTS(SELECT 1 FROM agent_org_execution_runs r + WHERE r.root_session_id=s.session_id OR r.root_session_id=s.parent_session_id) + AND NOT EXISTS(SELECT 1 FROM agent_org_execution_member_materializations m WHERE m.session_id=s.session_id)" + }; + let mut stmt = conn.prepare(&format!( + "SELECT s.* FROM agent_sessions s WHERE s.org_member_id IS NOT NULL + AND {current_filter} AND NOT EXISTS(SELECT 1 FROM org_history_copies c + WHERE c.copy_session_id=s.session_id)" + ))?; + let mut rows = stmt.query([])?; + while let Some(row) = rows.next()? { + let Some(session) = text(row, "session_id") else { + continue; + }; + // A persisted parent link is a fact. An absent link remains NULL. + conn.execute( + "INSERT OR IGNORE INTO org_history_sessions + (session_id,root_session_id,member_id,member_name,title,source_table,original_status) + VALUES (?1,?2,?3,?4,?4,'agent_sessions',?5)", + params![session,text(row,"parent_session_id"),text(row,"org_member_id"), + text(row,"name"),text(row,"status")], + )?; + } + conn.execute( + "INSERT OR IGNORE INTO org_history_sessions + (session_id,root_session_id,title,source_table,original_status) + SELECT s.session_id,s.session_id,s.name,'agent_sessions',s.status + FROM agent_sessions s WHERE EXISTS(SELECT 1 FROM org_history_sessions h + WHERE h.root_session_id=s.session_id)", + [], + )?; + conn.execute( + "UPDATE org_history_sessions SET + title=COALESCE(title,(SELECT name FROM agent_sessions s + WHERE s.session_id=org_history_sessions.session_id)), + original_status=COALESCE(original_status,(SELECT status FROM agent_sessions s + WHERE s.session_id=org_history_sessions.session_id))", + [], + )?; + } + Ok(()) +} + +fn capture_roster( + conn: &Connection, + source: &str, + run_id: Option<&str>, + root: &str, + snapshot: Option<&Value>, +) -> rusqlite::Result<()> { + let table = "agent_org_runtime_member_materializations"; + if !table_exists(conn, table)? { + return Ok(()); + } + let mut stmt = conn + .prepare("SELECT * FROM agent_org_runtime_member_materializations WHERE org_run_id=?1")?; + let mut rows = stmt.query([run_id])?; + while let Some(row) = rows.next()? { + let Some(session) = text(row, "session_id") else { + continue; + }; + let member = text(row, "member_id"); + let name = snapshot + .and_then(|snapshot| snapshot.get("members")) + .and_then(Value::as_array) + .and_then(|members| { + members.iter().find(|item| { + item.get("id") + .or_else(|| item.get("memberId")) + .and_then(Value::as_str) + == member.as_deref() + }) + }) + .and_then(|item| item.get("name")) + .and_then(Value::as_str); + conn.execute( + "INSERT OR IGNORE INTO org_history_sessions + (session_id,root_session_id,run_id,member_id,member_name,source_table) + VALUES (?1,?2,?3,?4,?5,?6)", + params![session, root, run_id, member, name, source], + )?; + } + Ok(()) +} + +pub(super) fn retired_items(conn: &Connection) -> rusqlite::Result<()> { + for table in [ + "agent_org_runtime_inbox_materializations", + "agent_inbox_materializations", + ] { + if !table_exists(conn, table)? { + continue; + } + let mut stmt = conn.prepare(&format!("SELECT * FROM {}", quoted(table)))?; + let mut rows = stmt.query([])?; + while let Some(row) = rows.next()? { + if let (Some(session), Some(message)) = + (text(row, "session_id"), text(row, "transcript_message_id")) + { + conn.execute( + "INSERT OR IGNORE INTO org_history_inbox_messages VALUES (?1,?2)", + params![session, message], + )?; + } + } + } + for (table, field, kind) in [ + ("agent_org_runtime_tasks", "output_json", "output"), + ("agent_org_tasks", "output_json", "output"), + ("agent_org_runtime_inbox", "payload_json", "group_message"), + ("agent_inbox", "payload_json", "group_message"), + ( + "agent_org_runtime_initial_inputs", + "content", + "initial_input", + ), + ( + "agent_org_runtime_member_intervention_turns", + "display_content", + "member_input", + ), + ("agent_org_runtime_plan_revisions", "plan_content", "plan"), + ] { + if !table_exists(conn, table)? { + continue; + } + let mut stmt = conn.prepare(&format!( + "SELECT rowid AS __source_rowid,* FROM {}", + quoted(table) + ))?; + let mut rows = stmt.query([])?; + while let Some(row) = rows.next()? { + let Some(run) = text(row, "org_run_id") else { + continue; + }; + let Some(root) = root_for_run(conn, &run)? else { + continue; + }; + let Some(raw) = text(row, field) else { + continue; + }; + let value = serde_json::from_str::(&raw).ok(); + if kind == "group_message" && text(row, "payload_kind").as_deref() != Some("plain") { + continue; + } + let mut content = text(row, "display_text") + .or_else(|| { + value + .as_ref() + .and_then(|v| { + v.get("content") + .or_else(|| v.get("text")) + .or_else(|| v.get("summary")) + }) + .and_then(Value::as_str) + .map(str::to_owned) + }) + .unwrap_or_else(|| raw.clone()); + if kind == "output" { + if let Some(output) = value.as_ref() { + content = [ + text(row, "subject"), + output + .get("summary") + .and_then(Value::as_str) + .map(str::to_owned), + output + .get("content") + .and_then(Value::as_str) + .map(str::to_owned), + ] + .into_iter() + .flatten() + .collect::>() + .join("\n\n"); + if content.is_empty() { + content = raw.clone(); + } + } + } + let key = text(row, "id") + .or_else(|| text(row, "turn_intent_id")) + .unwrap_or_else(|| { + row.get::<_, i64>("__source_rowid") + .unwrap_or_default() + .to_string() + }); + conn.execute( + "INSERT OR IGNORE INTO org_history_items + (id,root_session_id,source_session_id,kind,content,created_at,source_json) + VALUES (?1,?2,?3,?4,?5,?6,?7)", + params![ + stable_id("item", &format!("{table}:{run}:{key}")), + root, + text(row, "session_id"), + kind, + content, + text(row, "created_at").unwrap_or_default(), + raw + ], + )?; + } + } + capture_visible_events(conn)?; + Ok(()) +} + +fn capture_visible_events(conn: &Connection) -> rusqlite::Result<()> { + let has_sessions: bool = conn.query_row( + "SELECT EXISTS(SELECT 1 FROM org_history_sessions WHERE root_session_id IS NOT NULL)", + [], + |row| row.get(0), + )?; + if !has_sessions { + return Ok(()); + } + if !table_exists(conn, "events")? { + return Ok(()); + } + let mut stmt = conn.prepare( + "SELECT e.*,h.root_session_id FROM org_history_sessions h + JOIN events e ON e.session_id=h.session_id + WHERE h.root_session_id IS NOT NULL + AND NOT EXISTS(SELECT 1 FROM org_history_copies c WHERE c.source_session_id=h.session_id) AND ( + (h.root_session_id=e.session_id AND e.function_name IN + ('user_message','user_input','user','message','assistant_message','assistant')) + OR (json_valid(e.result_json) AND ( + json_type(e.result_json,'$.agent_org_group_root_reply') IS NOT NULL + OR json_type(e.result_json,'$.agent_org_user_directed_reply') IS NOT NULL + OR json_type(e.result_json,'$.agent_org_initial_reply') IS NOT NULL)))", + )?; + let mut rows = stmt.query([])?; + while let Some(row) = rows.next()? { + let id: String = row.get("id")?; + let source: String = row.get("session_id")?; + let raw: String = row.get("result_json")?; + let value = serde_json::from_str::(&raw).ok(); + let content = value + .as_ref() + .and_then(|v| v.get("content").or_else(|| v.pointer("/message/content"))) + .and_then(Value::as_str) + .map(str::to_owned) + .unwrap_or(row.get("content")?); + if content.is_empty() { + continue; + } + conn.execute( + "INSERT OR IGNORE INTO org_history_items + (id,root_session_id,source_session_id,kind,content,created_at,source_json) + VALUES (?1,?2,?3,'conversation',?4,?5,?6)", + params![ + stable_id("conversation", &format!("{source}:{id}")), + row.get::<_, String>("root_session_id")?, + source, + content, + row.get::<_, String>("created_at")?, + raw + ], + )?; + } + Ok(()) +} diff --git a/src-tauri/crates/agent-core/src/core/coordination/agent_org_history_store/conformance_tests.rs b/src-tauri/crates/agent-core/src/core/coordination/agent_org_history_store/conformance_tests.rs new file mode 100644 index 0000000000..74e919c307 --- /dev/null +++ b/src-tauri/crates/agent-core/src/core/coordination/agent_org_history_store/conformance_tests.rs @@ -0,0 +1,193 @@ +use super::*; + +#[test] +fn saved_materialization_preserves_membership_without_a_template_snapshot_or_parent_link() { + let conn = database(); + seed_old(&conn); + conn.execute_batch( + "UPDATE agent_org_runtime_runs SET org_snapshot_json=NULL; + UPDATE agent_sessions SET parent_session_id=NULL WHERE session_id='member';", + ) + .unwrap(); + init_agent_org_schemas(&conn).unwrap(); + let member = descriptor(&conn, "member").unwrap().unwrap(); + assert_eq!(member.root_session_id.as_deref(), Some("root")); + assert_eq!(member.members.len(), 2); + assert!(member.members.iter().any(|m| { + m.session_id == "member" + && m.member_id.as_deref() == Some("alice") + && m.name.as_deref() == Some("Alice") + })); + let copied_body: String = conn + .query_row( + "SELECT e.content FROM org_history_copies c + JOIN events e ON e.session_id=c.copy_session_id + WHERE c.source_session_id='member'", + [], + |row| row.get(0), + ) + .unwrap(); + assert_eq!(copied_body, "Saved member reply"); + assert_eq!(count(&conn, "agent_org_execution_runs"), 0); +} + +#[test] +fn finalization_and_background_history_inputs_retire_without_interpreting_execution_state() { + // These two branch heads have identical 39-table DDL, including the four + // changes that make the official old validator reject either version. + let schema = include_str!("../fixtures/background_history_agent_org.sql"); + let conn = database(); + seed_with_schema(&conn, schema); + assert_eq!( + old_fingerprint(&conn), + "d96f244c1ddb4293c82109cf8dc4ca0a41179f4aa464a22b81c69ffe65f9313c" + ); + conn.execute_batch( + "ALTER TABLE agent_org_runtime_runs ADD COLUMN intermediate_payload BLOB; + UPDATE agent_org_runtime_runs SET intermediate_payload=X'0001ff';", + ) + .unwrap(); + init_agent_org_schemas(&conn).unwrap(); + assert_eq!( + descriptor(&conn, "root").unwrap().unwrap().mode, + HistoryMode::HistoryOnly + ); + assert_eq!(count(&conn, "agent_org_execution_runs"), 0); + let blob: Vec = conn + .query_row( + "SELECT intermediate_payload FROM org_history_raw_1_agent_org_runtime_runs", + [], + |r| r.get(0), + ) + .unwrap(); + assert_eq!(blob, [0, 1, 255]); + assert!(page(&conn, "root", None, 100) + .unwrap() + .items + .iter() + .any(|i| i.content == "Saved report")); +} + +#[test] +fn completion_marker_with_all_execution_tables_missing_is_corruption_not_first_install() { + let conn = database(); + seed_old(&conn); + init_agent_org_schemas(&conn).unwrap(); + let names=conn.prepare("SELECT name FROM sqlite_master WHERE type='table' AND name LIKE 'agent_org_execution_%'").unwrap() + .query_map([],|r|r.get::<_,String>(0)).unwrap().collect::>>().unwrap(); + conn.execute_batch("PRAGMA foreign_keys=OFF").unwrap(); + for name in names { + conn.execute_batch(&format!("DROP TABLE {}", quoted(&name))) + .unwrap(); + } + let before = count(&conn, "org_history_schema_objects"); + assert!(init_agent_org_schemas(&conn).is_err()); + assert!(!table_exists(&conn, "agent_org_execution_runs").unwrap()); + assert_eq!(count(&conn, "org_history_schema_objects"), before); + assert_eq!(count(&conn, "org_history_sessions"), 2); +} + +#[test] +fn repeated_old_team_import_does_not_retire_current_members_or_rescan_archived_bodies() { + let conn = database(); + seed_old(&conn); + init_agent_org_schemas(&conn).unwrap(); + conn.execute_batch("INSERT INTO agent_sessions(session_id,name,status,created_at,updated_at,org_member_id) + VALUES ('current-member','Current member','running','now','now','alice'); + INSERT INTO agent_org_execution_runs + (id,org_id,coordinator_agent_id,root_session_id,entry_mode,status,created_at,updated_at) + VALUES ('current-run','org','coord','current-root','standalone_session','running','now','now'); + INSERT INTO agent_org_execution_member_materializations + (org_run_id,member_id,agent_id,generation,session_id,authority_class,status,created_at,updated_at) + VALUES ('current-run','alice','agent',1,'current-member','starting','succeeded','now','now'); + INSERT INTO agent_sessions(session_id,name,status,created_at,updated_at) + VALUES ('old-new','Downgrade team','idle','now','now'); + INSERT INTO agent_org_runtime_runs + (id,org_id,coordinator_agent_id,root_session_id,entry_mode,status,created_at,updated_at) + VALUES ('old-new-run','org','coord','old-new','standalone_session','idle','now','now');").unwrap(); + // Any attempt to scan/re-copy already archived bodies would now include this + // additional row; the next cutover owns only previously unimported sources. + event(&conn, "root", "after-retirement", "Not a new source", 2); + init_agent_org_schemas(&conn).unwrap(); + assert!(!is_history(&conn, "current-member").unwrap()); + assert!(is_history(&conn, "old-new").unwrap()); + assert!(!page(&conn, "root", None, 100) + .unwrap() + .items + .iter() + .any(|i| i.content == "Not a new source")); + assert_eq!(count(&conn, "agent_org_execution_runs"), 1); +} + +#[test] +fn large_archive_pages_use_keyset_index_and_normal_restart_writes_no_history() { + let conn = database(); + seed_old(&conn); + conn.execute_batch("BEGIN").unwrap(); + for n in 0..5000 { + event( + &conn, + "root", + &format!("large-{n}"), + &"x".repeat(1024), + n + 2, + ); + } + conn.execute_batch("COMMIT").unwrap(); + let start = std::time::Instant::now(); + init_agent_org_schemas(&conn).unwrap(); + let migration = start.elapsed(); + let changes = conn.total_changes(); + let start = std::time::Instant::now(); + for _ in 0..3 { + init_agent_org_schemas(&conn).unwrap(); + } + let restart = start.elapsed(); + assert_eq!(conn.total_changes(), changes); + let query_plan: String = conn + .query_row( + "EXPLAIN QUERY PLAN SELECT id FROM org_history_items + WHERE root_session_id=?1 AND (created_at,id)>(?2,?3) ORDER BY created_at,id LIMIT 51", + ["root", "2026-09-01", "item"], + |r| r.get(3), + ) + .unwrap(); + assert!(query_plan.contains("idx_org_history_items_page")); + let first = page(&conn, "root", None, 50).unwrap(); + assert_eq!(first.items.len(), 50); + assert!(first.next_cursor.is_some()); + eprintln!("5,000 KiB history: atomic import {migration:?}; three normal restarts {restart:?}; one page {} rows",first.items.len()); +} + +#[test] +fn two_initializers_archive_populated_database_exactly_once() { + let file = tempfile::NamedTempFile::new().unwrap(); + let conn = Connection::open(file.path()).unwrap(); + crate::foundation::persistence::test_schema::ensure_agent_sessions_schema(&conn); + crate::foundation::persistence::test_schema::ensure_session_events_schema(&conn); + conn.execute_batch("CREATE TABLE session_turn_intents(session_id TEXT,turn_intent_id TEXT,org_run_id TEXT,status TEXT);").unwrap(); + seed_old(&conn); + drop(conn); + let barrier = std::sync::Arc::new(std::sync::Barrier::new(2)); + let workers = (0..2) + .map(|_| { + let path = file.path().to_owned(); + let barrier = barrier.clone(); + std::thread::spawn(move || { + let conn = Connection::open(path).unwrap(); + conn.busy_timeout(std::time::Duration::from_secs(5)) + .unwrap(); + barrier.wait(); + init_agent_org_schemas(&conn).unwrap(); + }) + }) + .collect::>(); + for worker in workers { + worker.join().unwrap(); + } + let conn = Connection::open(file.path()).unwrap(); + assert_eq!(count(&conn, "org_history_archives"), 1); + assert_eq!(count(&conn, "org_history_sessions"), 2); + assert_eq!(count(&conn, "org_history_copies"), 2); + assert_eq!(count(&conn, "agent_org_execution_runs"), 0); +} diff --git a/src-tauri/crates/agent-core/src/core/coordination/agent_org_history_store/copies.rs b/src-tauri/crates/agent-core/src/core/coordination/agent_org_history_store/copies.rs new file mode 100644 index 0000000000..a48354d5b6 --- /dev/null +++ b/src-tauri/crates/agent-core/src/core/coordination/agent_org_history_store/copies.rs @@ -0,0 +1,372 @@ +//! Inert ordinary-session representations understood by official v2.0.8. +//! Called inside the source writer transaction; never invokes session/cloud hooks. +use rusqlite::{params, Connection, OptionalExtension}; +use serde_json::Value; + +use super::{stable_id, table_exists}; + +fn ensure_copy(conn: &Connection, source: &str) -> rusqlite::Result> { + if !table_exists(conn, "org_history_copies")? || !table_exists(conn, "agent_sessions")? { + return Ok(None); + } + let is_copy: bool = conn.query_row( + "SELECT EXISTS(SELECT 1 FROM org_history_copies WHERE copy_session_id=?1)", + [source], + |row| row.get(0), + )?; + if is_copy { + return Ok(None); + } + let existing = conn + .query_row( + "SELECT copy_session_id FROM org_history_copies WHERE source_session_id=?1", + [source], + |row| row.get::<_, String>(0), + ) + .optional()?; + if existing.is_some() { + return Ok(existing); + } + let retired: bool = conn.query_row( + "SELECT EXISTS(SELECT 1 FROM org_history_sessions WHERE session_id=?1)", + [source], + |row| row.get(0), + )?; + let current = if table_exists(conn, "agent_org_execution_runs")? { + conn.query_row( + "SELECT EXISTS(SELECT 1 FROM agent_org_execution_runs r WHERE r.root_session_id=?1) + OR EXISTS(SELECT 1 FROM agent_org_execution_member_materializations m WHERE m.session_id=?1)", + [source], |row| row.get::<_,bool>(0), + )? + } else { + false + }; + if !retired && !current { + return Ok(None); + } + let copy = format!( + "{}{}", + crate::definitions::prefix_lookup::SDE_SESSION_PREFIX, + stable_id("session", source) + ); + let inserted = conn.execute( + "INSERT OR IGNORE INTO agent_sessions + (session_id,name,status,user_input,created_at,updated_at,session_type) + SELECT ?2,CASE WHEN s.parent_session_id IS NOT NULL THEN + COALESCE((SELECT parent.name FROM agent_sessions parent WHERE parent.session_id=s.parent_session_id)||' · ','')||s.name + ELSE s.name END,'idle',s.user_input,s.created_at,s.updated_at,'sde' + FROM agent_sessions s WHERE s.session_id=?1", + params![source, copy], + )?; + if inserted == 0 { + return Ok(None); + } + conn.execute( + "INSERT INTO org_history_copies VALUES (?1,?2)", + params![source, copy], + )?; + Ok(Some(copy)) +} + +/// Persist only the changed event IDs. The original event writer owns atomicity. +pub fn mirror_events( + conn: &Connection, + session_id: &str, + event_ids: &[&str], +) -> rusqlite::Result<()> { + let Some(copy) = ensure_copy(conn, session_id)? else { + return Ok(()); + }; + for id in event_ids { + copy_event(conn, session_id, ©, id)?; + } + Ok(()) +} + +fn inert_json(raw: &str, copy_session: &str) -> String { + let Ok(mut value) = serde_json::from_str::(raw) else { + return raw.to_owned(); + }; + if let Some(object) = value.as_object_mut() { + // Direct user input remains visible after its execution provenance is + // removed. Internal scheduler inputs keep their existing hidden flag. + if object.get("agentOrgDirectSource").and_then(Value::as_bool) == Some(true) { + object.remove("syntheticUserInput"); + } + object.retain(|key, _| { + !key.starts_with("agent_org_") + && !key.starts_with("agentOrg") + && !matches!( + key.as_str(), + "turnIntentId" | "turn_intent_id" | "orgRunId" | "org_run_id" | "execution" + ) + }); + for key in ["sessionId", "session_id"] { + if object.contains_key(key) { + object.insert(key.into(), Value::String(copy_session.into())); + } + } + } + value.to_string() +} + +fn copy_event(conn: &Connection, source: &str, copy: &str, id: &str) -> rusqlite::Result<()> { + let mut stmt = conn.prepare_cached("SELECT * FROM events WHERE session_id=?1 AND id=?2")?; + let mut rows = stmt.query(params![source, id])?; + let Some(row) = rows.next()? else { + return Ok(()); + }; + let function: Option = row.get("function_name")?; + if function.as_deref() == Some("agent_org_execution") { + return Ok(()); + } + let result: String = row.get("result_json")?; + let meta: Option = row.get("meta_json")?; + let copy_event_id = stable_id("event", &format!("{source}:{id}")); + let fresh = !event_exists(conn, ©_event_id)?; + let changed=conn.execute( + "INSERT INTO events + (id,session_id,event_type,function_name,thread_id,args_json,result_json,content, + created_at,meta_json,history_sequence) + VALUES (?1,?2,?3,?4,NULL,?5,?6,?7,?8,?9,?10) + ON CONFLICT(id) DO UPDATE SET result_json=excluded.result_json, + args_json=excluded.args_json,content=excluded.content,meta_json=excluded.meta_json, + history_sequence=excluded.history_sequence + WHERE events.content IS NOT excluded.content OR events.result_json IS NOT excluded.result_json + OR events.args_json IS NOT excluded.args_json OR events.meta_json IS NOT excluded.meta_json + OR events.history_sequence IS NOT excluded.history_sequence", + params![ + copy_event_id, + copy, + row.get::<_, String>("event_type")?, + function, + inert_json(&row.get::<_, String>("args_json")?,copy), + inert_json(&result, copy), + row.get::<_, String>("content")?, + row.get::<_, String>("created_at")?, + meta.map(|raw| { + let mut value=serde_json::from_str::(&inert_json(&raw,copy)).unwrap_or(Value::Null); + if let Some(object)=value.as_object_mut() { object.insert("chunk_id".into(),Value::String(copy_event_id.clone())); } + value.to_string() + }), + row.get::<_, Option>("history_sequence")? + ], + )?; + if changed > 0 { + let time: String = row.get("created_at")?; + refresh_copy_cache(conn, copy, &time, fresh)?; + let value = serde_json::from_str::(&result).unwrap_or(Value::Null); + if value + .pointer("/agent_org_user_directed_reply/source_kind") + .and_then(Value::as_str) + == Some("group_mention") + { + // During the first v2.0.8 cutover, retired events are copied + // before the isolated execution schema is created. A saved group + // mention is still valid transcript history, but it cannot be + // projected through current-run tables that do not exist yet. + let run: Option = + if table_exists(conn, "agent_org_execution_member_materializations")? + && table_exists(conn, "agent_org_execution_runs")? + { + conn.query_row( + "SELECT m.org_run_id FROM agent_org_execution_member_materializations m + JOIN agent_org_execution_runs r ON r.id=m.org_run_id + WHERE m.session_id=?1 AND r.root_session_id<>?1 LIMIT 1", + [source], + |r| r.get(0), + ) + .optional()? + } else { + None + }; + if let Some(run) = run { + let content = value + .get("content") + .or_else(|| value.pointer("/message/content")) + .and_then(Value::as_str) + .unwrap_or_default(); + if !content.is_empty() { + mirror_visible_item(conn, &run, id, "group_reply", content, &time)?; + } + } + } + } + Ok(()) +} + +pub(super) fn backfill_retired(conn: &Connection) -> rusqlite::Result<()> { + if !table_exists(conn, "events")? { + return Ok(()); + } + let mut sessions = conn.prepare( + "SELECT session_id FROM org_history_sessions h WHERE NOT EXISTS + (SELECT 1 FROM org_history_copies c WHERE c.source_session_id=h.session_id)", + )?; + let sources = sessions + .query_map([], |row| row.get::<_, String>(0))? + .collect::>>()?; + for source in sources { + let Some(copy) = ensure_copy(conn, &source)? else { + continue; + }; + // Stream IDs from the existing session index: bounded memory even for + // large archives. Bodies are fetched and written one at a time. + let mut stmt = conn.prepare("SELECT id FROM events WHERE session_id=?1")?; + let mut rows = stmt.query([&source])?; + while let Some(row) = rows.next()? { + let id: String = row.get(0)?; + copy_event(conn, &source, ©, &id)?; + } + backfill_items(conn, &source)?; + } + Ok(()) +} + +fn backfill_items(conn: &Connection, source: &str) -> rusqlite::Result<()> { + let mut stmt = conn.prepare( + "SELECT i.id,i.content,i.created_at,c.copy_session_id,i.kind FROM org_history_items i + JOIN org_history_copies c ON c.source_session_id=i.root_session_id + WHERE i.root_session_id=?1 AND (i.kind<>'conversation' OR i.source_session_id<>i.root_session_id)", + )?; + let mut rows = stmt.query([source])?; + while let Some(row) = rows.next()? { + let id: String = row.get(0)?; + let content: String = row.get(1)?; + let kind: String = row.get(4)?; + let role = if matches!(kind.as_str(), "initial_input" | "member_input") { + "user" + } else { + "assistant" + }; + let result = serde_json::json!({"type":role,"content":content,"message":{"role":role,"content":content}}); + let event_id = stable_id("item-event", &id); + let copy: String = row.get(3)?; + let created_at: String = row.get(2)?; + let fresh = !event_exists(conn, &event_id)?; + conn.execute( + "INSERT OR IGNORE INTO events + (id,session_id,event_type,function_name,args_json,result_json,content,created_at) + VALUES (?1,?2,'raw','message','{}',?3,?4,?5)", + params![ + event_id, + row.get::<_, String>(3)?, + result.to_string(), + content, + row.get::<_, String>(2)? + ], + )?; + if fresh { + refresh_copy_cache(conn, ©, &created_at, true)?; + } + } + Ok(()) +} + +/// Incremental projection of content whose authoritative row is team-specific. +pub(crate) fn mirror_visible_item( + conn: &Connection, + run_id: &str, + source_id: &str, + kind: &str, + content: &str, + created_at: &str, +) -> rusqlite::Result<()> { + if !table_exists(conn, "org_history_copies")? { + return Ok(()); + } + let root: Option = conn + .query_row( + "SELECT root_session_id FROM agent_org_execution_runs WHERE id=?1", + [run_id], + |r| r.get(0), + ) + .optional()? + .flatten(); + let Some(root) = root else { + return Ok(()); + }; + let Some(copy) = ensure_copy(conn, &root)? else { + return Ok(()); + }; + let id = stable_id("visible", &format!("{run_id}:{kind}:{source_id}")); + conn.execute( + "INSERT INTO org_history_items (id,root_session_id,kind,content,created_at,source_json) + VALUES (?1,?2,?3,?4,?5,'{}') ON CONFLICT(id) DO UPDATE SET content=excluded.content WHERE org_history_items.content IS NOT excluded.content", + params![id, root, kind, content, created_at], + )?; + let role = if kind == "group_message" { + "user" + } else { + "assistant" + }; + let result = serde_json::json!({"type":role,"content":content,"message":{"role":role,"content":content}}); + let event_id = stable_id("visible-event", &id); + let fresh = !event_exists(conn, &event_id)?; + let changed=conn.execute( + "INSERT INTO events (id,session_id,event_type,function_name,args_json,result_json,content,created_at) + VALUES (?1,?2,'raw','message','{}',?3,?4,?5) + ON CONFLICT(id) DO UPDATE SET content=excluded.content,result_json=excluded.result_json WHERE events.content IS NOT excluded.content OR events.result_json IS NOT excluded.result_json", + params![event_id,copy,result.to_string(),content,created_at], + )?; + if changed > 0 { + refresh_copy_cache(conn, ©, created_at, fresh)?; + } + Ok(()) +} + +pub(crate) fn mirror_task_output( + conn: &Connection, + task: &super::super::agent_org_tasks::Task, +) -> Result<(), String> { + let Some(output) = task.output.as_ref() else { + return Ok(()); + }; + let text = match output.content.as_deref() { + Some(content) => format!("{}\n\n{}\n\n{}", task.subject, output.summary, content), + None => format!("{}\n\n{}", task.subject, output.summary), + }; + mirror_visible_item( + conn, + &task.org_run_id, + &task.id, + "output", + &text, + &output.produced_at, + ) + .map_err(|error| error.to_string()) +} + +fn event_exists(conn: &Connection, id: &str) -> rusqlite::Result { + conn.query_row( + "SELECT EXISTS(SELECT 1 FROM events WHERE id=?1)", + [id], + |r| r.get(0), + ) +} + +fn refresh_copy_cache( + conn: &Connection, + copy: &str, + time: &str, + fresh: bool, +) -> rusqlite::Result<()> { + if table_exists(conn, "sessions")? { + conn.execute("INSERT INTO sessions + (session_id,event_count,cached_at,content_revision,time_range_start,time_range_end) + VALUES (?1,?2,?3,1,?4,?4) + ON CONFLICT(session_id) DO UPDATE SET + event_count=sessions.event_count+excluded.event_count, + cached_at=excluded.cached_at,content_revision=sessions.content_revision+1, + time_range_start=MIN(COALESCE(sessions.time_range_start,excluded.time_range_start),excluded.time_range_start), + time_range_end=MAX(COALESCE(sessions.time_range_end,excluded.time_range_end),excluded.time_range_end)", + params![copy,i64::from(fresh),chrono::Utc::now().timestamp_millis(),time])?; + } + if table_exists(conn, "session_turn_index_state")? { + conn.execute( + "DELETE FROM session_turn_index_state WHERE session_id=?1", + [copy], + )?; + } + Ok(()) +} diff --git a/src-tauri/crates/agent-core/src/core/coordination/agent_org_history_store/mod.rs b/src-tauri/crates/agent-core/src/core/coordination/agent_org_history_store/mod.rs new file mode 100644 index 0000000000..f301f26772 --- /dev/null +++ b/src-tauri/crates/agent-core/src/core/coordination/agent_org_history_store/mod.rs @@ -0,0 +1,103 @@ +//! Historical identity and visible facts, deliberately independent of execution. +//! Raw archives are for recovery only; neither reads nor admissions execute them. + +mod archive; +mod capture; +mod copies; +mod read; + +use rusqlite::{Connection, OptionalExtension}; +use sha2::{Digest, Sha256}; + +pub use copies::mirror_events; +pub(crate) use copies::{mirror_task_output, mirror_visible_item}; +pub use read::{ + descriptor, page, require_current_run, HistoryDescriptor, HistoryMode, HistoryPage, +}; + +pub const READ_ONLY_ERROR: &str = "agent_org_history_read_only"; + +pub(super) fn cutover_complete(conn: &Connection) -> rusqlite::Result { + if !table_exists(conn, "org_history_state")? { + return Ok(false); + } + conn.query_row( + "SELECT EXISTS(SELECT 1 FROM org_history_state WHERE singleton=1)", + [], + |row| row.get(0), + ) +} + +pub(super) fn prepare_cutover(conn: &Connection, fresh: bool) -> rusqlite::Result<()> { + conn.execute_batch(include_str!("schema.sql"))?; + archive::retire_previous_execution(conn, fresh) +} + +pub(super) fn finish_cutover(conn: &Connection) -> rusqlite::Result<()> { + conn.execute("INSERT OR IGNORE INTO org_history_state VALUES (1,1)", [])?; + Ok(()) +} + +pub fn is_history(conn: &Connection, session_id: &str) -> rusqlite::Result { + if !table_exists(conn, "org_history_sessions")? { + return Ok(false); + } + conn.query_row( + "SELECT EXISTS(SELECT 1 FROM org_history_sessions WHERE session_id=?1) + OR EXISTS(SELECT 1 FROM org_history_copies WHERE copy_session_id=?1)", + [session_id], + |row| row.get(0), + ) +} + +pub fn require_writable(conn: &Connection, session_id: &str) -> Result<(), String> { + if is_history(conn, session_id).map_err(|error| error.to_string())? { + Err(READ_ONLY_ERROR.into()) + } else { + Ok(()) + } +} + +pub(crate) fn table_exists(conn: &Connection, table: &str) -> rusqlite::Result { + conn.query_row( + "SELECT EXISTS(SELECT 1 FROM sqlite_master WHERE type='table' AND name=?1)", + [table], + |row| row.get(0), + ) +} + +pub(super) fn quoted(name: &str) -> String { + format!("\"{}\"", name.replace('"', "\"\"")) +} + +pub(super) fn stable_id(kind: &str, source: &str) -> String { + format!("org-history-{kind}-{:x}", Sha256::digest(source.as_bytes())) +} + +pub(super) fn optional_text(row: &rusqlite::Row<'_>, column: &str) -> Option { + row.get::<_, Option>(column).ok().flatten() +} + +pub(super) fn root_for_run(conn: &Connection, run_id: &str) -> rusqlite::Result> { + conn.query_row( + "SELECT root_session_id FROM org_history_sessions + WHERE run_id=?1 AND root_session_id IS NOT NULL LIMIT 1", + [run_id], + |row| row.get(0), + ) + .optional() +} + +/// Resolve persisted history ownership before runtime loading or provider work. +pub async fn require_writable_session(session_id: &str) -> Result<(), String> { + let session_id = session_id.to_owned(); + tokio::task::spawn_blocking(move || { + let conn = database::db::get_connection().map_err(|error| error.to_string())?; + require_writable(&conn, &session_id) + }) + .await + .map_err(|error| error.to_string())? +} + +#[cfg(test)] +mod tests; diff --git a/src-tauri/crates/agent-core/src/core/coordination/agent_org_history_store/read.rs b/src-tauri/crates/agent-core/src/core/coordination/agent_org_history_store/read.rs new file mode 100644 index 0000000000..33298fc812 --- /dev/null +++ b/src-tauri/crates/agent-core/src/core/coordination/agent_org_history_store/read.rs @@ -0,0 +1,234 @@ +use base64::{engine::general_purpose::URL_SAFE_NO_PAD, Engine}; +use rusqlite::{params, Connection, OptionalExtension}; +use serde::{Deserialize, Serialize}; + +use super::{table_exists, READ_ONLY_ERROR}; + +#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)] +#[serde(rename_all = "snake_case")] +pub enum HistoryMode { + Current, + HistoryOnly, +} + +#[derive(Clone, Debug, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct HistoryMember { + pub session_id: String, + pub member_id: Option, + pub name: Option, +} + +#[derive(Clone, Debug, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct HistoryDescriptor { + pub mode: HistoryMode, + pub root_session_id: Option, + pub title: Option, + pub members: Vec, +} + +pub fn descriptor( + conn: &Connection, + session_id: &str, +) -> rusqlite::Result> { + if !table_exists(conn, "org_history_sessions")? { + return Ok(None); + } + let historical = conn + .query_row( + "SELECT root_session_id,title FROM org_history_sessions WHERE session_id=?1", + [session_id], + |row| { + Ok(( + row.get::<_, Option>(0)?, + row.get::<_, Option>(1)?, + )) + }, + ) + .optional()?; + if let Some((root, title)) = historical { + let mut stmt = conn.prepare( + "SELECT session_id,member_id,COALESCE(member_name,title) FROM org_history_sessions + WHERE COALESCE(root_session_id,session_id)=?1 ORDER BY session_id", + )?; + let members = stmt + .query_map([root.as_deref().unwrap_or(session_id)], |row| { + Ok(HistoryMember { + session_id: row.get(0)?, + member_id: row.get(1)?, + name: row.get(2)?, + }) + })? + .collect::>>()?; + return Ok(Some(HistoryDescriptor { + mode: HistoryMode::HistoryOnly, + root_session_id: root, + title, + members, + })); + } + if table_exists(conn, "agent_sessions")? { + let copy_title = conn + .query_row( + "SELECT s.name FROM org_history_copies c + JOIN agent_sessions s ON s.session_id=c.copy_session_id WHERE c.copy_session_id=?1", + [session_id], + |row| row.get::<_, String>(0), + ) + .optional()?; + if let Some(title) = copy_title { + return Ok(Some(HistoryDescriptor { + mode: HistoryMode::HistoryOnly, + root_session_id: Some(session_id.into()), + title: Some(title.clone()), + members: vec![HistoryMember { + session_id: session_id.into(), + member_id: None, + name: Some(title), + }], + })); + } + } + if !table_exists(conn, "agent_org_execution_runs")? { + return Ok(None); + } + let current = conn.query_row( + "SELECT r.id,r.root_session_id,s.name FROM agent_org_execution_runs r + LEFT JOIN agent_sessions s ON s.session_id=r.root_session_id + WHERE r.root_session_id=?1 OR EXISTS(SELECT 1 FROM agent_org_execution_member_materializations m + WHERE m.org_run_id=r.id AND m.session_id=?1) LIMIT 1", [session_id], + |row| Ok((row.get::<_,String>(0)?,row.get::<_,Option>(1)?,row.get::<_,Option>(2)?)), + ).optional()?; + if let Some((run, root, title)) = current { + let mut stmt = conn.prepare( + "SELECT m.session_id,m.member_id,s.name FROM agent_org_execution_member_materializations m + LEFT JOIN agent_sessions s ON s.session_id=m.session_id WHERE m.org_run_id=?1 ORDER BY m.member_id")?; + let members = stmt + .query_map([run], |row| { + Ok(HistoryMember { + session_id: row.get(0)?, + member_id: row.get(1)?, + name: row.get(2)?, + }) + })? + .collect::>>()?; + return Ok(Some(HistoryDescriptor { + mode: HistoryMode::Current, + root_session_id: root, + title, + members, + })); + } + Ok(None) +} + +#[derive(Clone, Debug, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct HistoryItem { + pub id: String, + pub source_session_id: Option, + pub kind: String, + pub content: String, + pub created_at: String, +} + +#[derive(Debug, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct HistoryPage { + pub items: Vec, + pub next_cursor: Option, +} + +#[derive(Serialize, Deserialize)] +struct Cursor { + session: String, + time: String, + id: String, +} + +pub fn page( + conn: &Connection, + session_id: &str, + cursor: Option<&str>, + limit: usize, +) -> Result { + let descriptor = descriptor(conn, session_id) + .map_err(|e| e.to_string())? + .filter(|value| matches!(value.mode, HistoryMode::HistoryOnly)) + .ok_or_else(|| "agent_org_history_not_found".to_string())?; + let root = descriptor.root_session_id.as_deref().unwrap_or(session_id); + let cursor = cursor + .map(|raw| { + if raw.len() > 2048 { + return Err("invalid_history_cursor".to_string()); + } + URL_SAFE_NO_PAD + .decode(raw) + .ok() + .and_then(|bytes| serde_json::from_slice::(&bytes).ok()) + .filter(|value| { + value.session == session_id && value.time.len() <= 96 && value.id.len() <= 512 + }) + .ok_or_else(|| "invalid_history_cursor".to_string()) + }) + .transpose()?; + let limit = limit.clamp(1, 100); + let time = cursor.as_ref().map(|c| c.time.as_str()).unwrap_or(""); + let id = cursor.as_ref().map(|c| c.id.as_str()).unwrap_or(""); + let mut stmt = conn + .prepare( + "SELECT id,source_session_id,kind,content,created_at FROM org_history_items + WHERE root_session_id=?1 AND (created_at,id)>(?2,?3) + ORDER BY created_at,id LIMIT ?4", + ) + .map_err(|e| e.to_string())?; + let mut items = stmt + .query_map(params![root, time, id, (limit + 1) as i64], |row| { + Ok(HistoryItem { + id: row.get(0)?, + source_session_id: row.get(1)?, + kind: row.get(2)?, + content: row.get(3)?, + created_at: row.get(4)?, + }) + }) + .map_err(|e| e.to_string())? + .collect::>>() + .map_err(|e| e.to_string())?; + let next_cursor = if items.len() > limit { + items.truncate(limit); + let last = &items[limit - 1]; + Some( + URL_SAFE_NO_PAD.encode( + serde_json::to_vec(&Cursor { + session: session_id.into(), + time: last.created_at.clone(), + id: last.id.clone(), + }) + .map_err(|e| e.to_string())?, + ), + ) + } else { + None + }; + Ok(HistoryPage { items, next_cursor }) +} + +pub fn require_current_run(conn: &Connection, run_id: &str) -> Result<(), String> { + if !table_exists(conn, "org_history_sessions").map_err(|e| e.to_string())? { + return Ok(()); + } + let retired: bool = conn + .query_row( + "SELECT EXISTS(SELECT 1 FROM org_history_sessions WHERE run_id=?1)", + [run_id], + |row| row.get(0), + ) + .map_err(|e| e.to_string())?; + if retired { + Err(READ_ONLY_ERROR.into()) + } else { + Ok(()) + } +} diff --git a/src-tauri/crates/agent-core/src/core/coordination/agent_org_history_store/schema.sql b/src-tauri/crates/agent-core/src/core/coordination/agent_org_history_store/schema.sql new file mode 100644 index 0000000000..adbea04a88 --- /dev/null +++ b/src-tauri/crates/agent-core/src/core/coordination/agent_org_history_store/schema.sql @@ -0,0 +1,52 @@ +CREATE TABLE IF NOT EXISTS org_history_state ( + singleton INTEGER PRIMARY KEY CHECK(singleton=1), + cutover_complete INTEGER NOT NULL CHECK(cutover_complete=1) +); +CREATE TABLE IF NOT EXISTS org_history_archives ( + id INTEGER PRIMARY KEY, + created_at TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP +); +CREATE TABLE IF NOT EXISTS org_history_schema_objects ( + archive_id INTEGER NOT NULL, + name TEXT NOT NULL, + object_type TEXT NOT NULL, + table_name TEXT NOT NULL, + original_sql TEXT, + raw_table TEXT, + PRIMARY KEY(archive_id, name) +); +CREATE TABLE IF NOT EXISTS org_history_sessions ( + session_id TEXT PRIMARY KEY, + root_session_id TEXT, + run_id TEXT, + member_id TEXT, + member_name TEXT, + title TEXT, + source_table TEXT NOT NULL, + original_status TEXT +); +CREATE INDEX IF NOT EXISTS idx_org_history_sessions_root + ON org_history_sessions(root_session_id, session_id); +CREATE INDEX IF NOT EXISTS idx_org_history_sessions_run + ON org_history_sessions(run_id, session_id); +CREATE TABLE IF NOT EXISTS org_history_items ( + id TEXT PRIMARY KEY, + root_session_id TEXT NOT NULL, + source_session_id TEXT, + kind TEXT NOT NULL, + content TEXT NOT NULL, + created_at TEXT NOT NULL, + source_json TEXT NOT NULL +); +CREATE INDEX IF NOT EXISTS idx_org_history_items_page + ON org_history_items(root_session_id, created_at, id); +CREATE TABLE IF NOT EXISTS org_history_copies ( + source_session_id TEXT PRIMARY KEY, + copy_session_id TEXT NOT NULL UNIQUE +); +-- Transcript provenance only: no wake, delivery or acknowledgement state. +CREATE TABLE IF NOT EXISTS org_history_inbox_messages ( + session_id TEXT NOT NULL, + message_id TEXT NOT NULL, + PRIMARY KEY(session_id,message_id) +); diff --git a/src-tauri/crates/agent-core/src/core/coordination/agent_org_history_store/tests.rs b/src-tauri/crates/agent-core/src/core/coordination/agent_org_history_store/tests.rs new file mode 100644 index 0000000000..f313d7076a --- /dev/null +++ b/src-tauri/crates/agent-core/src/core/coordination/agent_org_history_store/tests.rs @@ -0,0 +1,350 @@ +use rusqlite::{params, Connection}; +use sha2::{Digest, Sha256}; + +use super::*; +use crate::coordination::init_agent_org_schemas; + +fn database() -> Connection { + let conn = Connection::open_in_memory().unwrap(); + conn.execute_batch("PRAGMA foreign_keys=ON").unwrap(); + crate::foundation::persistence::test_schema::ensure_agent_sessions_schema(&conn); + conn.execute_batch("CREATE TABLE events ( + id TEXT PRIMARY KEY,session_id TEXT NOT NULL,event_type TEXT NOT NULL,function_name TEXT, + thread_id TEXT,args_json TEXT NOT NULL DEFAULT '{}',result_json TEXT NOT NULL DEFAULT '{}', + content TEXT NOT NULL DEFAULT '',created_at TEXT NOT NULL,meta_json TEXT,history_sequence INTEGER, + UNIQUE(id,session_id)); + CREATE INDEX idx_events_session_id ON events(session_id); + CREATE TABLE session_turn_intents(session_id TEXT,turn_intent_id TEXT,org_run_id TEXT,status TEXT);") + .unwrap(); + conn +} + +fn seed_old(conn: &Connection) { + seed_with_schema( + conn, + include_str!("../fixtures/official_v2_0_8_agent_org.sql"), + ); +} + +fn seed_with_schema(conn: &Connection, schema: &str) { + conn.execute_batch(schema).unwrap(); + conn.execute_batch("INSERT INTO agent_sessions(session_id,name,status,created_at,updated_at,org_member_id) + VALUES ('root','Original Team','running','2026-09-01','2026-09-01','coordinator'); + INSERT INTO agent_sessions(session_id,name,status,created_at,updated_at,org_member_id,parent_session_id) + VALUES ('member','Alice','running','2026-09-01','2026-09-01','alice','root'); + INSERT INTO agent_org_runtime_runs + (id,org_id,coordinator_agent_id,root_session_id,org_snapshot_json,entry_mode,status,created_at,updated_at) + VALUES ('run-old','org','coord','root','{\"orgName\":\"Original Team\",\"members\":[{\"id\":\"alice\",\"name\":\"Alice\"}]}', + 'standalone_session','running','2026-09-01','2026-09-01'); + INSERT INTO agent_org_runtime_member_materializations + (org_run_id,member_id,agent_id,generation,session_id,authority_class,status,created_at,updated_at) + VALUES ('run-old','alice','agent',1,'member','starting','succeeded','2026-09-01','2026-09-01'); + INSERT INTO session_turn_intents VALUES ('member','pending-turn','run-old','queued'); + INSERT INTO agent_org_runtime_inbox + (recipient_agent_id,recipient_member_id,sender_agent_id,org_run_id,payload_kind,payload_json,created_at) + VALUES ('agent','alice','_user','run-old','plain','{\"kind\":\"plain\",\"summary\":\"Question\",\"text\":\"Saved group question\"}', '2026-09-01');").unwrap(); + event(conn, "root", "report", "Saved report", 1); + event(conn, "member", "reply", "Saved member reply", 1); +} + +fn event(conn: &Connection, session: &str, id: &str, content: &str, sequence: i64) { + conn.execute("INSERT OR REPLACE INTO events + (id,session_id,event_type,function_name,result_json,content,created_at,history_sequence) + VALUES (?1,?2,'raw','message',?3,?4,'2026-09-01',?5)",params![id,session, + serde_json::json!({"message":{"content":content},"agent_org_execution":{"turn_intent_id":"pending-turn"},"turnIntentId":"pending-turn"}).to_string(),content,sequence]).unwrap(); +} + +fn count(conn: &Connection, table: &str) -> i64 { + conn.query_row( + &format!("SELECT COUNT(*) FROM {}", quoted(table)), + [], + |row| row.get(0), + ) + .unwrap() +} + +fn old_fingerprint(conn: &Connection) -> String { + // Exact v2.0.8 scanner and hashing algorithm, including SQL whitespace. + let mut stmt = conn + .prepare( + "SELECT type,name,tbl_name,sql FROM sqlite_master + WHERE sql IS NOT NULL AND type IN ('table','index','trigger') + AND (name LIKE 'agent_org_runtime_%' OR tbl_name LIKE 'agent_org_runtime_%') + ORDER BY type,name", + ) + .unwrap(); + let snapshot = stmt + .query_map([], |row| { + let kind: String = row.get(0)?; + let name: String = row.get(1)?; + let table: String = row.get(2)?; + let sql: String = row.get(3)?; + Ok(format!( + "{kind}|{name}|{table}|{:x}\n", + Sha256::digest(sql.trim().as_bytes()) + )) + }) + .unwrap() + .collect::>>() + .unwrap() + .concat(); + format!("{:x}", Sha256::digest(snapshot.as_bytes())) +} + +#[test] +fn official_old_validator_accepts_fixed_area_beside_new_objects_and_archives() { + let conn = database(); + seed_old(&conn); + let expected = "ca0b99fc4d60fe4a4d691c405114d7e48009b8b86fdeec78cf1a0f82998cd352"; + assert_eq!(old_fingerprint(&conn), expected); + init_agent_org_schemas(&conn).unwrap(); + assert_eq!(old_fingerprint(&conn), expected); + assert_eq!(count(&conn, "agent_org_runtime_runs"), 0); + assert_eq!(count(&conn, "agent_org_execution_runs"), 0); + assert_eq!(count(&conn, "org_history_sessions"), 2); + assert_eq!(count(&conn, "org_history_raw_1_agent_org_runtime_runs"), 1); + let original: String = conn + .query_row( + "SELECT status FROM org_history_raw_1_agent_org_runtime_runs", + [], + |r| r.get(0), + ) + .unwrap(); + assert_eq!( + original, "running", + "retirement must not fabricate a task/run outcome" + ); + assert_eq!( + require_writable(&conn, "root").unwrap_err(), + READ_ONLY_ERROR + ); + assert_eq!( + require_writable(&conn, "member").unwrap_err(), + READ_ONLY_ERROR + ); + assert_eq!( + require_current_run(&conn, "run-old").unwrap_err(), + READ_ONLY_ERROR + ); + let view = descriptor(&conn, "member").unwrap().unwrap(); + assert_eq!(view.root_session_id.as_deref(), Some("root")); + assert_eq!(view.members.len(), 2); + assert!(page(&conn, "root", None, 10) + .unwrap() + .items + .iter() + .any(|item| item.content == "Saved group question")); + let raw_active_objects: i64 = conn + .query_row( + "SELECT COUNT(*) FROM sqlite_master + WHERE tbl_name LIKE 'org_history_raw_%' AND type IN ('index','trigger')", + [], + |r| r.get(0), + ) + .unwrap(); + assert_eq!(raw_active_objects, 0); +} + +#[test] +fn official_old_group_mention_is_copied_before_execution_schema_exists() { + let conn = database(); + seed_old(&conn); + conn.execute( + "UPDATE events SET result_json=?2 WHERE id=?1", + params![ + "reply", + serde_json::json!({ + "message": {"content": "Saved member reply"}, + "agent_org_user_directed_reply": { + "source_kind": "group_mention", + "content": "Saved member reply" + } + }) + .to_string() + ], + ) + .unwrap(); + + init_agent_org_schemas(&conn).unwrap(); + + assert_eq!(count(&conn, "agent_org_execution_runs"), 0); + let copied: String = conn + .query_row( + "SELECT e.content FROM org_history_copies c + JOIN events e ON e.session_id=c.copy_session_id + WHERE c.source_session_id='member' AND e.content='Saved member reply'", + [], + |row| row.get(0), + ) + .unwrap(); + assert_eq!(copied, "Saved member reply"); +} + +#[test] +fn partial_old_tables_keep_shared_member_identity_and_body_without_inventing_a_run() { + let conn = database(); + seed_old(&conn); + conn.execute_batch( + "PRAGMA foreign_keys=OFF;DROP TABLE agent_org_runtime_runs; + DROP TABLE agent_org_runtime_member_materializations;PRAGMA foreign_keys=ON;", + ) + .unwrap(); + init_agent_org_schemas(&conn).unwrap(); + let view = descriptor(&conn, "member").unwrap().unwrap(); + assert_eq!(view.root_session_id.as_deref(), Some("root")); + assert_eq!(count(&conn, "agent_org_execution_runs"), 0); + let copy: String = conn + .query_row( + "SELECT copy_session_id FROM org_history_copies WHERE source_session_id='member'", + [], + |r| r.get(0), + ) + .unwrap(); + assert_eq!( + conn.query_row( + "SELECT content FROM events WHERE session_id=?1", + [copy], + |r| r.get::<_, String>(0) + ) + .unwrap(), + "Saved member reply" + ); + assert!(conn + .query_row( + "SELECT run_id FROM org_history_sessions WHERE session_id='member'", + [], + |r| r.get::<_, Option>(0) + ) + .unwrap() + .is_none()); +} + +#[test] +fn raw_schema_blobs_and_all_changes_roll_back_when_completion_write_fails() { + let conn = database(); + seed_old(&conn); + conn.execute_batch( + "CREATE TRIGGER reject_cutover BEFORE INSERT ON org_history_state + BEGIN SELECT RAISE(ABORT,'injected storage failure'); END;", + ) + .unwrap(); + assert!(init_agent_org_schemas(&conn).is_err()); + assert_eq!(count(&conn, "agent_org_runtime_runs"), 1); + assert!(!table_exists(&conn, "agent_org_execution_runs").unwrap()); + assert!(!table_exists(&conn, "org_history_raw_1_agent_org_runtime_runs").unwrap()); + assert_eq!(count(&conn, "org_history_sessions"), 0); + assert_eq!(count(&conn, "agent_sessions"), 2); + let enabled: bool = conn + .pragma_query_value(None, "foreign_keys", |r| r.get(0)) + .unwrap(); + assert!(enabled); + conn.execute_batch("DROP TRIGGER reject_cutover").unwrap(); + init_agent_org_schemas(&conn).unwrap(); +} + +#[test] +fn restarts_validate_without_recopying_or_resetting_current_teams() { + let conn = database(); + seed_old(&conn); + init_agent_org_schemas(&conn).unwrap(); + conn.execute_batch( + "INSERT INTO agent_org_execution_runs + (id,org_id,coordinator_agent_id,root_session_id,entry_mode,status,created_at,updated_at) + VALUES ('new-run','org','coord','new-root','standalone_session','running','now','now');", + ) + .unwrap(); + let events = count(&conn, "events"); + let raw = count(&conn, "org_history_schema_objects"); + for _ in 0..3 { + init_agent_org_schemas(&conn).unwrap(); + } + assert_eq!(count(&conn, "events"), events); + assert_eq!(count(&conn, "org_history_schema_objects"), raw); + assert_eq!(count(&conn, "agent_org_execution_runs"), 1); + assert!(require_writable(&conn, "new-root").is_ok()); + conn.execute_batch("DROP TABLE agent_org_execution_member_turn_admissions") + .unwrap(); + assert!(init_agent_org_schemas(&conn).is_err()); + assert_eq!(count(&conn, "agent_org_execution_runs"), 1); +} + +#[test] +fn downgrade_can_add_a_team_and_stale_intents_without_losing_copies_or_reimporting() { + let conn = database(); + seed_old(&conn); + init_agent_org_schemas(&conn).unwrap(); + let original_count = count(&conn, "events"); + conn.execute_batch("UPDATE session_turn_intents SET status='stale'; + INSERT INTO agent_sessions(session_id,name,status,created_at,updated_at) + VALUES ('old-new-root','Created in old app','idle','now','now'); + INSERT INTO agent_org_runtime_runs + (id,org_id,coordinator_agent_id,root_session_id,entry_mode,status,created_at,updated_at) + VALUES ('old-new-run','org','coord','old-new-root','standalone_session','idle','now','now');").unwrap(); + event( + &conn, + "old-new-root", + "old-new-event", + "Downgrade conversation", + 1, + ); + init_agent_org_schemas(&conn).unwrap(); + assert_eq!(count(&conn, "events"), original_count + 2); + assert_eq!(count(&conn, "org_history_sessions"), 3); + assert!(is_history(&conn, "old-new-root").unwrap()); + let sources = count(&conn, "org_history_schema_objects"); + init_agent_org_schemas(&conn).unwrap(); + assert_eq!(count(&conn, "org_history_schema_objects"), sources); + assert_eq!(count(&conn, "events"), original_count + 2); + assert_eq!(count(&conn, "agent_org_runtime_runs"), 0); +} + +#[test] +fn event_mirror_is_incremental_idempotent_and_strips_execution_identity() { + let conn = database(); + seed_old(&conn); + init_agent_org_schemas(&conn).unwrap(); + event(&conn, "member", "incremental", "Newly saved text", 2); + mirror_events(&conn, "member", &["incremental"]).unwrap(); + mirror_events(&conn, "member", &["incremental"]).unwrap(); + let copy: String = conn + .query_row( + "SELECT copy_session_id FROM org_history_copies WHERE source_session_id='member'", + [], + |r| r.get(0), + ) + .unwrap(); + let (rows,raw):(i64,String)=conn.query_row("SELECT COUNT(*),result_json FROM events WHERE session_id=?1 AND content='Newly saved text'",[©],|r|Ok((r.get(0)?,r.get(1)?))).unwrap(); + assert_eq!(rows, 1); + assert!(!raw.contains("turnIntentId")); + assert!(!raw.contains("agent_org_execution")); + assert_eq!(require_writable(&conn, ©).unwrap_err(), READ_ONLY_ERROR); + let detached:bool=conn.query_row("SELECT org_id IS NULL AND org_member_id IS NULL AND parent_session_id IS NULL AND work_item_id IS NULL FROM agent_sessions WHERE session_id=?1",[copy],|r|r.get(0)).unwrap(); + assert!(detached); +} + +#[test] +fn history_pages_are_bounded_stable_and_bound_to_the_requested_session() { + let conn = database(); + seed_old(&conn); + init_agent_org_schemas(&conn).unwrap(); + for id in 0..200 { + conn.execute("INSERT INTO org_history_items VALUES (?1,'root',NULL,'output','body','2026-09-02','{}')",[format!("item-{id:03}")]).unwrap(); + } + let first = page(&conn, "root", None, 25).unwrap(); + assert_eq!(first.items.len(), 25); + let second = page(&conn, "root", first.next_cursor.as_deref(), 25).unwrap(); + assert_eq!(second.items.len(), 25); + assert!(!second + .items + .iter() + .any(|item| first.items.iter().any(|prior| prior.id == item.id))); + assert!(page(&conn, "member", first.next_cursor.as_deref(), 25).is_err()); + assert_eq!( + page(&conn, "root", None, usize::MAX).unwrap().items.len(), + 100 + ); + assert!(page(&conn, "root", Some("garbage"), 25).is_err()); +} + +#[path = "conformance_tests.rs"] +mod conformance_tests; diff --git a/src-tauri/crates/agent-core/src/core/coordination/agent_org_ownership.rs b/src-tauri/crates/agent-core/src/core/coordination/agent_org_ownership.rs index 7aa88ba23e..1f366e7ce7 100644 --- a/src-tauri/crates/agent-core/src/core/coordination/agent_org_ownership.rs +++ b/src-tauri/crates/agent-core/src/core/coordination/agent_org_ownership.rs @@ -136,7 +136,7 @@ pub fn load_team_for_run(conn: &Connection, run_id: &str) -> Result = conn .query_row( "SELECT root_session_id,status,activation_generation,archived_at,archive_receipt_id - FROM agent_org_runtime_runs WHERE id=?1", + FROM agent_org_execution_runs WHERE id=?1", [run_id], |row| { Ok(AgentOrgRunOwnershipRow { @@ -174,7 +174,7 @@ pub fn load_team_for_run(conn: &Connection, run_id: &str) -> Result Result, String> { let mut statement = conn .prepare( - "SELECT id FROM agent_org_runtime_runs + "SELECT id FROM agent_org_execution_runs WHERE root_session_id=?1 ORDER BY id", ) .map_err(|error| error.to_string())?; @@ -211,7 +211,7 @@ fn load_owned_sessions( SELECT descendant.session_id,descendant.parent_session_id, descendant.org_member_id,descendant.status,descendant.depth, descendant.cycle, - (SELECT nested.id FROM agent_org_runtime_runs nested + (SELECT nested.id FROM agent_org_execution_runs nested WHERE nested.id<>?2 AND nested.root_session_id=descendant.session_id ORDER BY nested.id LIMIT 1), diff --git a/src-tauri/crates/agent-core/src/core/coordination/agent_org_pause.rs b/src-tauri/crates/agent-core/src/core/coordination/agent_org_pause.rs index 675d0aa3fd..40433a13ba 100644 --- a/src-tauri/crates/agent-core/src/core/coordination/agent_org_pause.rs +++ b/src-tauri/crates/agent-core/src/core/coordination/agent_org_pause.rs @@ -78,7 +78,7 @@ pub(crate) struct ContinuationDispatch { pub(super) fn create_schema(conn: &Connection) -> rusqlite::Result<()> { conn.execute_batch( - "CREATE TABLE IF NOT EXISTS agent_org_runtime_pause_episodes ( + "CREATE TABLE IF NOT EXISTS agent_org_execution_pause_episodes ( episode_id TEXT PRIMARY KEY CHECK(length(trim(episode_id)) > 0), org_run_id TEXT NOT NULL, pause_request_id TEXT NOT NULL CHECK(length(trim(pause_request_id)) > 0), @@ -92,7 +92,7 @@ pub(super) fn create_schema(conn: &Connection) -> rusqlite::Result<()> { resumed_at TEXT, UNIQUE(org_run_id, pause_request_id), UNIQUE(resume_request_id), - FOREIGN KEY(org_run_id) REFERENCES agent_org_runtime_runs(id) ON DELETE CASCADE, + FOREIGN KEY(org_run_id) REFERENCES agent_org_execution_runs(id) ON DELETE CASCADE, CHECK( (status='active' AND resume_request_id IS NULL AND resume_generation IS NULL AND resumed_at IS NULL) @@ -102,18 +102,18 @@ pub(super) fn create_schema(conn: &Connection) -> rusqlite::Result<()> { AND resumed_at IS NOT NULL) ) ); - CREATE UNIQUE INDEX IF NOT EXISTS idx_agent_org_runtime_pause_one_active - ON agent_org_runtime_pause_episodes(org_run_id) + CREATE UNIQUE INDEX IF NOT EXISTS idx_agent_org_execution_pause_one_active + ON agent_org_execution_pause_episodes(org_run_id) WHERE status='active'; - CREATE INDEX IF NOT EXISTS idx_agent_org_runtime_pause_request - ON agent_org_runtime_pause_episodes(org_run_id, pause_request_id); - CREATE INDEX IF NOT EXISTS idx_agent_org_runtime_pause_public_timeline - ON agent_org_runtime_pause_episodes(org_run_id, created_at, episode_id); - CREATE INDEX IF NOT EXISTS idx_agent_org_runtime_resume_public_timeline - ON agent_org_runtime_pause_episodes(org_run_id, resumed_at, episode_id) + CREATE INDEX IF NOT EXISTS idx_agent_org_execution_pause_request + ON agent_org_execution_pause_episodes(org_run_id, pause_request_id); + CREATE INDEX IF NOT EXISTS idx_agent_org_execution_pause_public_timeline + ON agent_org_execution_pause_episodes(org_run_id, created_at, episode_id); + CREATE INDEX IF NOT EXISTS idx_agent_org_execution_resume_public_timeline + ON agent_org_execution_pause_episodes(org_run_id, resumed_at, episode_id) WHERE resumed_at IS NOT NULL; - CREATE TABLE IF NOT EXISTS agent_org_runtime_pause_handoffs ( + CREATE TABLE IF NOT EXISTS agent_org_execution_pause_handoffs ( handoff_id TEXT PRIMARY KEY CHECK(length(trim(handoff_id)) > 0), episode_id TEXT NOT NULL, org_run_id TEXT NOT NULL, @@ -141,10 +141,10 @@ pub(super) fn create_schema(conn: &Connection) -> rusqlite::Result<()> { updated_at TEXT NOT NULL, UNIQUE(episode_id, session_id, original_turn_intent_id), UNIQUE(continuation_turn_intent_id), - FOREIGN KEY(episode_id) REFERENCES agent_org_runtime_pause_episodes(episode_id) ON DELETE CASCADE, - FOREIGN KEY(org_run_id) REFERENCES agent_org_runtime_runs(id) ON DELETE CASCADE, + FOREIGN KEY(episode_id) REFERENCES agent_org_execution_pause_episodes(episode_id) ON DELETE CASCADE, + FOREIGN KEY(org_run_id) REFERENCES agent_org_execution_runs(id) ON DELETE CASCADE, FOREIGN KEY(session_id, original_turn_intent_id) - REFERENCES agent_org_runtime_turn_contexts(session_id, turn_intent_id) + REFERENCES agent_org_execution_turn_contexts(session_id, turn_intent_id) ON DELETE CASCADE, CHECK( (turn_kind='coordinator' AND task_id IS NULL AND original_owner_member_id IS NULL) @@ -166,15 +166,15 @@ pub(super) fn create_schema(conn: &Connection) -> rusqlite::Result<()> { (continuation_status='skipped' AND skip_reason IS NOT NULL) ) ); - CREATE INDEX IF NOT EXISTS idx_agent_org_runtime_pause_capture - ON agent_org_runtime_turn_contexts( + CREATE INDEX IF NOT EXISTS idx_agent_org_execution_pause_capture + ON agent_org_execution_turn_contexts( org_run_id, activation_generation, turn_kind, session_id, turn_intent_id ) WHERE turn_kind IN ('coordinator','task_execution'); - CREATE INDEX IF NOT EXISTS idx_agent_org_runtime_pause_drain - ON agent_org_runtime_pause_handoffs(episode_id, drain_status, session_id); - CREATE INDEX IF NOT EXISTS idx_agent_org_runtime_pause_dispatch - ON agent_org_runtime_pause_handoffs(continuation_status, org_run_id, session_id);", + CREATE INDEX IF NOT EXISTS idx_agent_org_execution_pause_drain + ON agent_org_execution_pause_handoffs(episode_id, drain_status, session_id); + CREATE INDEX IF NOT EXISTS idx_agent_org_execution_pause_dispatch + ON agent_org_execution_pause_handoffs(continuation_status, org_run_id, session_id);", ) } @@ -200,7 +200,7 @@ pub(crate) fn pause_run_commit(run_id: &str, request_id: &str) -> Result = tx .query_row( - "SELECT status, activation_generation FROM agent_org_runtime_runs WHERE id=?1", + "SELECT status, activation_generation FROM agent_org_execution_runs WHERE id=?1", [run_id], |row| Ok((row.get(0)?, row.get(1)?)), ) @@ -240,7 +240,7 @@ pub(crate) fn pause_run_commit(run_id: &str, request_id: &str) -> Result Result Result Result Result Result)> = tx .query_row( "SELECT status,activation_generation,root_session_id - FROM agent_org_runtime_runs WHERE id=?1", + FROM agent_org_execution_runs WHERE id=?1", [run_id], |row| Ok((row.get(0)?, row.get(1)?, row.get(2)?)), ) @@ -430,7 +430,7 @@ pub fn resume_run(run_id: &str, request_id: &str) -> Result = tx .query_row( "SELECT episode_id,pause_generation - FROM agent_org_runtime_pause_episodes + FROM agent_org_execution_pause_episodes WHERE org_run_id=?1 AND status='active'", [run_id], |row| Ok((row.get(0)?, row.get(1)?)), @@ -453,7 +453,7 @@ pub fn resume_run(run_id: &str, request_id: &str) -> Result Result Result Result Result { conn.query_row( "SELECT EXISTS( - SELECT 1 FROM agent_org_runtime_member_materializations materialization + SELECT 1 FROM agent_org_execution_member_materializations materialization JOIN agent_sessions session ON session.session_id=materialization.session_id WHERE materialization.org_run_id=?1 @@ -609,7 +609,7 @@ fn continuation_skip_reason( AND session.agent_definition_id=materialization.agent_id AND session.org_member_id=materialization.member_id AND NOT EXISTS ( - SELECT 1 FROM agent_org_runtime_member_materializations newer + SELECT 1 FROM agent_org_execution_member_materializations newer WHERE newer.org_run_id=materialization.org_run_id AND newer.member_id=materialization.member_id AND newer.status='succeeded' @@ -642,7 +642,7 @@ fn continuation_skip_reason( .ok_or_else(|| "Task handoff has no owner".to_string())?; let task: Option<(String, Option)> = conn .query_row( - "SELECT status,owner FROM agent_org_runtime_tasks WHERE org_run_id=?1 AND id=?2", + "SELECT status,owner FROM agent_org_execution_tasks WHERE org_run_id=?1 AND id=?2", params![run_id, task_id], |row| Ok((row.get(0)?, row.get(1)?)), ) @@ -694,12 +694,12 @@ fn resolve_terminal_task_assignment_after_resume_skip( .ok_or_else(|| "terminal Task handoff has no owner".to_string())?; let resolution_reason = format!("pause_resume_{skip_reason}"); conn.execute( - "INSERT OR IGNORE INTO agent_org_runtime_inbox_delivery_resolutions ( + "INSERT OR IGNORE INTO agent_org_execution_inbox_delivery_resolutions ( inbox_id,org_run_id,resolution_kind,resolved_by_member_id,reason, replacement_inbox_id,replacement_task_id,created_at ) SELECT inbox.id,inbox.org_run_id,'cancelled','coordinator',?4,NULL,NULL,?5 - FROM agent_org_runtime_inbox inbox + FROM agent_org_execution_inbox inbox WHERE inbox.org_run_id=?1 AND inbox.recipient_member_id=?2 AND inbox.delivery_class='formal_work' @@ -710,10 +710,10 @@ fn resolve_terminal_task_assignment_after_resume_skip( ) .map_err(|error| error.to_string())?; conn.execute( - "DELETE FROM agent_org_runtime_inbox_materializations + "DELETE FROM agent_org_execution_inbox_materializations WHERE inbox_id IN ( SELECT resolution.inbox_id - FROM agent_org_runtime_inbox_delivery_resolutions resolution + FROM agent_org_execution_inbox_delivery_resolutions resolution WHERE resolution.org_run_id=?1 AND resolution.resolution_kind='cancelled' AND resolution.reason=?2 @@ -733,8 +733,8 @@ pub(crate) fn list_running_handoffs( .prepare( "SELECT handoff.episode_id,handoff.org_run_id,handoff.session_id, handoff.original_turn_intent_id - FROM agent_org_runtime_pause_handoffs handoff - JOIN agent_org_runtime_pause_episodes episode + FROM agent_org_execution_pause_handoffs handoff + JOIN agent_org_execution_pause_episodes episode ON episode.episode_id=handoff.episode_id WHERE handoff.episode_id=?1 AND episode.teardown_owner_id=?2 AND handoff.original_intent_status='running' @@ -769,7 +769,7 @@ pub(crate) fn bind_runtime_and_request_yield( database::db::with_sessions_writer(|| { let conn = database::db::get_connection().map_err(|error| error.to_string())?; conn.execute( - "UPDATE agent_org_runtime_pause_handoffs + "UPDATE agent_org_execution_pause_handoffs SET runtime_lease_id=?4,dialog_turn_generation=?5,yield_requested_at=?6,updated_at=?6 WHERE episode_id=?1 AND session_id=?2 AND original_turn_intent_id=?3 AND drain_status='waiting' AND runtime_lease_id IS NULL", @@ -796,7 +796,7 @@ pub(crate) fn mark_runtime_absent( database::db::with_sessions_writer(|| { let conn = database::db::get_connection().map_err(|error| error.to_string())?; conn.execute( - "UPDATE agent_org_runtime_pause_handoffs + "UPDATE agent_org_execution_pause_handoffs SET drain_status='runtime_absent',released_at=?4,updated_at=?4 WHERE episode_id=?1 AND session_id=?2 AND original_turn_intent_id=?3 AND drain_status IN ('waiting','timed_out') AND runtime_lease_id IS NULL", @@ -817,7 +817,7 @@ pub(crate) fn mark_released( database::db::with_sessions_writer(|| { let conn = database::db::get_connection().map_err(|error| error.to_string())?; conn.query_row( - "UPDATE agent_org_runtime_pause_handoffs + "UPDATE agent_org_execution_pause_handoffs SET drain_status='released',released_at=?5,updated_at=?5 WHERE session_id=?1 AND original_turn_intent_id=?2 AND runtime_lease_id=?3 AND dialog_turn_generation=?4 @@ -845,7 +845,7 @@ pub(crate) fn bound_episode_for_runtime( ) -> Result, String> { let conn = database::db::get_connection().map_err(|error| error.to_string())?; conn.query_row( - "SELECT episode_id FROM agent_org_runtime_pause_handoffs + "SELECT episode_id FROM agent_org_execution_pause_handoffs WHERE session_id=?1 AND original_turn_intent_id=?2 AND runtime_lease_id=?3 AND dialog_turn_generation=?4 AND drain_status IN ('waiting','timed_out') @@ -867,7 +867,7 @@ pub(crate) fn mark_unresolved_timed_out(episode_id: &str) -> Result Result)> = conn .query_row( "SELECT handoff.turn_kind,handoff.task_id - FROM agent_org_runtime_pause_handoffs handoff - JOIN agent_org_runtime_pause_episodes episode + FROM agent_org_execution_pause_handoffs handoff + JOIN agent_org_execution_pause_episodes episode ON episode.episode_id=handoff.episode_id - JOIN agent_org_runtime_runs run ON run.id=handoff.org_run_id + JOIN agent_org_execution_runs run ON run.id=handoff.org_run_id JOIN session_turn_intents intent ON intent.session_id=handoff.session_id AND intent.turn_intent_id=handoff.continuation_turn_intent_id @@ -1028,7 +1028,7 @@ pub(crate) fn claim_continuation_dispatch( database::db::with_sessions_writer(|| { let conn = database::db::get_connection().map_err(|error| error.to_string())?; conn.execute( - "UPDATE agent_org_runtime_pause_handoffs + "UPDATE agent_org_execution_pause_handoffs SET continuation_status='dispatched',updated_at=?3 WHERE episode_id=?1 AND continuation_turn_intent_id=?2 AND continuation_status='queued'", @@ -1049,13 +1049,13 @@ pub(crate) fn requeue_continuation_dispatch( database::db::with_sessions_writer(|| { let conn = database::db::get_connection().map_err(|error| error.to_string())?; conn.execute( - "UPDATE agent_org_runtime_pause_handoffs + "UPDATE agent_org_execution_pause_handoffs SET continuation_status='queued',updated_at=?3 WHERE episode_id=?1 AND continuation_turn_intent_id=?2 AND continuation_status='dispatched' AND EXISTS ( SELECT 1 FROM session_turn_intents intent - WHERE intent.session_id=agent_org_runtime_pause_handoffs.session_id + WHERE intent.session_id=agent_org_execution_pause_handoffs.session_id AND intent.turn_intent_id=?2 AND intent.status='queued' )", params![episode_id, turn_intent_id, chrono::Utc::now().to_rfc3339()], @@ -1073,7 +1073,7 @@ pub(crate) fn reconcile_runtime_absence_after_restart(conn: &Connection) -> Resu let tx = database::db::begin_immediate(conn).map_err(|error| error.to_string())?; let runtime_rows = tx .execute( - "UPDATE agent_org_runtime_pause_handoffs + "UPDATE agent_org_execution_pause_handoffs SET drain_status='runtime_absent',released_at=COALESCE(released_at,?1),updated_at=?1 WHERE drain_status IN ('waiting','timed_out')", [&now], @@ -1089,10 +1089,10 @@ pub(crate) fn reconcile_runtime_absence_after_restart(conn: &Connection) -> Resu SET status='queued',updated_at=?1 WHERE intent.status='running' AND EXISTS ( - SELECT 1 FROM agent_org_runtime_pause_handoffs handoff - JOIN agent_org_runtime_pause_episodes episode + SELECT 1 FROM agent_org_execution_pause_handoffs handoff + JOIN agent_org_execution_pause_episodes episode ON episode.episode_id=handoff.episode_id - JOIN agent_org_runtime_runs run ON run.id=handoff.org_run_id + JOIN agent_org_execution_runs run ON run.id=handoff.org_run_id WHERE handoff.session_id=intent.session_id AND handoff.continuation_turn_intent_id=intent.turn_intent_id AND handoff.continuation_status='dispatched' @@ -1104,13 +1104,13 @@ pub(crate) fn reconcile_runtime_absence_after_restart(conn: &Connection) -> Resu .map_err(|error| error.to_string())?; let dispatch_rows = tx .execute( - "UPDATE agent_org_runtime_pause_handoffs + "UPDATE agent_org_execution_pause_handoffs SET continuation_status='queued',updated_at=?1 WHERE continuation_status='dispatched' AND EXISTS ( SELECT 1 FROM session_turn_intents intent - WHERE intent.session_id=agent_org_runtime_pause_handoffs.session_id - AND intent.turn_intent_id=agent_org_runtime_pause_handoffs.continuation_turn_intent_id + WHERE intent.session_id=agent_org_execution_pause_handoffs.session_id + AND intent.turn_intent_id=agent_org_execution_pause_handoffs.continuation_turn_intent_id AND intent.status='queued' )", [&now], @@ -1132,7 +1132,7 @@ fn active_pause_outcome( ) -> Result, String> { let request_id: Option = conn .query_row( - "SELECT pause_request_id FROM agent_org_runtime_pause_episodes + "SELECT pause_request_id FROM agent_org_execution_pause_episodes WHERE org_run_id=?1 AND status='active'", [run_id], |row| row.get(0), @@ -1156,8 +1156,8 @@ fn pause_outcome_for_request( COUNT(handoff.handoff_id), COALESCE(SUM(CASE WHEN handoff.drain_status IN ('waiting','timed_out') THEN 1 ELSE 0 END),0), COALESCE(SUM(CASE WHEN handoff.drain_timeout_at IS NOT NULL THEN 1 ELSE 0 END),0) - FROM agent_org_runtime_pause_episodes episode - LEFT JOIN agent_org_runtime_pause_handoffs handoff ON handoff.episode_id=episode.episode_id + FROM agent_org_execution_pause_episodes episode + LEFT JOIN agent_org_execution_pause_handoffs handoff ON handoff.episode_id=episode.episode_id WHERE episode.org_run_id=?1 AND episode.pause_request_id=?2 GROUP BY episode.episode_id,episode.pause_generation", params![run_id, request_id], @@ -1188,8 +1188,8 @@ fn resume_outcome_for_request( "SELECT episode.episode_id,episode.resume_generation, COALESCE(SUM(CASE WHEN handoff.continuation_status IN ('queued','dispatched') THEN 1 ELSE 0 END),0), COALESCE(SUM(CASE WHEN handoff.continuation_status='skipped' THEN 1 ELSE 0 END),0) - FROM agent_org_runtime_pause_episodes episode - LEFT JOIN agent_org_runtime_pause_handoffs handoff ON handoff.episode_id=episode.episode_id + FROM agent_org_execution_pause_episodes episode + LEFT JOIN agent_org_execution_pause_handoffs handoff ON handoff.episode_id=episode.episode_id WHERE episode.org_run_id=?1 AND episode.resume_request_id=?2 GROUP BY episode.episode_id,episode.resume_generation", params![run_id, request_id], diff --git a/src-tauri/crates/agent-core/src/core/coordination/agent_org_pause/turn_authority.rs b/src-tauri/crates/agent-core/src/core/coordination/agent_org_pause/turn_authority.rs index c858b2fe78..662ffe6ec2 100644 --- a/src-tauri/crates/agent-core/src/core/coordination/agent_org_pause/turn_authority.rs +++ b/src-tauri/crates/agent-core/src/core/coordination/agent_org_pause/turn_authority.rs @@ -9,10 +9,10 @@ pub(crate) fn claimed_continuation_in_tx( ) -> Result { conn.query_row( "SELECT EXISTS( - SELECT 1 FROM agent_org_runtime_pause_handoffs handoff - JOIN agent_org_runtime_pause_episodes episode USING(episode_id) - JOIN agent_org_runtime_runs run ON run.id=handoff.org_run_id - JOIN agent_org_runtime_turn_contexts context + SELECT 1 FROM agent_org_execution_pause_handoffs handoff + JOIN agent_org_execution_pause_episodes episode USING(episode_id) + JOIN agent_org_execution_runs run ON run.id=handoff.org_run_id + JOIN agent_org_execution_turn_contexts context ON context.session_id=handoff.session_id AND context.turn_intent_id=handoff.continuation_turn_intent_id JOIN session_turn_intents intent @@ -43,13 +43,13 @@ pub(crate) fn released_execution_in_tx( ) -> Result { conn.query_row( "SELECT EXISTS( - SELECT 1 FROM agent_org_runtime_turn_contexts context + SELECT 1 FROM agent_org_execution_turn_contexts context JOIN session_turn_intents intent ON intent.session_id=context.session_id AND intent.turn_intent_id=context.turn_intent_id - JOIN agent_org_runtime_pause_episodes episode + JOIN agent_org_execution_pause_episodes episode ON episode.org_run_id=context.org_run_id AND episode.pause_generation=context.activation_generation+1 - JOIN agent_org_runtime_pause_handoffs handoff + JOIN agent_org_execution_pause_handoffs handoff ON handoff.episode_id=episode.episode_id AND handoff.session_id=context.session_id AND handoff.original_turn_intent_id=context.turn_intent_id WHERE context.session_id=?1 AND context.turn_intent_id=?2 diff --git a/src-tauri/crates/agent-core/src/core/coordination/agent_org_plan_approvals/artifact.rs b/src-tauri/crates/agent-core/src/core/coordination/agent_org_plan_approvals/artifact.rs index 76e676872b..b1a300c540 100644 --- a/src-tauri/crates/agent-core/src/core/coordination/agent_org_plan_approvals/artifact.rs +++ b/src-tauri/crates/agent-core/src/core/coordination/agent_org_plan_approvals/artifact.rs @@ -411,7 +411,7 @@ pub(super) fn list_distinct_plan_paths_after( let mut stmt = conn .prepare( "SELECT DISTINCT plan_path - FROM agent_org_runtime_plan_revisions + FROM agent_org_execution_plan_revisions WHERE (?1 IS NULL OR plan_path > ?1) ORDER BY plan_path ASC LIMIT ?2", diff --git a/src-tauri/crates/agent-core/src/core/coordination/agent_org_plan_approvals/mod.rs b/src-tauri/crates/agent-core/src/core/coordination/agent_org_plan_approvals/mod.rs index 1b74e958b2..f9fea5b2ba 100644 --- a/src-tauri/crates/agent-core/src/core/coordination/agent_org_plan_approvals/mod.rs +++ b/src-tauri/crates/agent-core/src/core/coordination/agent_org_plan_approvals/mod.rs @@ -178,7 +178,7 @@ pub fn init_schema(conn: &Connection) -> rusqlite::Result<()> { pub(crate) fn create_schema(conn: &Connection) -> rusqlite::Result<()> { conn.execute_batch( - "CREATE TABLE IF NOT EXISTS agent_org_runtime_plan_revisions ( + "CREATE TABLE IF NOT EXISTS agent_org_execution_plan_revisions ( plan_revision_id TEXT PRIMARY KEY, org_run_id TEXT NOT NULL, source_task_id TEXT NOT NULL, @@ -194,27 +194,27 @@ pub(crate) fn create_schema(conn: &Connection) -> rusqlite::Result<()> { content_digest TEXT NOT NULL CHECK(length(content_digest)=64), created_at TEXT NOT NULL, UNIQUE(org_run_id, source_task_id, revision_number), - FOREIGN KEY(org_run_id) REFERENCES agent_org_runtime_runs(id) ON DELETE CASCADE, + FOREIGN KEY(org_run_id) REFERENCES agent_org_execution_runs(id) ON DELETE CASCADE, FOREIGN KEY(previous_plan_revision_id) - REFERENCES agent_org_runtime_plan_revisions(plan_revision_id) + REFERENCES agent_org_execution_plan_revisions(plan_revision_id) ); - CREATE TRIGGER IF NOT EXISTS trg_agent_org_runtime_plan_revisions_immutable - BEFORE UPDATE ON agent_org_runtime_plan_revisions + CREATE TRIGGER IF NOT EXISTS trg_agent_org_execution_plan_revisions_immutable + BEFORE UPDATE ON agent_org_execution_plan_revisions BEGIN SELECT RAISE(ABORT, 'agent_org_plan_revision_immutable'); END; - CREATE INDEX IF NOT EXISTS idx_agent_org_runtime_plan_revisions_run_task - ON agent_org_runtime_plan_revisions( + CREATE INDEX IF NOT EXISTS idx_agent_org_execution_plan_revisions_run_task + ON agent_org_execution_plan_revisions( org_run_id, source_task_id, revision_number DESC ); - CREATE INDEX IF NOT EXISTS idx_agent_org_runtime_plan_revisions_path - ON agent_org_runtime_plan_revisions(plan_path, created_at DESC); - CREATE INDEX IF NOT EXISTS idx_agent_org_runtime_plan_revisions_source_session_turn - ON agent_org_runtime_plan_revisions( + CREATE INDEX IF NOT EXISTS idx_agent_org_execution_plan_revisions_path + ON agent_org_execution_plan_revisions(plan_path, created_at DESC); + CREATE INDEX IF NOT EXISTS idx_agent_org_execution_plan_revisions_source_session_turn + ON agent_org_execution_plan_revisions( source_session_id, source_turn_intent_id, created_at ); - CREATE TABLE IF NOT EXISTS agent_org_runtime_plan_decisions ( + CREATE TABLE IF NOT EXISTS agent_org_execution_plan_decisions ( approval_id TEXT PRIMARY KEY, plan_revision_id TEXT NOT NULL UNIQUE, request_id TEXT NOT NULL UNIQUE, @@ -229,7 +229,7 @@ pub(crate) fn create_schema(conn: &Connection) -> rusqlite::Result<()> { created_at TEXT NOT NULL, resolved_at TEXT, FOREIGN KEY(plan_revision_id) - REFERENCES agent_org_runtime_plan_revisions(plan_revision_id) + REFERENCES agent_org_execution_plan_revisions(plan_revision_id) ON DELETE CASCADE, CHECK( (status='pending' AND decision_by IS NULL AND resolved_at IS NULL) @@ -237,8 +237,8 @@ pub(crate) fn create_schema(conn: &Connection) -> rusqlite::Result<()> { (status!='pending' AND decision_by IS NOT NULL AND resolved_at IS NOT NULL) ) ); - CREATE INDEX IF NOT EXISTS idx_agent_org_runtime_plan_decisions_status - ON agent_org_runtime_plan_decisions(status, created_at, approval_id);", + CREATE INDEX IF NOT EXISTS idx_agent_org_execution_plan_decisions_status + ON agent_org_execution_plan_decisions(status, created_at, approval_id);", )?; Ok(()) } diff --git a/src-tauri/crates/agent-core/src/core/coordination/agent_org_plan_approvals/persistence.rs b/src-tauri/crates/agent-core/src/core/coordination/agent_org_plan_approvals/persistence.rs index ea66f2baf0..29a060db53 100644 --- a/src-tauri/crates/agent-core/src/core/coordination/agent_org_plan_approvals/persistence.rs +++ b/src-tauri/crates/agent-core/src/core/coordination/agent_org_plan_approvals/persistence.rs @@ -22,7 +22,7 @@ pub(super) fn insert_record( revision: &AgentOrgPlanRevision, ) -> Result<(), String> { conn.execute( - "INSERT INTO agent_org_runtime_plan_revisions ( + "INSERT INTO agent_org_execution_plan_revisions ( plan_revision_id,org_run_id,source_task_id,source_member_id, source_session_id,source_turn_intent_id,root_session_id, revision_number,previous_plan_revision_id,plan_title,plan_path, @@ -47,7 +47,7 @@ pub(super) fn insert_record( ) .map_err(|err| err.to_string())?; conn.execute( - "INSERT INTO agent_org_runtime_plan_decisions ( + "INSERT INTO agent_org_execution_plan_decisions ( approval_id,plan_revision_id,request_id,policy,status,decision_by, feedback,created_at,resolved_at ) VALUES (?1,?2,?3,?4,?5,?6,?7,?8,?9)", @@ -74,10 +74,10 @@ pub(super) fn query_record( ) -> Result, String> { let sql = format!( "SELECT {RECORD_SELECT} - FROM agent_org_runtime_plan_revisions revision - JOIN agent_org_runtime_plan_decisions decision + FROM agent_org_execution_plan_revisions revision + JOIN agent_org_execution_plan_decisions decision ON decision.plan_revision_id=revision.plan_revision_id - LEFT JOIN agent_org_runtime_tasks task + LEFT JOIN agent_org_execution_tasks task ON task.org_run_id=revision.org_run_id AND task.id=revision.source_task_id {where_clause} LIMIT 1" ); diff --git a/src-tauri/crates/agent-core/src/core/coordination/agent_org_plan_approvals/store.rs b/src-tauri/crates/agent-core/src/core/coordination/agent_org_plan_approvals/store.rs index cf60ebb023..7799e0ceb9 100644 --- a/src-tauri/crates/agent-core/src/core/coordination/agent_org_plan_approvals/store.rs +++ b/src-tauri/crates/agent-core/src/core/coordination/agent_org_plan_approvals/store.rs @@ -287,10 +287,10 @@ impl AgentOrgPlanRevisionStore { let conn = get_connection().map_err(|err| err.to_string())?; let sql = format!( "SELECT {RECORD_SELECT} - FROM agent_org_runtime_plan_revisions revision - JOIN agent_org_runtime_plan_decisions decision + FROM agent_org_execution_plan_revisions revision + JOIN agent_org_execution_plan_decisions decision ON decision.plan_revision_id=revision.plan_revision_id - LEFT JOIN agent_org_runtime_tasks task + LEFT JOIN agent_org_execution_tasks task ON task.org_run_id=revision.org_run_id AND task.id=revision.source_task_id WHERE revision.org_run_id=?1 AND decision.status=?2 ORDER BY revision.revision_number ASC,revision.plan_revision_id ASC" @@ -312,8 +312,8 @@ impl AgentOrgPlanRevisionStore { let mut stmt = conn .prepare( "SELECT revision.source_task_id - FROM agent_org_runtime_plan_revisions revision - JOIN agent_org_runtime_plan_decisions decision + FROM agent_org_execution_plan_revisions revision + JOIN agent_org_execution_plan_decisions decision ON decision.plan_revision_id=revision.plan_revision_id WHERE revision.org_run_id=?1 AND decision.status=?2 ORDER BY revision.revision_number ASC,revision.plan_revision_id ASC", @@ -377,10 +377,10 @@ impl AgentOrgPlanRevisionStore { length(CAST(revision.plan_content AS BLOB)),revision.content_digest, decision.decision_by,decision.feedback,revision.created_at, decision.resolved_at,task.output_json - FROM agent_org_runtime_plan_revisions revision - JOIN agent_org_runtime_plan_decisions decision + FROM agent_org_execution_plan_revisions revision + JOIN agent_org_execution_plan_decisions decision ON decision.plan_revision_id=revision.plan_revision_id - LEFT JOIN agent_org_runtime_tasks task + LEFT JOIN agent_org_execution_tasks task ON task.org_run_id=revision.org_run_id AND task.id=revision.source_task_id WHERE revision.org_run_id=?1 {pending_filter} ORDER BY (decision.status='pending') DESC, @@ -607,7 +607,7 @@ impl AgentOrgPlanRevisionStore { authorize_decision(revision.policy, decision_by)?; let (run_status, coordinator_agent_id): (String, String) = conn .query_row( - "SELECT status,coordinator_agent_id FROM agent_org_runtime_runs WHERE id=?1", + "SELECT status,coordinator_agent_id FROM agent_org_execution_runs WHERE id=?1", params![&revision.org_run_id], |row| Ok((row.get(0)?, row.get(1)?)), ) @@ -621,7 +621,7 @@ impl AgentOrgPlanRevisionStore { let resolved_at = chrono::Utc::now().to_rfc3339(); let changed = conn .execute( - "UPDATE agent_org_runtime_plan_decisions + "UPDATE agent_org_execution_plan_decisions SET status=?1, decision_by=?2, feedback=?3, resolved_at=?4 WHERE approval_id=?5 AND plan_revision_id=?6 AND status=?7", params![ @@ -658,7 +658,7 @@ impl AgentOrgPlanRevisionStore { && decision_source_turn_intent_id.is_some(); let remaining_open_task_count: i64 = conn .query_row( - "SELECT COUNT(*) FROM agent_org_runtime_tasks + "SELECT COUNT(*) FROM agent_org_execution_tasks WHERE org_run_id=?1 AND status IN ('pending','in_progress')", [&revision.org_run_id], |row| row.get(0), @@ -703,7 +703,7 @@ impl AgentOrgPlanRevisionStore { )?; if suppress_self_wake { conn.execute( - "UPDATE agent_org_runtime_inbox SET read_at=?2 WHERE id=?1 AND read_at IS NULL", + "UPDATE agent_org_execution_inbox SET read_at=?2 WHERE id=?1 AND read_at IS NULL", params![coordinator_record.id, chrono::Utc::now().to_rfc3339()], ) .map_err(|error| error.to_string())?; @@ -838,17 +838,17 @@ impl AgentOrgPlanRevisionStore { let mut stmt = conn .prepare( "SELECT DISTINCT revision.org_run_id - FROM agent_org_runtime_plan_revisions revision - JOIN agent_org_runtime_plan_decisions decision + FROM agent_org_execution_plan_revisions revision + JOIN agent_org_execution_plan_decisions decision ON decision.plan_revision_id=revision.plan_revision_id WHERE decision.status=?1 AND ( NOT EXISTS ( - SELECT 1 FROM agent_org_runtime_runs run + SELECT 1 FROM agent_org_execution_runs run WHERE run.id=revision.org_run_id ) OR EXISTS ( - SELECT 1 FROM agent_org_runtime_runs run + SELECT 1 FROM agent_org_execution_runs run WHERE run.id=revision.org_run_id AND run.status='failed' ) @@ -866,19 +866,19 @@ impl AgentOrgPlanRevisionStore { }; let changed = conn .execute( - "UPDATE agent_org_runtime_plan_decisions + "UPDATE agent_org_execution_plan_decisions SET status=?1, decision_by='automatic', resolved_at=?2 WHERE status=?3 AND plan_revision_id IN ( SELECT revision.plan_revision_id - FROM agent_org_runtime_plan_revisions revision + FROM agent_org_execution_plan_revisions revision WHERE NOT EXISTS ( - SELECT 1 FROM agent_org_runtime_runs run + SELECT 1 FROM agent_org_execution_runs run WHERE run.id=revision.org_run_id ) OR EXISTS ( - SELECT 1 FROM agent_org_runtime_runs run + SELECT 1 FROM agent_org_execution_runs run WHERE run.id=revision.org_run_id AND run.status='failed' ) diff --git a/src-tauri/crates/agent-core/src/core/coordination/agent_org_plan_approvals/tests.rs b/src-tauri/crates/agent-core/src/core/coordination/agent_org_plan_approvals/tests.rs index 31a4bf2cc1..555fbcd07e 100644 --- a/src-tauri/crates/agent-core/src/core/coordination/agent_org_plan_approvals/tests.rs +++ b/src-tauri/crates/agent-core/src/core/coordination/agent_org_plan_approvals/tests.rs @@ -35,6 +35,7 @@ fn setup(policy: PlanApprovalPolicy) -> (test_helpers::test_env::SandboxGuard, A let sandbox = test_helpers::test_env::sandbox(); let conn = get_connection().expect("test db"); crate::persistence::test_schema::ensure_agent_sessions_schema(&conn); + crate::persistence::test_schema::ensure_session_events_schema(&conn); conn.execute_batch( "CREATE TABLE session_turn_intents ( session_id TEXT NOT NULL, @@ -152,7 +153,7 @@ fn setup(policy: PlanApprovalPolicy) -> (test_helpers::test_env::SandboxGuard, A ) .expect("persist Coordinator Turn intent"); conn.execute( - "INSERT INTO agent_org_runtime_turn_contexts( + "INSERT INTO agent_org_execution_turn_contexts( session_id,turn_intent_id,org_run_id,participant_id,turn_kind, source_kind,source_id,activation_generation,created_at ) VALUES ('root-plan-approval','coordinator-turn',?1,'coordinator','coordinator', @@ -196,7 +197,7 @@ fn create_plan_task_with_ids( ) .expect("persist planning Turn intent"); conn.execute( - "INSERT INTO agent_org_runtime_turn_contexts( + "INSERT INTO agent_org_execution_turn_contexts( session_id,turn_intent_id,org_run_id,participant_id,turn_kind, task_id,owner_member_id,dispatch_member_id,member_dispatch_sequence, source_kind,source_id,activation_generation,created_at diff --git a/src-tauri/crates/agent-core/src/core/coordination/agent_org_plan_approvals/tests/formal_receipt_tests.rs b/src-tauri/crates/agent-core/src/core/coordination/agent_org_plan_approvals/tests/formal_receipt_tests.rs index e69898c266..d74bed094a 100644 --- a/src-tauri/crates/agent-core/src/core/coordination/agent_org_plan_approvals/tests/formal_receipt_tests.rs +++ b/src-tauri/crates/agent-core/src/core/coordination/agent_org_plan_approvals/tests/formal_receipt_tests.rs @@ -24,7 +24,7 @@ fn plan_request_receipt_binds_the_exact_revision_task_and_source_turn() { .query_row( "SELECT source_kind,task_id,owner_member_id,source_turn_intent_id, plan_revision_id,task_output_digest - FROM agent_org_runtime_formal_trigger_receipts + FROM agent_org_execution_formal_trigger_receipts WHERE org_run_id=?1 AND source_kind='plan_request'", [&context.run_id], |row| { @@ -71,7 +71,7 @@ fn approved_plan_receipt_binds_the_canonical_task_output_digest() { let (inbox_id, source_turn, digest, revision_id): (i64, Option, String, String) = conn .query_row( "SELECT inbox_id,source_turn_intent_id,task_output_digest,plan_revision_id - FROM agent_org_runtime_formal_trigger_receipts + FROM agent_org_execution_formal_trigger_receipts WHERE org_run_id=?1 AND source_kind='plan_decision'", [&context.run_id], |row| Ok((row.get(0)?, row.get(1)?, row.get(2)?, row.get(3)?)), @@ -126,7 +126,7 @@ fn user_request_changes_creates_a_pending_coordinator_decision_fact() { let (status, source_turn, digest): (String, Option, Option) = conn .query_row( "SELECT status,source_turn_intent_id,task_output_digest - FROM agent_org_runtime_formal_trigger_receipts + FROM agent_org_execution_formal_trigger_receipts WHERE org_run_id=?1 AND source_kind='plan_decision'", [&context.run_id], |row| Ok((row.get(0)?, row.get(1)?, row.get(2)?)), @@ -195,7 +195,7 @@ fn coordinator_decision_turn_resolves_its_own_plan_and_assignment_facts() { let mut stmt = conn .prepare( "SELECT source_kind,status,doorbell_status,source_turn_intent_id - FROM agent_org_runtime_formal_trigger_receipts + FROM agent_org_execution_formal_trigger_receipts WHERE org_run_id=?1 AND source_kind IN ('plan_decision','task_assignment') ORDER BY source_kind", ) diff --git a/src-tauri/crates/agent-core/src/core/coordination/agent_org_plan_approvals/tests/immutable_revision_tests.rs b/src-tauri/crates/agent-core/src/core/coordination/agent_org_plan_approvals/tests/immutable_revision_tests.rs index 5b68edadd0..5117f77919 100644 --- a/src-tauri/crates/agent-core/src/core/coordination/agent_org_plan_approvals/tests/immutable_revision_tests.rs +++ b/src-tauri/crates/agent-core/src/core/coordination/agent_org_plan_approvals/tests/immutable_revision_tests.rs @@ -217,7 +217,7 @@ fn sqlite_rejects_any_plan_revision_update() { let error = get_connection() .unwrap() .execute( - "UPDATE agent_org_runtime_plan_revisions + "UPDATE agent_org_execution_plan_revisions SET plan_content='# rewritten' WHERE plan_revision_id=?1", [&pending.plan_revision_id], ) diff --git a/src-tauri/crates/agent-core/src/core/coordination/agent_org_plan_approvals/tests/pause_resume_tests.rs b/src-tauri/crates/agent-core/src/core/coordination/agent_org_plan_approvals/tests/pause_resume_tests.rs index 361ee7e122..bd98fe7049 100644 --- a/src-tauri/crates/agent-core/src/core/coordination/agent_org_plan_approvals/tests/pause_resume_tests.rs +++ b/src-tauri/crates/agent-core/src/core/coordination/agent_org_plan_approvals/tests/pause_resume_tests.rs @@ -58,7 +58,7 @@ fn resumed_coordinator_can_approve_revision_authored_before_pause() { crate::coordination::agent_org_final_summary::create_schema(&conn) .expect("final summary schema"); conn.execute( - "INSERT INTO agent_org_runtime_member_dispatch_allocators ( + "INSERT INTO agent_org_execution_member_dispatch_allocators ( org_run_id,member_id,next_sequence ) VALUES (?1,'planner',2) ON CONFLICT(org_run_id,member_id) DO UPDATE SET next_sequence=2", @@ -70,7 +70,7 @@ fn resumed_coordinator_can_approve_revision_authored_before_pause() { ("planner", "planner-agent", "planner-session"), ] { conn.execute( - "INSERT INTO agent_org_runtime_member_materializations ( + "INSERT INTO agent_org_execution_member_materializations ( org_run_id,member_id,agent_id,generation,session_id, authority_class,status,created_at,updated_at ) VALUES (?1,?2,?3,1,?4,'formal','succeeded',?5,?5)", @@ -119,7 +119,7 @@ fn resumed_coordinator_can_approve_revision_authored_before_pause() { let continuation_turn_id: String = conn .query_row( "SELECT continuation_turn_intent_id - FROM agent_org_runtime_pause_handoffs + FROM agent_org_execution_pause_handoffs WHERE episode_id=?1 AND turn_kind='coordinator' AND continuation_status='queued'", [&resumed.episode_id], @@ -159,8 +159,8 @@ fn resumed_coordinator_can_approve_revision_authored_before_pause() { let (run_generation, actor_kind, actor_turn): (i64, String, Option) = conn .query_row( "SELECT run.activation_generation,event.actor_kind,event.source_turn_intent_id - FROM agent_org_runtime_runs run - JOIN agent_org_runtime_task_events event ON event.org_run_id=run.id + FROM agent_org_execution_runs run + JOIN agent_org_execution_task_events event ON event.org_run_id=run.id WHERE run.id=?1 AND event.task_id=?2 AND event.next_status='completed' ORDER BY event.created_at DESC LIMIT 1", diff --git a/src-tauri/crates/agent-core/src/core/coordination/agent_org_plan_approvals/tests/persistence_boundary_tests.rs b/src-tauri/crates/agent-core/src/core/coordination/agent_org_plan_approvals/tests/persistence_boundary_tests.rs index 08d0693a21..22fb8052bd 100644 --- a/src-tauri/crates/agent-core/src/core/coordination/agent_org_plan_approvals/tests/persistence_boundary_tests.rs +++ b/src-tauri/crates/agent-core/src/core/coordination/agent_org_plan_approvals/tests/persistence_boundary_tests.rs @@ -61,7 +61,7 @@ fn coordinator_request_insert_failure_rolls_back_pending_creation() { create_plan_task(&context); get_connection() .expect("test db") - .execute("DROP TABLE agent_org_runtime_inbox", []) + .execute("DROP TABLE agent_org_execution_inbox", []) .expect("remove inbox to force request delivery failure"); let params = approval_params(&context); diff --git a/src-tauri/crates/agent-core/src/core/coordination/agent_org_plan_approvals/tests/projection_tests.rs b/src-tauri/crates/agent-core/src/core/coordination/agent_org_plan_approvals/tests/projection_tests.rs index 7ae678ef34..6084213601 100644 --- a/src-tauri/crates/agent-core/src/core/coordination/agent_org_plan_approvals/tests/projection_tests.rs +++ b/src-tauri/crates/agent-core/src/core/coordination/agent_org_plan_approvals/tests/projection_tests.rs @@ -64,12 +64,12 @@ fn watchdog_pending_task_projection_never_materializes_plan_markdown() { // source id remains valid and proves the hot path does not decode it. let conn = get_connection().unwrap(); conn.execute( - "DROP TRIGGER trg_agent_org_runtime_plan_revisions_immutable", + "DROP TRIGGER trg_agent_org_execution_plan_revisions_immutable", [], ) .unwrap(); conn.execute( - "UPDATE agent_org_runtime_plan_revisions + "UPDATE agent_org_execution_plan_revisions SET plan_content=CAST(X'80' AS TEXT) WHERE plan_revision_id=?1", params![&pending.plan_revision_id], diff --git a/src-tauri/crates/agent-core/src/core/coordination/agent_org_plan_approvals/tests/request_changes_tests.rs b/src-tauri/crates/agent-core/src/core/coordination/agent_org_plan_approvals/tests/request_changes_tests.rs index 325059dca3..566ebec2bf 100644 --- a/src-tauri/crates/agent-core/src/core/coordination/agent_org_plan_approvals/tests/request_changes_tests.rs +++ b/src-tauri/crates/agent-core/src/core/coordination/agent_org_plan_approvals/tests/request_changes_tests.rs @@ -36,7 +36,7 @@ fn feedback_insert_failure_rolls_back_changes_requested_status() { let pending = create_pending_approval(&context); get_connection() .expect("test db") - .execute("DROP TABLE agent_org_runtime_inbox", []) + .execute("DROP TABLE agent_org_execution_inbox", []) .expect("remove inbox to force delivery failure"); AgentOrgPlanApprovalStore::request_changes( diff --git a/src-tauri/crates/agent-core/src/core/coordination/agent_org_plan_approvals/transitions.rs b/src-tauri/crates/agent-core/src/core/coordination/agent_org_plan_approvals/transitions.rs index 2af9c35618..32ecd1252b 100644 --- a/src-tauri/crates/agent-core/src/core/coordination/agent_org_plan_approvals/transitions.rs +++ b/src-tauri/crates/agent-core/src/core/coordination/agent_org_plan_approvals/transitions.rs @@ -33,7 +33,7 @@ pub(super) fn create_pending_in_tx( validate_owned_plan_path_with_connection(tx, ¶ms.source_session_id, ¶ms.plan_path)?; let run_status: Option = tx .query_row( - "SELECT status FROM agent_org_runtime_runs WHERE id=?1", + "SELECT status FROM agent_org_execution_runs WHERE id=?1", params![¶ms.org_run_id], |row| row.get(0), ) @@ -56,7 +56,7 @@ pub(super) fn create_pending_in_tx( let task: Option<(Option, String, String)> = tx .query_row( - "SELECT owner, status, execution_mode FROM agent_org_runtime_tasks + "SELECT owner, status, execution_mode FROM agent_org_execution_tasks WHERE org_run_id=?1 AND id=?2", params![¶ms.org_run_id, ¶ms.source_task_id], |row| Ok((row.get(0)?, row.get(1)?, row.get(2)?)), @@ -89,8 +89,8 @@ pub(super) fn create_pending_in_tx( let previous: Option<(String, i64)> = tx .query_row( "SELECT revision.plan_revision_id,revision.revision_number - FROM agent_org_runtime_plan_revisions revision - JOIN agent_org_runtime_plan_decisions decision + FROM agent_org_execution_plan_revisions revision + JOIN agent_org_execution_plan_decisions decision ON decision.plan_revision_id=revision.plan_revision_id WHERE revision.org_run_id=?1 AND revision.source_task_id=?2 ORDER BY revision.revision_number DESC LIMIT 1", @@ -102,10 +102,10 @@ pub(super) fn create_pending_in_tx( let revision_number = next_revision_number(previous.as_ref().map(|(_, number)| *number))?; let now = chrono::Utc::now().to_rfc3339(); tx.execute( - "UPDATE agent_org_runtime_plan_decisions + "UPDATE agent_org_execution_plan_decisions SET status=?1, decision_by='automatic', resolved_at=?2 WHERE status=?3 AND plan_revision_id IN ( - SELECT plan_revision_id FROM agent_org_runtime_plan_revisions + SELECT plan_revision_id FROM agent_org_execution_plan_revisions WHERE org_run_id=?4 AND source_task_id=?5 )", params![ @@ -223,7 +223,7 @@ pub(super) fn approve_pending_in_tx( let resolved_at = chrono::Utc::now().to_rfc3339(); let changed = tx .execute( - "UPDATE agent_org_runtime_plan_decisions + "UPDATE agent_org_execution_plan_decisions SET status=?1, decision_by=?2, resolved_at=?3 WHERE approval_id=?4 AND plan_revision_id=?5 AND status=?6", params![ @@ -384,7 +384,7 @@ fn enqueue_post_approval_messages_in_tx( )?; if suppress_self_wake { tx.execute( - "UPDATE agent_org_runtime_inbox SET read_at=?2 WHERE id=?1 AND read_at IS NULL", + "UPDATE agent_org_execution_inbox SET read_at=?2 WHERE id=?1 AND read_at IS NULL", params![decision_record.id, chrono::Utc::now().to_rfc3339()], ) .map_err(|error| error.to_string())?; @@ -414,7 +414,7 @@ fn participant_agent_ids_in_tx( let (coordinator_agent_id, snapshot_json): (String, Option) = tx .query_row( "SELECT coordinator_agent_id, org_snapshot_json - FROM agent_org_runtime_runs WHERE id=?1 AND status='running'", + FROM agent_org_execution_runs WHERE id=?1 AND status='running'", params![run_id], |row| Ok((row.get(0)?, row.get(1)?)), ) diff --git a/src-tauri/crates/agent-core/src/core/coordination/agent_org_run_blockers.rs b/src-tauri/crates/agent-core/src/core/coordination/agent_org_run_blockers.rs index fa70e268bf..c6c63edbab 100644 --- a/src-tauri/crates/agent-core/src/core/coordination/agent_org_run_blockers.rs +++ b/src-tauri/crates/agent-core/src/core/coordination/agent_org_run_blockers.rs @@ -120,7 +120,7 @@ pub fn build_with_connection( load_open_task_objects(conn, org_run_id)?, "Tasks are still open", "agent_org_open_tasks", - "agent_org_runtime_tasks", + "agent_org_execution_tasks", AgentOrgRunBlockerRecoveryState::WaitingForRuntime, None, )); @@ -156,7 +156,7 @@ pub fn build_from_candidate_with_connection( run_objects(org_run_id), "The Team is not available for completion", "run_completion_run_unavailable", - "agent_org_runtime_runs", + "agent_org_execution_runs", AgentOrgRunBlockerRecoveryState::SystemAttentionRequired, None, ), @@ -166,7 +166,7 @@ pub fn build_from_candidate_with_connection( run_objects(org_run_id), "The Coordinator view is stale", "run_completion_stale_coordinator_snapshot", - "agent_org_runtime_turn_contexts", + "agent_org_execution_turn_contexts", AgentOrgRunBlockerRecoveryState::SystemAttentionRequired, None, ), @@ -186,7 +186,7 @@ pub fn build_from_candidate_with_connection( run_objects(org_run_id), "Task data needs system repair", "agent_org_corrupt_task_data", - "agent_org_runtime_tasks", + "agent_org_execution_tasks", AgentOrgRunBlockerRecoveryState::SystemAttentionRequired, None, ), @@ -209,7 +209,7 @@ pub fn build_from_candidate_with_connection( ), "Member startup is still being reconciled", "agent_org_pending_formal_materializations", - "agent_org_runtime_member_materializations", + "agent_org_execution_member_materializations", AgentOrgRunBlockerRecoveryState::WaitingForRuntime, None, ), @@ -219,7 +219,7 @@ pub fn build_from_candidate_with_connection( bounded_for_count(load_recovery_objects(conn, org_run_id)?, *count), "System recovery is in progress", "agent_org_active_recovery_reservations", - "agent_org_runtime_recovery_attempts", + "agent_org_execution_recovery_attempts", AgentOrgRunBlockerRecoveryState::SystemRepairing, None, ), @@ -246,7 +246,7 @@ pub fn build_from_candidate_with_connection( identity_objects("task", task_ids.clone()), "Tasks are still open", "agent_org_open_tasks", - "agent_org_runtime_tasks", + "agent_org_execution_tasks", AgentOrgRunBlockerRecoveryState::WaitingForRuntime, None, ), @@ -256,7 +256,7 @@ pub fn build_from_candidate_with_connection( bounded_for_count(load_handoff_objects(conn, org_run_id)?, *count), "A task handoff is unresolved", "agent_org_unresolved_task_handoffs", - "agent_org_runtime_task_execution_handoffs", + "agent_org_execution_task_execution_handoffs", AgentOrgRunBlockerRecoveryState::UserActionRequired, Some("review_handoff"), ), @@ -275,7 +275,7 @@ pub fn build_from_candidate_with_connection( }], "Completion evidence is stale", "agent_org_stale_completion_certificate", - "agent_org_runtime_run_completion_certificates", + "agent_org_execution_run_completion_certificates", AgentOrgRunBlockerRecoveryState::SystemAttentionRequired, None, ), @@ -285,7 +285,7 @@ pub fn build_from_candidate_with_connection( identity_objects("task", task_ids.clone()), "Task closure evidence is incomplete", "run_completion_delivery_closure_incomplete", - "agent_org_runtime_tasks", + "agent_org_execution_tasks", AgentOrgRunBlockerRecoveryState::UserActionRequired, Some("review_tasks"), ), @@ -295,7 +295,7 @@ pub fn build_from_candidate_with_connection( identity_objects("task", task_ids.clone()), "Task scope-removal evidence is invalid", "run_completion_scope_removal_invalid", - "agent_org_runtime_tasks", + "agent_org_execution_tasks", AgentOrgRunBlockerRecoveryState::UserActionRequired, Some("review_tasks"), ), @@ -305,7 +305,7 @@ pub fn build_from_candidate_with_connection( identity_objects("task", task_ids.clone()), "Task replacement evidence is invalid", "run_completion_replacement_chain_invalid", - "agent_org_runtime_tasks", + "agent_org_execution_tasks", AgentOrgRunBlockerRecoveryState::UserActionRequired, Some("review_tasks"), ), @@ -366,11 +366,11 @@ fn append_system_blockers( if facts.corrupt_task_count > 0 { let predicate = crate::coordination::agent_org_tasks::corrupt_task_row_predicate_sql(); let sql = format!( - "SELECT task.id,task.subject FROM agent_org_runtime_tasks task + "SELECT task.id,task.subject FROM agent_org_execution_tasks task WHERE task.org_run_id=?1 AND ( {predicate} OR NOT EXISTS ( - SELECT 1 FROM agent_org_runtime_work_episode_tasks episode_task + SELECT 1 FROM agent_org_execution_work_episode_tasks episode_task WHERE episode_task.org_run_id=task.org_run_id AND episode_task.task_id=task.id ) @@ -386,7 +386,7 @@ fn append_system_blockers( objects, "Task data needs system repair", "agent_org_corrupt_task_data", - "agent_org_runtime_tasks", + "agent_org_execution_tasks", AgentOrgRunBlockerRecoveryState::SystemAttentionRequired, None, )); @@ -399,7 +399,7 @@ fn append_system_blockers( conn, "SELECT intent.turn_intent_id,context.participant_id || ' turn' FROM session_turn_intents intent - JOIN agent_org_runtime_turn_contexts context + JOIN agent_org_execution_turn_contexts context ON context.session_id=intent.session_id AND context.turn_intent_id=intent.turn_intent_id WHERE intent.org_run_id=?1 @@ -425,11 +425,11 @@ fn append_system_blockers( load_objects( conn, "SELECT member_id,member_id - FROM agent_org_runtime_member_materializations + FROM agent_org_execution_member_materializations WHERE org_run_id=?1 AND generation=( SELECT activation_generation - FROM agent_org_runtime_runs WHERE id=?1 + FROM agent_org_execution_runs WHERE id=?1 ) AND authority_class IN ('starting','formal') AND status<>'succeeded' @@ -439,7 +439,7 @@ fn append_system_blockers( )?, "Member startup is still being reconciled", "agent_org_pending_formal_materializations", - "agent_org_runtime_member_materializations", + "agent_org_execution_member_materializations", AgentOrgRunBlockerRecoveryState::WaitingForRuntime, None, )); @@ -451,7 +451,7 @@ fn append_system_blockers( load_objects( conn, "SELECT target_key,action_kind || ' → ' || target_key - FROM agent_org_runtime_recovery_attempts + FROM agent_org_execution_recovery_attempts WHERE org_run_id=?1 AND reservation_token IS NOT NULL ORDER BY action_kind,target_key LIMIT ?2", org_run_id, @@ -459,7 +459,7 @@ fn append_system_blockers( )?, "System recovery is in progress", "agent_org_active_recovery_reservations", - "agent_org_runtime_recovery_attempts", + "agent_org_execution_recovery_attempts", AgentOrgRunBlockerRecoveryState::SystemRepairing, None, )); @@ -478,14 +478,14 @@ fn append_system_blockers( load_objects( conn, "SELECT handoff.id,handoff.old_task_id || ' handoff' - FROM agent_org_runtime_task_execution_handoffs handoff + FROM agent_org_execution_task_execution_handoffs handoff WHERE handoff.org_run_id=?1 AND handoff.state IN ('requested','yielding','timeout','unknown','failed') AND handoff.resolution IS NULL AND EXISTS ( SELECT 1 - FROM agent_org_runtime_work_episode_tasks episode_task - JOIN agent_org_runtime_work_episodes episode + FROM agent_org_execution_work_episode_tasks episode_task + JOIN agent_org_execution_work_episodes episode ON episode.id=episode_task.work_episode_id WHERE episode_task.org_run_id=handoff.org_run_id AND episode_task.task_id=handoff.old_task_id @@ -497,7 +497,7 @@ fn append_system_blockers( )?, "A task handoff is unresolved", "agent_org_unresolved_task_handoffs", - "agent_org_runtime_task_execution_handoffs", + "agent_org_execution_task_execution_handoffs", AgentOrgRunBlockerRecoveryState::UserActionRequired, Some("review_handoff"), )); @@ -520,7 +520,7 @@ fn append_system_blockers( }], "Completion evidence is stale", "agent_org_stale_completion_certificate", - "agent_org_runtime_run_completion_certificates", + "agent_org_execution_run_completion_certificates", AgentOrgRunBlockerRecoveryState::SystemAttentionRequired, None, )); @@ -537,7 +537,7 @@ pub fn append_completion_failure(blockers: &mut Vec, error: Some(ids), "Task closure evidence is incomplete", "run_completion_delivery_closure_incomplete", - "agent_org_runtime_tasks", + "agent_org_execution_tasks", AgentOrgRunBlockerRecoveryState::UserActionRequired, Some("review_tasks"), ) @@ -550,7 +550,7 @@ pub fn append_completion_failure(blockers: &mut Vec, error: Some(ids), "Task scope-removal evidence is invalid", "run_completion_scope_removal_invalid", - "agent_org_runtime_tasks", + "agent_org_execution_tasks", AgentOrgRunBlockerRecoveryState::UserActionRequired, Some("review_tasks"), ) @@ -563,7 +563,7 @@ pub fn append_completion_failure(blockers: &mut Vec, error: Some(ids), "Task replacement evidence is invalid", "run_completion_replacement_chain_invalid", - "agent_org_runtime_tasks", + "agent_org_execution_tasks", AgentOrgRunBlockerRecoveryState::UserActionRequired, Some("review_tasks"), ) @@ -614,7 +614,7 @@ fn load_in_flight_turn_objects( "SELECT intent.turn_intent_id, context.participant_id || ' turn' FROM session_turn_intents intent - JOIN agent_org_runtime_turn_contexts context + JOIN agent_org_execution_turn_contexts context ON context.session_id=intent.session_id AND context.turn_intent_id=intent.turn_intent_id WHERE intent.org_run_id=?1 @@ -636,7 +636,7 @@ fn load_unknown_turn_objects( conn, "SELECT intent.turn_intent_id,context.participant_id || ' turn' FROM session_turn_intents intent - JOIN agent_org_runtime_turn_contexts context + JOIN agent_org_execution_turn_contexts context ON context.session_id=intent.session_id AND context.turn_intent_id=intent.turn_intent_id WHERE intent.org_run_id=?1 @@ -657,10 +657,10 @@ fn load_pending_materialization_objects( load_objects( conn, "SELECT member_id,member_id - FROM agent_org_runtime_member_materializations + FROM agent_org_execution_member_materializations WHERE org_run_id=?1 AND generation=( - SELECT activation_generation FROM agent_org_runtime_runs WHERE id=?1 + SELECT activation_generation FROM agent_org_execution_runs WHERE id=?1 ) AND authority_class IN ('starting','formal') AND status<>'succeeded' ORDER BY generation,member_id LIMIT ?2", @@ -676,7 +676,7 @@ fn load_recovery_objects( load_objects( conn, "SELECT target_key,action_kind || ' → ' || target_key - FROM agent_org_runtime_recovery_attempts + FROM agent_org_execution_recovery_attempts WHERE org_run_id=?1 AND reservation_token IS NOT NULL ORDER BY action_kind,target_key LIMIT ?2", org_run_id, @@ -691,8 +691,8 @@ fn load_plan_approval_objects( load_objects( conn, "SELECT revision.plan_revision_id,revision.plan_title - FROM agent_org_runtime_plan_revisions revision - JOIN agent_org_runtime_plan_decisions decision + FROM agent_org_execution_plan_revisions revision + JOIN agent_org_execution_plan_decisions decision ON decision.plan_revision_id=revision.plan_revision_id WHERE revision.org_run_id=?1 AND decision.status='pending' ORDER BY revision.created_at,revision.plan_revision_id LIMIT ?2", @@ -710,8 +710,8 @@ fn pending_plan_approval_blocker( .query_row( "SELECT EXISTS( SELECT 1 - FROM agent_org_runtime_plan_revisions revision - JOIN agent_org_runtime_plan_decisions decision + FROM agent_org_execution_plan_revisions revision + JOIN agent_org_execution_plan_decisions decision ON decision.plan_revision_id=revision.plan_revision_id WHERE revision.org_run_id=?1 AND decision.status='pending' AND decision.policy='user' @@ -730,7 +730,7 @@ fn pending_plan_approval_blocker( "A plan decision is being resolved" }, "agent_org_pending_plan_approvals", - "agent_org_runtime_plan_decisions", + "agent_org_execution_plan_decisions", if requires_user_action { AgentOrgRunBlockerRecoveryState::UserActionRequired } else { @@ -747,13 +747,13 @@ fn load_handoff_objects( load_objects( conn, "SELECT handoff.id,handoff.old_task_id || ' handoff' - FROM agent_org_runtime_task_execution_handoffs handoff + FROM agent_org_execution_task_execution_handoffs handoff WHERE handoff.org_run_id=?1 AND handoff.state IN ('requested','yielding','timeout','unknown','failed') AND handoff.resolution IS NULL AND EXISTS ( - SELECT 1 FROM agent_org_runtime_work_episode_tasks episode_task - JOIN agent_org_runtime_work_episodes episode + SELECT 1 FROM agent_org_execution_work_episode_tasks episode_task + JOIN agent_org_execution_work_episodes episode ON episode.id=episode_task.work_episode_id WHERE episode_task.org_run_id=handoff.org_run_id AND episode_task.task_id=handoff.old_task_id @@ -771,10 +771,10 @@ fn load_open_task_objects( ) -> Result, String> { load_objects( conn, - "SELECT task.id,task.subject FROM agent_org_runtime_tasks task - JOIN agent_org_runtime_work_episode_tasks episode_task + "SELECT task.id,task.subject FROM agent_org_execution_tasks task + JOIN agent_org_execution_work_episode_tasks episode_task ON episode_task.org_run_id=task.org_run_id AND episode_task.task_id=task.id - JOIN agent_org_runtime_work_episodes episode + JOIN agent_org_execution_work_episodes episode ON episode.id=episode_task.work_episode_id WHERE task.org_run_id=?1 AND episode.status='active' AND task.status IN ('pending','in_progress') @@ -797,8 +797,8 @@ fn blocking_inbox_blockers( inbox.recipient_member_id, 'unknown recipient' ) - FROM agent_org_runtime_inbox inbox - JOIN agent_org_runtime_runs run ON run.id=inbox.org_run_id + FROM agent_org_execution_inbox inbox + JOIN agent_org_execution_runs run ON run.id=inbox.org_run_id LEFT JOIN json_each( CASE WHEN json_valid(run.org_snapshot_json) THEN json_extract(run.org_snapshot_json,'$.members') ELSE '[]' END @@ -807,13 +807,13 @@ fn blocking_inbox_blockers( WHERE inbox.org_run_id=?1 AND inbox.delivery_class='formal_work' AND inbox.read_at IS NULL AND NOT EXISTS ( - SELECT 1 FROM agent_org_runtime_inbox_delivery_resolutions resolution + SELECT 1 FROM agent_org_execution_inbox_delivery_resolutions resolution WHERE resolution.inbox_id=inbox.id ) AND NOT ( inbox.payload_kind='shutdown_request' AND NOT EXISTS ( - SELECT 1 FROM agent_org_runtime_tasks task + SELECT 1 FROM agent_org_execution_tasks task WHERE task.org_run_id=inbox.org_run_id AND task.owner=inbox.recipient_member_id AND task.status IN ('pending','in_progress') @@ -823,7 +823,7 @@ fn blocking_inbox_blockers( inbox.recipient_member_id<>'coordinator' OR inbox.sender_agent_id=?2 OR EXISTS ( - SELECT 1 FROM agent_org_runtime_formal_trigger_receipts receipt + SELECT 1 FROM agent_org_execution_formal_trigger_receipts receipt WHERE receipt.inbox_id=inbox.id AND receipt.status IN ('pending','materialized') ) @@ -887,7 +887,7 @@ fn blocking_inbox_blockers( unbound, "A historical task message can be repaired by the Coordinator", "unbound_coordinator_task_message", - "agent_org_runtime_inbox_task_bindings", + "agent_org_execution_inbox_task_bindings", AgentOrgRunBlockerRecoveryState::CoordinatorRepairAvailable, None, )); @@ -899,7 +899,7 @@ fn blocking_inbox_blockers( unavailable, "Inbox work targets a permanently unavailable member", "permanently_unavailable_inbox_recipient", - "agent_org_runtime_inbox", + "agent_org_execution_inbox", AgentOrgRunBlockerRecoveryState::CoordinatorRepairAvailable, None, )); @@ -911,7 +911,7 @@ fn blocking_inbox_blockers( waiting, "Inbox work is waiting for its runtime", "agent_org_blocking_inbox", - "agent_org_runtime_inbox", + "agent_org_execution_inbox", AgentOrgRunBlockerRecoveryState::WaitingForRuntime, None, )); @@ -923,7 +923,7 @@ fn blocking_inbox_blockers( attention, "Inbox data needs system attention", "agent_org_unrepairable_blocking_inbox", - "agent_org_runtime_inbox", + "agent_org_execution_inbox", AgentOrgRunBlockerRecoveryState::SystemAttentionRequired, None, )); @@ -935,7 +935,7 @@ fn blocking_inbox_blockers( Vec::new(), "Additional Inbox work is waiting", "agent_org_blocking_inbox", - "agent_org_runtime_inbox", + "agent_org_execution_inbox", AgentOrgRunBlockerRecoveryState::WaitingForRuntime, None, )); diff --git a/src-tauri/crates/agent-core/src/core/coordination/agent_org_run_completion.rs b/src-tauri/crates/agent-core/src/core/coordination/agent_org_run_completion.rs index 6d5e8b3423..2e6a731323 100644 --- a/src-tauri/crates/agent-core/src/core/coordination/agent_org_run_completion.rs +++ b/src-tauri/crates/agent-core/src/core/coordination/agent_org_run_completion.rs @@ -250,7 +250,7 @@ impl RunCompletionCandidateAssessment { pub(crate) fn create_schema(conn: &Connection) -> rusqlite::Result<()> { super::agent_org_work_episodes::create_schema(conn)?; conn.execute_batch( - "CREATE TABLE IF NOT EXISTS agent_org_runtime_run_completion_certificates ( + "CREATE TABLE IF NOT EXISTS agent_org_execution_run_completion_certificates ( id TEXT PRIMARY KEY, org_run_id TEXT NOT NULL, activation_generation INTEGER NOT NULL CHECK(activation_generation >= 1), @@ -268,14 +268,14 @@ pub(crate) fn create_schema(conn: &Connection) -> rusqlite::Result<()> { validator_version INTEGER NOT NULL CHECK(validator_version=1), created_at TEXT NOT NULL, UNIQUE(org_run_id, request_id), - FOREIGN KEY (org_run_id) REFERENCES agent_org_runtime_runs(id) ON DELETE CASCADE + FOREIGN KEY (org_run_id) REFERENCES agent_org_execution_runs(id) ON DELETE CASCADE ); - CREATE INDEX IF NOT EXISTS idx_agent_org_runtime_run_completion_certificates_turn - ON agent_org_runtime_run_completion_certificates( + CREATE INDEX IF NOT EXISTS idx_agent_org_execution_run_completion_certificates_turn + ON agent_org_execution_run_completion_certificates( coordinator_session_id,coordinator_turn_intent_id ); - CREATE INDEX IF NOT EXISTS idx_agent_org_runtime_run_completion_public_timeline - ON agent_org_runtime_run_completion_certificates(org_run_id,created_at,id);", + CREATE INDEX IF NOT EXISTS idx_agent_org_execution_run_completion_public_timeline + ON agent_org_execution_run_completion_certificates(org_run_id,created_at,id);", ) } @@ -429,8 +429,8 @@ fn try_assess_delivered_candidate_with_connection( .query_row( "SELECT COUNT(*), COALESCE(SUM(CASE WHEN status IN ('pending','in_progress') THEN 1 ELSE 0 END),0) - FROM agent_org_runtime_tasks task - JOIN agent_org_runtime_work_episode_tasks episode_task + FROM agent_org_execution_tasks task + JOIN agent_org_execution_work_episode_tasks episode_task ON episode_task.org_run_id=task.org_run_id AND episode_task.task_id=task.id WHERE task.org_run_id=?1 AND episode_task.work_episode_id=?2", params![org_run_id, &work_episode.id], @@ -521,8 +521,8 @@ fn try_assess_delivered_candidate_with_connection( if open_task_count > 0 { let mut statement = conn .prepare( - "SELECT task.id FROM agent_org_runtime_tasks task - JOIN agent_org_runtime_work_episode_tasks episode_task + "SELECT task.id FROM agent_org_execution_tasks task + JOIN agent_org_execution_work_episode_tasks episode_task ON episode_task.org_run_id=task.org_run_id AND episode_task.task_id=task.id WHERE task.org_run_id=?1 AND episode_task.work_episode_id=?2 AND task.status IN ('pending','in_progress') @@ -639,7 +639,7 @@ pub fn certify_in_tx( let run: Option<(String, i64, Option)> = conn .query_row( "SELECT status,activation_generation,root_session_id - FROM agent_org_runtime_runs WHERE id=?1", + FROM agent_org_execution_runs WHERE id=?1", [org_run_id], |row| Ok((row.get(0)?, row.get(1)?, row.get(2)?)), ) @@ -680,7 +680,7 @@ pub fn certify_in_tx( let work_revision: i64 = conn .query_row( - "SELECT work_revision FROM agent_org_runtime_run_progress WHERE org_run_id=?1", + "SELECT work_revision FROM agent_org_execution_run_progress WHERE org_run_id=?1", [org_run_id], |row| row.get(0), ) @@ -728,8 +728,8 @@ pub fn certify_in_tx( let handoff_blockers: i64 = conn .query_row( "SELECT COUNT(*) - FROM agent_org_runtime_task_execution_handoffs handoff - JOIN agent_org_runtime_work_episode_tasks episode_task + FROM agent_org_execution_task_execution_handoffs handoff + JOIN agent_org_execution_work_episode_tasks episode_task ON episode_task.org_run_id=handoff.org_run_id AND episode_task.task_id=handoff.old_task_id WHERE handoff.org_run_id=?1 AND episode_task.work_episode_id=?2 @@ -758,7 +758,7 @@ pub fn certify_in_tx( let id = uuid::Uuid::new_v4().to_string(); let now = chrono::Utc::now().to_rfc3339(); conn.execute( - "INSERT INTO agent_org_runtime_run_completion_certificates ( + "INSERT INTO agent_org_execution_run_completion_certificates ( id,org_run_id,activation_generation,work_revision,request_id,request_digest, outcome,summary,coordinator_session_id,coordinator_turn_intent_id, evidence_task_ids_json,closure_task_ids_json,task_output_refs_json, @@ -856,7 +856,7 @@ fn certify_user_handoff_cancellation_in_tx( let run: Option<(String, i64, Option)> = conn .query_row( "SELECT status,activation_generation,root_session_id - FROM agent_org_runtime_runs WHERE id=?1", + FROM agent_org_execution_runs WHERE id=?1", [org_run_id], |row| Ok((row.get(0)?, row.get(1)?, row.get(2)?)), ) @@ -893,8 +893,8 @@ fn certify_user_handoff_cancellation_in_tx( let receipt: Option<(String, Option)> = conn .query_row( "SELECT handoff.state,handoff.resolution - FROM agent_org_runtime_task_execution_handoffs handoff - JOIN agent_org_runtime_work_episode_tasks episode_task + FROM agent_org_execution_task_execution_handoffs handoff + JOIN agent_org_execution_work_episode_tasks episode_task ON episode_task.org_run_id=handoff.org_run_id AND episode_task.task_id=handoff.old_task_id WHERE handoff.id=?1 AND handoff.org_run_id=?2 @@ -914,8 +914,8 @@ fn certify_user_handoff_cancellation_in_tx( } let unresolved_handoffs: i64 = conn .query_row( - "SELECT COUNT(*) FROM agent_org_runtime_task_execution_handoffs handoff - JOIN agent_org_runtime_work_episode_tasks episode_task + "SELECT COUNT(*) FROM agent_org_execution_task_execution_handoffs handoff + JOIN agent_org_execution_work_episode_tasks episode_task ON episode_task.org_run_id=handoff.org_run_id AND episode_task.task_id=handoff.old_task_id WHERE handoff.org_run_id=?1 AND episode_task.work_episode_id=?2 @@ -930,7 +930,7 @@ fn certify_user_handoff_cancellation_in_tx( } let work_revision: i64 = conn .query_row( - "SELECT work_revision FROM agent_org_runtime_run_progress WHERE org_run_id=?1", + "SELECT work_revision FROM agent_org_execution_run_progress WHERE org_run_id=?1", [org_run_id], |row| row.get(0), ) @@ -964,7 +964,7 @@ fn certify_user_handoff_cancellation_in_tx( let id = uuid::Uuid::new_v4().to_string(); let now = chrono::Utc::now().to_rfc3339(); conn.execute( - "INSERT INTO agent_org_runtime_run_completion_certificates ( + "INSERT INTO agent_org_execution_run_completion_certificates ( id,org_run_id,activation_generation,work_revision,request_id,request_digest, outcome,summary,coordinator_session_id,coordinator_turn_intent_id, evidence_task_ids_json,closure_task_ids_json,task_output_refs_json, @@ -1026,7 +1026,7 @@ fn persist_validated_outcome_in_tx( ) -> Result<(), String> { let changed = conn .execute( - "UPDATE agent_org_runtime_runs + "UPDATE agent_org_execution_runs SET last_activity_outcome=?1,updated_at=?2 WHERE id=?3 AND status='running' AND activation_generation=?4", params![ @@ -1372,7 +1372,7 @@ pub(crate) fn valid_team_user_event( ) -> Result { conn.query_row( "WITH RECURSIVE team_sessions(session_id) AS ( - SELECT root_session_id FROM agent_org_runtime_runs WHERE id=?1 + SELECT root_session_id FROM agent_org_execution_runs WHERE id=?1 UNION ALL SELECT child.session_id FROM agent_sessions child @@ -1415,7 +1415,7 @@ fn valid_user_scope_removal_source( conn.query_row( "SELECT EXISTS( SELECT 1 - FROM agent_org_runtime_task_events event + FROM agent_org_execution_task_events event WHERE event.org_run_id=?1 AND event.task_id=?2 AND event.event_type='updated' AND event.next_status='cancelled' @@ -1436,10 +1436,10 @@ pub fn load_current_episode_with_connection( conn.query_row( &format!( "SELECT {CERTIFICATE_COLUMNS} - FROM agent_org_runtime_run_completion_certificates + FROM agent_org_execution_run_completion_certificates WHERE id=( SELECT current_episode.certificate_id - FROM agent_org_runtime_work_episodes current_episode + FROM agent_org_execution_work_episodes current_episode WHERE current_episode.org_run_id=?1 ORDER BY current_episode.episode_sequence DESC LIMIT 1 )" @@ -1458,7 +1458,7 @@ pub fn load_with_connection( conn.query_row( &format!( "SELECT {CERTIFICATE_COLUMNS} - FROM agent_org_runtime_run_completion_certificates WHERE id=?1" + FROM agent_org_execution_run_completion_certificates WHERE id=?1" ), [certificate_id], decode_certificate, @@ -1671,18 +1671,18 @@ mod tests { fn user_scope_removal_requires_exact_team_user_event() { let conn = Connection::open_in_memory().unwrap(); conn.execute_batch( - "CREATE TABLE agent_org_runtime_runs(id TEXT PRIMARY KEY,root_session_id TEXT); + "CREATE TABLE agent_org_execution_runs(id TEXT PRIMARY KEY,root_session_id TEXT); CREATE TABLE agent_sessions(session_id TEXT PRIMARY KEY,parent_session_id TEXT); CREATE TABLE events( id TEXT PRIMARY KEY,session_id TEXT,event_type TEXT, function_name TEXT,meta_json TEXT ); - CREATE TABLE agent_org_runtime_task_events( + CREATE TABLE agent_org_execution_task_events( id TEXT PRIMARY KEY,org_run_id TEXT,task_id TEXT,event_type TEXT, next_status TEXT,actor_member_id TEXT,actor_kind TEXT, source_turn_intent_id TEXT ); - INSERT INTO agent_org_runtime_runs(id,root_session_id) VALUES ('run','root'); + INSERT INTO agent_org_execution_runs(id,root_session_id) VALUES ('run','root'); INSERT INTO agent_sessions(session_id,parent_session_id) VALUES ('root',NULL); INSERT INTO events(id,session_id,event_type,function_name,meta_json) VALUES ('user-event','root','raw','user_message','{\"source\":\"user\"}'), @@ -1741,7 +1741,7 @@ mod tests { "run_completion_scope_removal_source_invalid:run-view-removed" ); conn.execute_batch( - "INSERT INTO agent_org_runtime_task_events( + "INSERT INTO agent_org_execution_task_events( id,org_run_id,task_id,event_type,next_status,actor_member_id, actor_kind,source_turn_intent_id ) VALUES ( @@ -1799,11 +1799,11 @@ mod tests { fn validated_outcome_is_owned_by_the_certificate_transaction() { let mut conn = Connection::open_in_memory().unwrap(); conn.execute_batch( - "CREATE TABLE agent_org_runtime_runs( + "CREATE TABLE agent_org_execution_runs( id TEXT PRIMARY KEY,status TEXT,activation_generation INTEGER, last_activity_outcome TEXT,updated_at TEXT ); - INSERT INTO agent_org_runtime_runs + INSERT INTO agent_org_execution_runs VALUES ('run','running',1,NULL,'before');", ) .unwrap(); @@ -1813,7 +1813,7 @@ mod tests { .unwrap(); assert_eq!( tx.query_row( - "SELECT last_activity_outcome FROM agent_org_runtime_runs WHERE id='run'", + "SELECT last_activity_outcome FROM agent_org_execution_runs WHERE id='run'", [], |row| row.get::<_, String>(0), ) @@ -1823,7 +1823,7 @@ mod tests { tx.rollback().unwrap(); assert!(conn .query_row( - "SELECT last_activity_outcome FROM agent_org_runtime_runs WHERE id='run'", + "SELECT last_activity_outcome FROM agent_org_execution_runs WHERE id='run'", [], |row| row.get::<_, Option>(0), ) @@ -1840,7 +1840,7 @@ mod tests { .unwrap(); assert_eq!( conn.query_row( - "SELECT last_activity_outcome FROM agent_org_runtime_runs WHERE id='run'", + "SELECT last_activity_outcome FROM agent_org_execution_runs WHERE id='run'", [], |row| row.get::<_, String>(0), ) @@ -1864,11 +1864,11 @@ mod tests { fn certificate_request_replay_is_read_only_and_digest_conflict_fails_closed() { let conn = Connection::open_in_memory().unwrap(); conn.execute_batch( - "CREATE TABLE agent_org_runtime_runs( + "CREATE TABLE agent_org_execution_runs( id TEXT PRIMARY KEY,status TEXT,activation_generation INTEGER, root_session_id TEXT ); - INSERT INTO agent_org_runtime_runs + INSERT INTO agent_org_execution_runs VALUES ('run','running',1,'root');", ) .unwrap(); @@ -1878,7 +1878,7 @@ mod tests { crate::coordination::agent_org_formal_triggers::create_schema(&conn).unwrap(); crate::coordination::agent_org_final_summary::create_schema(&conn).unwrap(); conn.execute( - "INSERT INTO agent_org_runtime_run_completion_certificates( + "INSERT INTO agent_org_execution_run_completion_certificates( id,org_run_id,activation_generation,work_revision,request_id,request_digest, outcome,summary,coordinator_session_id,coordinator_turn_intent_id, evidence_task_ids_json,closure_task_ids_json,task_output_refs_json, @@ -1892,7 +1892,7 @@ mod tests { ) .unwrap(); conn.execute_batch( - "INSERT INTO agent_org_runtime_work_episodes( + "INSERT INTO agent_org_execution_work_episodes( id,org_run_id,episode_sequence,status,opening_activation_generation, closing_activation_generation,opening_work_revision,closing_work_revision, outcome,certificate_id,opened_by_turn_intent_id,created_at,closed_at @@ -1919,7 +1919,7 @@ mod tests { assert_eq!(replay.id, "certificate"); let count: i64 = conn .query_row( - "SELECT COUNT(*) FROM agent_org_runtime_run_completion_certificates", + "SELECT COUNT(*) FROM agent_org_execution_run_completion_certificates", [], |row| row.get(0), ) diff --git a/src-tauri/crates/agent-core/src/core/coordination/agent_org_run_completion/keep_stopped_tests.rs b/src-tauri/crates/agent-core/src/core/coordination/agent_org_run_completion/keep_stopped_tests.rs index 83a6e2e01a..7490852edc 100644 --- a/src-tauri/crates/agent-core/src/core/coordination/agent_org_run_completion/keep_stopped_tests.rs +++ b/src-tauri/crates/agent-core/src/core/coordination/agent_org_run_completion/keep_stopped_tests.rs @@ -14,12 +14,12 @@ fn keep_stopped_closes_the_last_open_scope_as_cancelled() { crate::coordination::agent_org_task_handoffs::create_schema(&conn).unwrap(); crate::coordination::agent_org_final_summary::create_schema(&conn).unwrap(); conn.execute_batch( - r#"INSERT INTO agent_org_runtime_runs( + r#"INSERT INTO agent_org_execution_runs( id,org_id,coordinator_agent_id,root_session_id,entry_mode,status, activation_generation,created_at,updated_at ) VALUES ('run','org','coordinator-agent','root','standalone_session', 'running',3,'2026-08-28T00:00:00Z','2026-08-28T00:00:00Z'); - INSERT INTO agent_org_runtime_tasks( + INSERT INTO agent_org_execution_tasks( id,org_run_id,activation_generation,subject,owner,status,execution_mode, cancel_reason_json,created_by_participant_id,source_turn_intent_id, created_at,updated_at @@ -48,7 +48,7 @@ fn keep_stopped_closes_the_last_open_scope_as_cancelled() { episode ); conn.execute( - "INSERT INTO agent_org_runtime_task_execution_handoffs( + "INSERT INTO agent_org_execution_task_execution_handoffs( id,org_run_id,activation_generation,request_id,request_digest, old_task_id,old_owner_member_id,replacement_task_id,state, resolution,requested_at,released_at,resolved_at,updated_at @@ -64,7 +64,7 @@ fn keep_stopped_closes_the_last_open_scope_as_cancelled() { let episode_state: (String, String, String) = conn .query_row( "SELECT status,outcome,certificate_id - FROM agent_org_runtime_work_episodes WHERE id=?1", + FROM agent_org_execution_work_episodes WHERE id=?1", [&episode], |row| Ok((row.get(0)?, row.get(1)?, row.get(2)?)), ) @@ -79,7 +79,7 @@ fn keep_stopped_closes_the_last_open_scope_as_cancelled() { ); assert_eq!( conn.query_row( - "SELECT last_activity_outcome FROM agent_org_runtime_runs WHERE id='run'", + "SELECT last_activity_outcome FROM agent_org_execution_runs WHERE id='run'", [], |row| row.get::<_, String>(0), ) @@ -88,7 +88,7 @@ fn keep_stopped_closes_the_last_open_scope_as_cancelled() { ); assert_eq!( conn.query_row( - "SELECT status FROM agent_org_runtime_final_summary_receipts + "SELECT status FROM agent_org_execution_final_summary_receipts WHERE certificate_id=?1", [&certificate.id], |row| row.get::<_, String>(0), diff --git a/src-tauri/crates/agent-core/src/core/coordination/agent_org_run_completion/notifications.rs b/src-tauri/crates/agent-core/src/core/coordination/agent_org_run_completion/notifications.rs index 5a19626b75..0d389046ce 100644 --- a/src-tauri/crates/agent-core/src/core/coordination/agent_org_run_completion/notifications.rs +++ b/src-tauri/crates/agent-core/src/core/coordination/agent_org_run_completion/notifications.rs @@ -30,10 +30,10 @@ pub(super) fn assess_notifications( "SELECT inbox.id,CASE WHEN length(CAST(inbox.payload_json AS BLOB))<=?2 THEN inbox.payload_json ELSE 'null' END,inbox.sender_agent_id,inbox.payload_kind, receipt.source_kind,COALESCE(inbox.source_turn_intent_id,receipt.source_turn_intent_id),receipt.task_output_digest, COALESCE(receipt.status IN ('pending','materialized'),0) - FROM agent_org_runtime_inbox inbox - LEFT JOIN agent_org_runtime_formal_trigger_receipts receipt ON receipt.inbox_id=inbox.id + FROM agent_org_execution_inbox inbox + LEFT JOIN agent_org_execution_formal_trigger_receipts receipt ON receipt.inbox_id=inbox.id WHERE inbox.org_run_id=?1 AND inbox.recipient_member_id='coordinator' AND inbox.read_at IS NULL - AND NOT EXISTS(SELECT 1 FROM agent_org_runtime_inbox_delivery_resolutions resolution WHERE resolution.inbox_id=inbox.id) + AND NOT EXISTS(SELECT 1 FROM agent_org_execution_inbox_delivery_resolutions resolution WHERE resolution.inbox_id=inbox.id) ORDER BY inbox.id").map_err(|e| e.to_string())?; // Stream only this run's unresolved input, one bounded payload at a time. // A row-count cutoff must not manufacture model work or hide a later @@ -72,9 +72,9 @@ pub(super) fn assess_notifications( if candidate.projected_inbox_ids.contains(&id) { let exact: bool = conn .query_row( - "SELECT EXISTS(SELECT 1 FROM agent_org_runtime_inbox_materializations materialization - LEFT JOIN agent_org_runtime_formal_trigger_receipts receipt ON receipt.inbox_id=materialization.inbox_id - LEFT JOIN agent_org_runtime_formal_trigger_attempts attempt ON attempt.receipt_id=receipt.receipt_id AND attempt.attempt=receipt.current_attempt + "SELECT EXISTS(SELECT 1 FROM agent_org_execution_inbox_materializations materialization + LEFT JOIN agent_org_execution_formal_trigger_receipts receipt ON receipt.inbox_id=materialization.inbox_id + LEFT JOIN agent_org_execution_formal_trigger_attempts attempt ON attempt.receipt_id=receipt.receipt_id AND attempt.attempt=receipt.current_attempt WHERE materialization.inbox_id=?1 AND materialization.session_id=?2 AND (receipt.receipt_id IS NULL OR (attempt.session_id=?2 AND attempt.turn_intent_id=?3 AND attempt.status IN ('running','queued'))))", params![ @@ -136,7 +136,7 @@ pub(super) fn request_input_in_tx( assessment: &NotificationAssessment, ) -> Result<(), String> { for inbox_id in &assessment.needs_model_ids { - let exists:bool=conn.query_row("SELECT EXISTS(SELECT 1 FROM agent_org_runtime_formal_trigger_receipts WHERE inbox_id=?1)", + let exists:bool=conn.query_row("SELECT EXISTS(SELECT 1 FROM agent_org_execution_formal_trigger_receipts WHERE inbox_id=?1)", [inbox_id],|r|r.get(0)).map_err(|e|e.to_string())?; if exists { continue; @@ -193,15 +193,15 @@ fn classify( // Exact producer Turn, completed task in this episode, and no newer // work for that member. An old idle can never settle a new execution. let status: Option = conn.query_row( - "SELECT intent.status FROM agent_org_runtime_turn_contexts context + "SELECT intent.status FROM agent_org_execution_turn_contexts context JOIN session_turn_intents intent USING(session_id,turn_intent_id) - JOIN agent_org_runtime_runs run ON run.id=context.org_run_id - JOIN agent_org_runtime_tasks task ON task.org_run_id=context.org_run_id AND task.id=context.task_id - JOIN agent_org_runtime_work_episode_tasks episode_task ON episode_task.org_run_id=task.org_run_id AND episode_task.task_id=task.id + JOIN agent_org_execution_runs run ON run.id=context.org_run_id + JOIN agent_org_execution_tasks task ON task.org_run_id=context.org_run_id AND task.id=context.task_id + JOIN agent_org_execution_work_episode_tasks episode_task ON episode_task.org_run_id=task.org_run_id AND episode_task.task_id=task.id WHERE context.org_run_id=?1 AND context.turn_intent_id=?2 AND context.participant_id=?3 AND context.turn_kind='task_execution' AND task.status='completed' AND episode_task.work_episode_id=?4 - AND NOT EXISTS(SELECT 1 FROM agent_org_runtime_turn_contexts newer + AND NOT EXISTS(SELECT 1 FROM agent_org_execution_turn_contexts newer JOIN session_turn_intents next USING(session_id,turn_intent_id) WHERE newer.org_run_id=context.org_run_id AND newer.participant_id=context.participant_id AND newer.context_id>context.context_id @@ -225,7 +225,7 @@ fn classify( return Ok(NotificationDecision::NeedsModel); }; let raw: Option = conn.query_row( - "SELECT output_json FROM agent_org_runtime_tasks WHERE org_run_id=?1 AND id=?2 AND status='completed'", + "SELECT output_json FROM agent_org_execution_tasks WHERE org_run_id=?1 AND id=?2 AND status='completed'", params![run_id,task_id],|r|r.get(0)).optional().map_err(|e|e.to_string())?.flatten(); let Some(raw) = raw else { return Ok(NotificationDecision::Invalid); @@ -277,21 +277,21 @@ pub(super) fn reconcile_in_tx( "coordinatorSessionId":candidate.coordinator_session_id,"coordinatorTurnIntentId":candidate.coordinator_turn_intent_id, "evidence":evidence}).to_string(); conn.execute( - "INSERT INTO agent_org_runtime_inbox_delivery_resolutions + "INSERT INTO agent_org_execution_inbox_delivery_resolutions (inbox_id,org_run_id,resolution_kind,resolved_by_member_id,reason,created_at) SELECT id,org_run_id,'system_reconciled','system:completion',?3,?4 - FROM agent_org_runtime_inbox WHERE id=?1 AND org_run_id=?2 AND read_at IS NULL + FROM agent_org_execution_inbox WHERE id=?1 AND org_run_id=?2 AND read_at IS NULL ON CONFLICT(inbox_id) DO NOTHING", params![inbox_id, run_id, reason, now], ) .map_err(|e| e.to_string())?; - conn.execute("UPDATE agent_org_runtime_formal_trigger_attempts SET status='resolved',terminal_at=?2,updated_at=?2 - WHERE receipt_id IN(SELECT receipt_id FROM agent_org_runtime_formal_trigger_receipts WHERE inbox_id=?1) + conn.execute("UPDATE agent_org_execution_formal_trigger_attempts SET status='resolved',terminal_at=?2,updated_at=?2 + WHERE receipt_id IN(SELECT receipt_id FROM agent_org_execution_formal_trigger_receipts WHERE inbox_id=?1) AND status IN ('queued','running')",params![inbox_id,now]).map_err(|e|e.to_string())?; - conn.execute("UPDATE agent_org_runtime_formal_trigger_receipts SET status='resolved',doorbell_status='suppressed',resolved_at=?2,updated_at=?2 + conn.execute("UPDATE agent_org_execution_formal_trigger_receipts SET status='resolved',doorbell_status='suppressed',resolved_at=?2,updated_at=?2 WHERE inbox_id=?1 AND status<>'resolved'",params![inbox_id,now]).map_err(|e|e.to_string())?; conn.execute( - "DELETE FROM agent_org_runtime_inbox_materializations WHERE inbox_id=?1", + "DELETE FROM agent_org_execution_inbox_materializations WHERE inbox_id=?1", [inbox_id], ) .map_err(|e| e.to_string())?; @@ -319,39 +319,39 @@ mod tests { fn fixture() -> Connection { let conn = Connection::open_in_memory().expect("in-memory database"); conn.execute_batch( - "CREATE TABLE agent_org_runtime_runs( + "CREATE TABLE agent_org_execution_runs( id TEXT PRIMARY KEY,activation_generation INTEGER NOT NULL ); CREATE TABLE session_turn_intents( session_id TEXT NOT NULL,turn_intent_id TEXT NOT NULL,status TEXT NOT NULL, PRIMARY KEY(session_id,turn_intent_id) ); - CREATE TABLE agent_org_runtime_turn_contexts( + CREATE TABLE agent_org_execution_turn_contexts( context_id INTEGER PRIMARY KEY AUTOINCREMENT, session_id TEXT NOT NULL,turn_intent_id TEXT NOT NULL, org_run_id TEXT NOT NULL,participant_id TEXT NOT NULL, turn_kind TEXT NOT NULL,task_id TEXT,activation_generation INTEGER ); - CREATE TABLE agent_org_runtime_tasks( + CREATE TABLE agent_org_execution_tasks( org_run_id TEXT NOT NULL,id TEXT NOT NULL,status TEXT NOT NULL, activation_generation INTEGER NOT NULL,PRIMARY KEY(org_run_id,id) ); - CREATE TABLE agent_org_runtime_work_episode_tasks( + CREATE TABLE agent_org_execution_work_episode_tasks( org_run_id TEXT NOT NULL,work_episode_id TEXT NOT NULL,task_id TEXT NOT NULL ); - INSERT INTO agent_org_runtime_runs VALUES('run',4); + INSERT INTO agent_org_execution_runs VALUES('run',4); INSERT INTO session_turn_intents VALUES( 'member-session','turn-before-pause','completed' ); - INSERT INTO agent_org_runtime_turn_contexts( + INSERT INTO agent_org_execution_turn_contexts( session_id,turn_intent_id,org_run_id,participant_id,turn_kind, task_id,activation_generation ) VALUES( 'member-session','turn-before-pause','run','member','task_execution', 'task',2 ); - INSERT INTO agent_org_runtime_tasks VALUES('run','task','completed',2); - INSERT INTO agent_org_runtime_work_episode_tasks VALUES( + INSERT INTO agent_org_execution_tasks VALUES('run','task','completed',2); + INSERT INTO agent_org_execution_work_episode_tasks VALUES( 'run','episode','task' );", ) @@ -396,7 +396,7 @@ mod tests { "INSERT INTO session_turn_intents VALUES( 'member-session','turn-after-resume','running' ); - INSERT INTO agent_org_runtime_turn_contexts( + INSERT INTO agent_org_execution_turn_contexts( session_id,turn_intent_id,org_run_id,participant_id,turn_kind, task_id,activation_generation ) VALUES( diff --git a/src-tauri/crates/agent-core/src/core/coordination/agent_org_run_completion/pending.rs b/src-tauri/crates/agent-core/src/core/coordination/agent_org_run_completion/pending.rs index 34d3fa9c60..4c52a2823a 100644 --- a/src-tauri/crates/agent-core/src/core/coordination/agent_org_run_completion/pending.rs +++ b/src-tauri/crates/agent-core/src/core/coordination/agent_org_run_completion/pending.rs @@ -97,7 +97,7 @@ fn blocked( "completion_blocked:{:x}", sha2::Sha256::digest(facts.to_string()) ); - let repeated:bool=conn.query_row("SELECT EXISTS(SELECT 1 FROM agent_org_runtime_tool_call_receipts + let repeated:bool=conn.query_row("SELECT EXISTS(SELECT 1 FROM agent_org_execution_tool_call_receipts WHERE org_run_id=?1 AND session_id=?2 AND turn_intent_id=?3 AND tool_name='org_run_complete' AND CASE WHEN json_valid(result_text) THEN json_extract(result_text,'$.facts_fingerprint')=?4 ELSE 0 END)", params![run_id,candidate.coordinator_session_id,candidate.coordinator_turn_intent_id,fingerprint],|r|r.get(0)).map_err(|e|e.to_string())?; @@ -111,7 +111,7 @@ fn blocked( fn clear(conn: &Connection, run_id: &str) -> Result<(), String> { conn.execute( - "UPDATE agent_org_runtime_run_progress SET completion_candidate_json=NULL, + "UPDATE agent_org_execution_run_progress SET completion_candidate_json=NULL, completion_requested=0,completion_requested_at=NULL,completion_requested_work_revision=NULL, completion_summary=NULL WHERE org_run_id=?1 AND completion_candidate_json IS NOT NULL", [run_id], @@ -195,7 +195,7 @@ pub(crate) fn submit_in_tx( request_input_in_tx(conn, run_id, ¬ices)?; return Ok(CompletionSubmission::RequiresInput { guidance:"New results or messages require review. End this Turn; the pending input will be delivered once.".into() }); } - let mut statement=conn.prepare("SELECT context.session_id,context.turn_intent_id FROM agent_org_runtime_turn_contexts context + let mut statement=conn.prepare("SELECT context.session_id,context.turn_intent_id FROM agent_org_execution_turn_contexts context JOIN session_turn_intents intent USING(session_id,turn_intent_id) WHERE context.org_run_id=?1 AND context.turn_kind='task_execution' AND intent.status IN ('optimistic','queued','running')").map_err(|e|e.to_string())?; let waiting_turns = statement @@ -228,7 +228,7 @@ pub(crate) fn submit_in_tx( .is_some_and(|p| p.turn_intent_id == pending.turn_intent_id && p.work_revision == revision) { conn.execute( - "UPDATE agent_org_runtime_run_progress SET completion_candidate_json=?2, + "UPDATE agent_org_execution_run_progress SET completion_candidate_json=?2, completion_requested=1,completion_requested_at=?3,completion_requested_work_revision=?4, completion_summary=?5,updated_at=?3 WHERE org_run_id=?1", params![ @@ -242,7 +242,7 @@ pub(crate) fn submit_in_tx( .map_err(|e| e.to_string())?; } conn.execute( - "UPDATE agent_org_runtime_turn_contexts SET terminal_reason='waiting_for_org_event' + "UPDATE agent_org_execution_turn_contexts SET terminal_reason='waiting_for_org_event' WHERE session_id=?1 AND turn_intent_id=?2", params![pending.session_id, pending.turn_intent_id], ) @@ -254,7 +254,7 @@ pub(crate) fn submit_in_tx( } fn load(conn: &Connection, run_id: &str) -> Result, String> { - let raw:Option=conn.query_row("SELECT completion_candidate_json FROM agent_org_runtime_run_progress WHERE org_run_id=?1", + let raw:Option=conn.query_row("SELECT completion_candidate_json FROM agent_org_execution_run_progress WHERE org_run_id=?1", [run_id],|r|r.get(0)).optional().map_err(|e|e.to_string())?.flatten(); raw.map(|raw| serde_json::from_str(&raw).map_err(|e| e.to_string())) .transpose() @@ -269,9 +269,9 @@ pub(crate) fn recheck_pending_in_tx(conn: &Connection, run_id: &str) -> Result Resultoriginal.context_id AND intent.source<>'resume' AND intent.status NOT IN ('cancelled','rejected','stale','coalesced'))", @@ -323,7 +323,7 @@ pub(crate) fn recheck_pending_in_tx(conn: &Connection, run_id: &str) -> Result=conn.query_row("SELECT output_json FROM agent_org_runtime_tasks WHERE org_run_id=?1 AND id=?2 AND status='completed'",params![run_id,expected.task_id],|r|r.get(0)).optional().map_err(|e|e.to_string())?.flatten(); + let raw:Option=conn.query_row("SELECT output_json FROM agent_org_execution_tasks WHERE org_run_id=?1 AND id=?2 AND status='completed'",params![run_id,expected.task_id],|r|r.get(0)).optional().map_err(|e|e.to_string())?.flatten(); let output = raw .map(|raw| serde_json::from_str::(&raw)) .transpose() @@ -364,7 +364,7 @@ pub(crate) fn recheck_pending_in_tx(conn: &Connection, run_id: &str) -> Result Result { let tx = database::db::begin_immediate(&conn).map_err(|e| e.to_string())?; let waiting = recheck_pending_in_tx(&tx, run_id)?; let certified = current_authority_certificate(&tx, run_id)?.is_some(); - let pending:bool=tx.query_row("SELECT EXISTS(SELECT 1 FROM agent_org_runtime_formal_trigger_receipts WHERE org_run_id=?1 AND status IN ('pending','materialized'))",[run_id],|r|r.get(0)).map_err(|e|e.to_string())?; - let unread: bool = tx.query_row("SELECT EXISTS(SELECT 1 FROM agent_org_runtime_inbox inbox + let pending:bool=tx.query_row("SELECT EXISTS(SELECT 1 FROM agent_org_execution_formal_trigger_receipts WHERE org_run_id=?1 AND status IN ('pending','materialized'))",[run_id],|r|r.get(0)).map_err(|e|e.to_string())?; + let unread: bool = tx.query_row("SELECT EXISTS(SELECT 1 FROM agent_org_execution_inbox inbox WHERE inbox.org_run_id=?1 AND inbox.recipient_member_id='coordinator' AND inbox.read_at IS NULL - AND NOT EXISTS(SELECT 1 FROM agent_org_runtime_inbox_delivery_resolutions resolution WHERE resolution.inbox_id=inbox.id))", + AND NOT EXISTS(SELECT 1 FROM agent_org_execution_inbox_delivery_resolutions resolution WHERE resolution.inbox_id=inbox.id))", [run_id], |r|r.get(0)).map_err(|e|e.to_string())?; tx.commit().map_err(|e| e.to_string())?; Ok(waiting || (certified && !pending && !unread)) @@ -464,9 +464,9 @@ pub(crate) fn recheck_after_turn( )?; recheck_pending_in_tx(&tx, &context.org_run_id)?; let ids = { - let mut stmt=tx.prepare("SELECT receipt_id FROM agent_org_runtime_formal_trigger_receipts + let mut stmt=tx.prepare("SELECT receipt_id FROM agent_org_execution_formal_trigger_receipts WHERE org_run_id=?1 AND status='pending' AND doorbell_status='missing' - AND (trigger_kind='final_summary' OR EXISTS(SELECT 1 FROM agent_org_runtime_inbox inbox WHERE inbox.id=agent_org_runtime_formal_trigger_receipts.inbox_id AND inbox.recipient_member_id='coordinator')) + AND (trigger_kind='final_summary' OR EXISTS(SELECT 1 FROM agent_org_execution_inbox inbox WHERE inbox.id=agent_org_execution_formal_trigger_receipts.inbox_id AND inbox.recipient_member_id='coordinator')) ORDER BY created_at,receipt_id LIMIT 100").map_err(|e|e.to_string())?; let ids = stmt .query_map([&context.org_run_id], |r| r.get(0)) @@ -483,7 +483,7 @@ pub(crate) fn recheck_after_turn( /// Startup already reconciled interrupted Turns and paused absent runtimes. /// Revisit only saved candidates; stale authority must not survive recovery. pub(crate) fn reconcile_after_restart(conn: &Connection) -> Result { - let mut stmt=conn.prepare("SELECT org_run_id FROM agent_org_runtime_run_progress WHERE completion_candidate_json IS NOT NULL").map_err(|e|e.to_string())?; + let mut stmt=conn.prepare("SELECT org_run_id FROM agent_org_execution_run_progress WHERE completion_candidate_json IS NOT NULL").map_err(|e|e.to_string())?; let run_ids = stmt .query_map([], |r| r.get::<_, String>(0)) .map_err(|e| e.to_string())? @@ -508,12 +508,12 @@ pub(crate) fn settle_completion_only_wake( let conn = database::db::get_connection().map_err(|e| e.to_string())?; let tx = database::db::begin_immediate(&conn).map_err(|e| e.to_string())?; let identity:Option<(String,String)>=tx.query_row("SELECT context.org_run_id,intent.status - FROM agent_org_runtime_turn_contexts context JOIN session_turn_intents intent USING(session_id,turn_intent_id) - JOIN agent_org_runtime_runs run ON run.id=context.org_run_id + FROM agent_org_execution_turn_contexts context JOIN session_turn_intents intent USING(session_id,turn_intent_id) + JOIN agent_org_execution_runs run ON run.id=context.org_run_id WHERE context.session_id=?1 AND context.turn_intent_id=?2 AND context.participant_id='coordinator' AND context.source_kind='root_turn' AND intent.source='resume' AND intent.status IN ('queued','running') AND context.activation_generation=run.activation_generation AND run.status='running' - AND NOT EXISTS(SELECT 1 FROM agent_org_runtime_final_summary_receipts summary + AND NOT EXISTS(SELECT 1 FROM agent_org_execution_final_summary_receipts summary WHERE summary.coordinator_session_id=?1 AND summary.turn_intent_id=?2)", params![session_id,turn_intent_id],|r|Ok((r.get(0)?,r.get(1)?))).optional().map_err(|e|e.to_string())?; let Some((run_id, _status)) = identity else { @@ -539,8 +539,8 @@ pub(crate) fn settle_completion_only_wake( )?; let waiting = recheck_pending_in_tx(&tx, &run_id)?; let certified = current_authority_certificate(&tx, &run_id)?.is_some(); - let needs_input:bool=tx.query_row("SELECT EXISTS(SELECT 1 FROM agent_org_runtime_inbox inbox WHERE inbox.org_run_id=?1 AND inbox.recipient_member_id='coordinator' AND inbox.read_at IS NULL - AND NOT EXISTS(SELECT 1 FROM agent_org_runtime_inbox_delivery_resolutions resolution WHERE resolution.inbox_id=inbox.id))",[&run_id],|r|r.get(0)).map_err(|e|e.to_string())?; + let needs_input:bool=tx.query_row("SELECT EXISTS(SELECT 1 FROM agent_org_execution_inbox inbox WHERE inbox.org_run_id=?1 AND inbox.recipient_member_id='coordinator' AND inbox.read_at IS NULL + AND NOT EXISTS(SELECT 1 FROM agent_org_execution_inbox_delivery_resolutions resolution WHERE resolution.inbox_id=inbox.id))",[&run_id],|r|r.get(0)).map_err(|e|e.to_string())?; let handled = waiting || (certified && !needs_input); if !handled { tx.execute_batch("ROLLBACK TO completion_wake") @@ -565,8 +565,8 @@ pub(crate) fn recheck_after_wake(run_id: &str) -> Result, String> { } recheck_pending_in_tx(&tx, run_id)?; let ids = if let Some(certificate) = current_authority_certificate(&tx, run_id)? { - let mut stmt=tx.prepare("SELECT trigger.receipt_id FROM agent_org_runtime_formal_trigger_receipts trigger - JOIN agent_org_runtime_final_summary_receipts summary ON trigger.trigger_id=summary.receipt_id + let mut stmt=tx.prepare("SELECT trigger.receipt_id FROM agent_org_execution_formal_trigger_receipts trigger + JOIN agent_org_execution_final_summary_receipts summary ON trigger.trigger_id=summary.receipt_id WHERE trigger.org_run_id=?1 AND trigger.trigger_kind='final_summary' AND trigger.status='pending' AND trigger.doorbell_status='missing' AND summary.certificate_id=?2 LIMIT 1").map_err(|e|e.to_string())?; let ids = stmt diff --git a/src-tauri/crates/agent-core/src/core/coordination/agent_org_run_completion/presentation.rs b/src-tauri/crates/agent-core/src/core/coordination/agent_org_run_completion/presentation.rs index 95b746e7c1..e8bdf23f50 100644 --- a/src-tauri/crates/agent-core/src/core/coordination/agent_org_run_completion/presentation.rs +++ b/src-tauri/crates/agent-core/src/core/coordination/agent_org_run_completion/presentation.rs @@ -92,7 +92,7 @@ pub(crate) fn record_provider_presentation( let current: bool = tx .query_row( "SELECT EXISTS(SELECT 1 FROM session_turn_intents intent - JOIN agent_org_runtime_runs run ON run.id=?3 + JOIN agent_org_execution_runs run ON run.id=?3 WHERE intent.session_id=?1 AND intent.turn_intent_id=?2 AND intent.status='running' AND run.activation_generation=?4 AND run.status='running')", params![ @@ -108,7 +108,7 @@ pub(crate) fn record_provider_presentation( return Ok(()); } let raw: String = tx.query_row( - "SELECT coordinator_presented_outputs_json FROM agent_org_runtime_turn_contexts WHERE context_id=?1", + "SELECT coordinator_presented_outputs_json FROM agent_org_execution_turn_contexts WHERE context_id=?1", [context.context_id], |row| row.get(0)).map_err(|e| e.to_string())?; let mut presented: Vec = serde_json::from_str(&raw).map_err(|e| e.to_string())?; @@ -122,7 +122,7 @@ pub(crate) fn record_provider_presentation( continue; } let stored: Option = tx.query_row( - "SELECT output_json FROM agent_org_runtime_tasks WHERE org_run_id=?1 AND id=?2 AND status='completed'", + "SELECT output_json FROM agent_org_execution_tasks WHERE org_run_id=?1 AND id=?2 AND status='completed'", params![context.org_run_id,task_id], |row| row.get(0)).optional().map_err(|e| e.to_string())?.flatten(); let stored = stored .map(|raw| serde_json::from_str::(&raw)) @@ -144,7 +144,7 @@ pub(crate) fn record_provider_presentation( if presented.len() > 128 { presented.drain(..presented.len() - 128); } - tx.execute("UPDATE agent_org_runtime_turn_contexts SET coordinator_presented_outputs_json=?2 WHERE context_id=?1", + tx.execute("UPDATE agent_org_execution_turn_contexts SET coordinator_presented_outputs_json=?2 WHERE context_id=?1", params![context.context_id,serde_json::to_string(&presented).map_err(|e| e.to_string())?]).map_err(|e| e.to_string())?; tx.commit().map_err(|e| e.to_string()) }) @@ -161,10 +161,10 @@ pub(super) fn presented_output_evidence( candidate_turn: &str, ) -> Result, String> { conn.query_row( - "SELECT context.session_id,context.turn_intent_id,output.value FROM agent_org_runtime_turn_contexts context + "SELECT context.session_id,context.turn_intent_id,output.value FROM agent_org_execution_turn_contexts context JOIN session_turn_intents intent USING(session_id,turn_intent_id) - JOIN agent_org_runtime_runs run ON run.id=context.org_run_id - JOIN agent_org_runtime_work_episode_tasks episode_task ON episode_task.org_run_id=context.org_run_id AND episode_task.task_id=?3 + JOIN agent_org_execution_runs run ON run.id=context.org_run_id + JOIN agent_org_execution_work_episode_tasks episode_task ON episode_task.org_run_id=context.org_run_id AND episode_task.task_id=?3 JOIN json_each(context.coordinator_presented_outputs_json) output WHERE context.org_run_id=?1 AND episode_task.work_episode_id=?2 AND context.activation_generation=run.activation_generation diff --git a/src-tauri/crates/agent-core/src/core/coordination/agent_org_runs/helpers.rs b/src-tauri/crates/agent-core/src/core/coordination/agent_org_runs/helpers.rs index dffad5105f..17443389de 100644 --- a/src-tauri/crates/agent-core/src/core/coordination/agent_org_runs/helpers.rs +++ b/src-tauri/crates/agent-core/src/core/coordination/agent_org_runs/helpers.rs @@ -65,7 +65,7 @@ pub(super) fn load_by_id(run_id: &str) -> SqliteResult idled_at, archived_at, archive_receipt_id - FROM agent_org_runtime_runs + FROM agent_org_execution_runs WHERE id = ?1 LIMIT 1", params![run_id], @@ -100,7 +100,7 @@ pub(super) fn load_by_root_session( idled_at, archived_at, archive_receipt_id - FROM agent_org_runtime_runs + FROM agent_org_execution_runs WHERE root_session_id = ?1 ORDER BY created_at DESC LIMIT 1", @@ -210,7 +210,7 @@ pub(super) fn flatten_members( pub(super) fn insert_run(conn: &Connection, run: &AgentOrgRunRecord) -> SqliteResult<()> { conn.execute( - "INSERT INTO agent_org_runtime_runs ( + "INSERT INTO agent_org_execution_runs ( id, org_id, coordinator_agent_id, diff --git a/src-tauri/crates/agent-core/src/core/coordination/agent_org_runs/materialization.rs b/src-tauri/crates/agent-core/src/core/coordination/agent_org_runs/materialization.rs index c2c32f699e..8b8c1bdba1 100644 --- a/src-tauri/crates/agent-core/src/core/coordination/agent_org_runs/materialization.rs +++ b/src-tauri/crates/agent-core/src/core/coordination/agent_org_runs/materialization.rs @@ -138,7 +138,7 @@ pub struct CreateAgentOrgInitialInput { pub(super) fn init_schema(conn: &Connection) -> rusqlite::Result<()> { conn.execute_batch( - "CREATE TABLE IF NOT EXISTS agent_org_runtime_member_materializations ( + "CREATE TABLE IF NOT EXISTS agent_org_execution_member_materializations ( org_run_id TEXT NOT NULL, member_id TEXT NOT NULL, agent_id TEXT NOT NULL, @@ -156,12 +156,12 @@ pub(super) fn init_schema(conn: &Connection) -> rusqlite::Result<()> { updated_at TEXT NOT NULL, PRIMARY KEY(org_run_id, member_id, generation), UNIQUE(org_run_id, session_id), - FOREIGN KEY(org_run_id) REFERENCES agent_org_runtime_runs(id) ON DELETE CASCADE + FOREIGN KEY(org_run_id) REFERENCES agent_org_execution_runs(id) ON DELETE CASCADE ); - CREATE INDEX IF NOT EXISTS idx_agent_org_runtime_member_materializations_pending - ON agent_org_runtime_member_materializations(status, org_run_id, generation); + CREATE INDEX IF NOT EXISTS idx_agent_org_execution_member_materializations_pending + ON agent_org_execution_member_materializations(status, org_run_id, generation); - CREATE TABLE IF NOT EXISTS agent_org_runtime_initial_inputs ( + CREATE TABLE IF NOT EXISTS agent_org_execution_initial_inputs ( org_run_id TEXT PRIMARY KEY, turn_intent_id TEXT NOT NULL, message_id TEXT NOT NULL, @@ -174,10 +174,10 @@ pub(super) fn init_schema(conn: &Connection) -> rusqlite::Result<()> { updated_at TEXT NOT NULL, UNIQUE(turn_intent_id), UNIQUE(message_id), - FOREIGN KEY(org_run_id) REFERENCES agent_org_runtime_runs(id) ON DELETE CASCADE + FOREIGN KEY(org_run_id) REFERENCES agent_org_execution_runs(id) ON DELETE CASCADE ); - CREATE INDEX IF NOT EXISTS idx_agent_org_runtime_initial_inputs_dispatch - ON agent_org_runtime_initial_inputs(status, org_run_id);", + CREATE INDEX IF NOT EXISTS idx_agent_org_execution_initial_inputs_dispatch + ON agent_org_execution_initial_inputs(status, org_run_id);", ) } @@ -194,7 +194,7 @@ pub(super) fn insert_materialization_intent( AgentOrgMaterializationStatus::Pending }; conn.execute( - "INSERT INTO agent_org_runtime_member_materializations ( + "INSERT INTO agent_org_execution_member_materializations ( org_run_id, member_id, agent_id, generation, session_id, authority_class, status, created_at, updated_at ) VALUES (?1, ?2, ?3, ?4, ?5, 'starting', ?6, ?7, ?7)", @@ -219,7 +219,7 @@ pub(super) fn insert_initial_input( now: &str, ) -> Result<(), String> { conn.execute( - "INSERT INTO agent_org_runtime_initial_inputs ( + "INSERT INTO agent_org_execution_initial_inputs ( org_run_id, turn_intent_id, message_id, content, payload_json, status, created_at, updated_at ) VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7, ?7)", @@ -246,7 +246,7 @@ pub(super) fn list_materializations_with_connection( "SELECT org_run_id, member_id, agent_id, generation, session_id, authority_class, status, error_code, error_json, created_at, updated_at - FROM agent_org_runtime_member_materializations + FROM agent_org_execution_member_materializations WHERE org_run_id=?1 ORDER BY member_id ASC", ) @@ -265,7 +265,7 @@ pub(super) fn load_initial_input_with_connection( conn.query_row( "SELECT org_run_id, turn_intent_id, message_id, content, payload_json, status, created_at, updated_at - FROM agent_org_runtime_initial_inputs WHERE org_run_id=?1", + FROM agent_org_execution_initial_inputs WHERE org_run_id=?1", [org_run_id], row_to_initial_input, ) @@ -280,7 +280,7 @@ pub(super) fn load_initial_input_by_turn_with_connection( conn.query_row( "SELECT org_run_id, turn_intent_id, message_id, content, payload_json, status, created_at, updated_at - FROM agent_org_runtime_initial_inputs WHERE turn_intent_id=?1", + FROM agent_org_execution_initial_inputs WHERE turn_intent_id=?1", [turn_intent_id], row_to_initial_input, ) @@ -297,8 +297,8 @@ pub(super) fn load_initial_public_input_for_turn_with_connection( "SELECT initial.org_run_id,initial.turn_intent_id,initial.message_id, initial.content,initial.payload_json,initial.status, initial.created_at,initial.updated_at - FROM agent_org_runtime_initial_inputs initial - JOIN agent_org_runtime_runs run ON run.id=initial.org_run_id + FROM agent_org_execution_initial_inputs initial + JOIN agent_org_execution_runs run ON run.id=initial.org_run_id WHERE run.root_session_id=?1 AND initial.turn_intent_id=?2", rusqlite::params![root_session_id, turn_intent_id], row_to_initial_input, @@ -322,8 +322,8 @@ pub(super) fn list_recoverable_initial_inputs_with_connection( initial.message_id, initial.content, initial.payload_json, initial.status, initial.created_at, initial.updated_at - FROM agent_org_runtime_initial_inputs initial - JOIN agent_org_runtime_runs run ON run.id=initial.org_run_id + FROM agent_org_execution_initial_inputs initial + JOIN agent_org_execution_runs run ON run.id=initial.org_run_id JOIN session_turn_intents turn ON turn.org_run_id=initial.org_run_id AND turn.turn_intent_id=initial.turn_intent_id diff --git a/src-tauri/crates/agent-core/src/core/coordination/agent_org_runs/mod.rs b/src-tauri/crates/agent-core/src/core/coordination/agent_org_runs/mod.rs index fbd829a586..b2dd5c5aeb 100644 --- a/src-tauri/crates/agent-core/src/core/coordination/agent_org_runs/mod.rs +++ b/src-tauri/crates/agent-core/src/core/coordination/agent_org_runs/mod.rs @@ -473,7 +473,7 @@ pub fn init_schema(conn: &Connection) -> SqliteResult<()> { pub(crate) fn create_schema(conn: &Connection) -> SqliteResult<()> { conn.execute_batch( - "CREATE TABLE IF NOT EXISTS agent_org_runtime_runs ( + "CREATE TABLE IF NOT EXISTS agent_org_execution_runs ( id TEXT PRIMARY KEY, org_id TEXT NOT NULL, coordinator_agent_id TEXT NOT NULL, @@ -507,14 +507,14 @@ pub(crate) fn create_schema(conn: &Connection) -> SqliteResult<()> { (status<>'archived' AND archived_at IS NULL AND archive_receipt_id IS NULL) ) ); - CREATE INDEX IF NOT EXISTS idx_agent_org_runtime_runs_org_updated - ON agent_org_runtime_runs(org_id, updated_at); - CREATE INDEX IF NOT EXISTS idx_agent_org_runtime_runs_root_session - ON agent_org_runtime_runs(root_session_id); - CREATE INDEX IF NOT EXISTS idx_agent_org_runtime_runs_work_item - ON agent_org_runtime_runs(work_item_id); - CREATE INDEX IF NOT EXISTS idx_agent_org_runtime_runs_status - ON agent_org_runtime_runs(status);", + CREATE INDEX IF NOT EXISTS idx_agent_org_execution_runs_org_updated + ON agent_org_execution_runs(org_id, updated_at); + CREATE INDEX IF NOT EXISTS idx_agent_org_execution_runs_root_session + ON agent_org_execution_runs(root_session_id); + CREATE INDEX IF NOT EXISTS idx_agent_org_execution_runs_work_item + ON agent_org_execution_runs(work_item_id); + CREATE INDEX IF NOT EXISTS idx_agent_org_execution_runs_status + ON agent_org_execution_runs(status);", )?; materialization::init_schema(conn)?; progress::init_schema(conn)?; diff --git a/src-tauri/crates/agent-core/src/core/coordination/agent_org_runs/progress.rs b/src-tauri/crates/agent-core/src/core/coordination/agent_org_runs/progress.rs index 30c2b3bb28..2a62878260 100644 --- a/src-tauri/crates/agent-core/src/core/coordination/agent_org_runs/progress.rs +++ b/src-tauri/crates/agent-core/src/core/coordination/agent_org_runs/progress.rs @@ -28,7 +28,7 @@ pub struct AgentOrgRunProgress { pub(super) fn init_schema(conn: &Connection) -> rusqlite::Result<()> { conn.execute_batch( - "CREATE TABLE IF NOT EXISTS agent_org_runtime_run_progress ( + "CREATE TABLE IF NOT EXISTS agent_org_execution_run_progress ( org_run_id TEXT PRIMARY KEY, work_revision INTEGER NOT NULL DEFAULT 0 CHECK(work_revision >= 0), coordinator_presented_work_revision INTEGER, @@ -39,14 +39,14 @@ pub(super) fn init_schema(conn: &Connection) -> rusqlite::Result<()> { completion_summary TEXT, completion_candidate_json TEXT CHECK(completion_candidate_json IS NULL OR json_valid(completion_candidate_json)=1), updated_at TEXT NOT NULL, - FOREIGN KEY(org_run_id) REFERENCES agent_org_runtime_runs(id) ON DELETE CASCADE + FOREIGN KEY(org_run_id) REFERENCES agent_org_execution_runs(id) ON DELETE CASCADE );", )?; conn.execute( - "INSERT INTO agent_org_runtime_run_progress (org_run_id, updated_at) - SELECT run.id, run.updated_at FROM agent_org_runtime_runs run + "INSERT INTO agent_org_execution_run_progress (org_run_id, updated_at) + SELECT run.id, run.updated_at FROM agent_org_execution_runs run WHERE NOT EXISTS ( - SELECT 1 FROM agent_org_runtime_run_progress progress + SELECT 1 FROM agent_org_execution_run_progress progress WHERE progress.org_run_id=run.id )", [], @@ -56,7 +56,7 @@ pub(super) fn init_schema(conn: &Connection) -> rusqlite::Result<()> { pub(super) fn ensure_progress_in_conn(conn: &Connection, org_run_id: &str) -> Result<(), String> { conn.execute( - "INSERT INTO agent_org_runtime_run_progress (org_run_id, updated_at) + "INSERT INTO agent_org_execution_run_progress (org_run_id, updated_at) VALUES (?1, ?2) ON CONFLICT(org_run_id) DO NOTHING", params![org_run_id, chrono::Utc::now().to_rfc3339()], @@ -71,7 +71,7 @@ pub(super) fn ensure_progress_in_conn(conn: &Connection, org_run_id: &str) -> Re pub(crate) fn bump_work_revision_in_tx(tx: &Connection, org_run_id: &str) -> Result { ensure_progress_in_conn(tx, org_run_id)?; tx.execute( - "UPDATE agent_org_runtime_run_progress + "UPDATE agent_org_execution_run_progress SET work_revision=work_revision+1, completion_requested=0, completion_requested_at=NULL, @@ -84,7 +84,7 @@ pub(crate) fn bump_work_revision_in_tx(tx: &Connection, org_run_id: &str) -> Res ) .map_err(|error| error.to_string())?; tx.query_row( - "SELECT work_revision FROM agent_org_runtime_run_progress WHERE org_run_id=?1", + "SELECT work_revision FROM agent_org_execution_run_progress WHERE org_run_id=?1", [org_run_id], |row| row.get(0), ) @@ -97,7 +97,7 @@ pub(crate) fn current_work_revision_in_tx( ) -> Result { ensure_progress_in_conn(conn, org_run_id)?; conn.query_row( - "SELECT work_revision FROM agent_org_runtime_run_progress WHERE org_run_id=?1", + "SELECT work_revision FROM agent_org_execution_run_progress WHERE org_run_id=?1", [org_run_id], |row| row.get(0), ) @@ -113,7 +113,7 @@ pub(super) fn load_progress_with_conn( coordinator_observed_work_revision,completion_requested, completion_requested_at,completion_requested_work_revision, completion_summary,updated_at - FROM agent_org_runtime_run_progress WHERE org_run_id=?1", + FROM agent_org_execution_run_progress WHERE org_run_id=?1", [org_run_id], row_to_progress, ) @@ -129,8 +129,8 @@ pub(super) fn stage_coordinator_presented_with_conn( let revision = conn .query_row( "SELECT progress.work_revision - FROM agent_org_runtime_run_progress progress - JOIN agent_org_runtime_runs run ON run.id=progress.org_run_id + FROM agent_org_execution_run_progress progress + JOIN agent_org_execution_runs run ON run.id=progress.org_run_id WHERE progress.org_run_id=?1 AND run.status IN ('running','idle')", [org_run_id], @@ -142,7 +142,7 @@ pub(super) fn stage_coordinator_presented_with_conn( return Ok(None); }; conn.execute( - "UPDATE agent_org_runtime_run_progress + "UPDATE agent_org_execution_run_progress SET coordinator_presented_work_revision=?2,updated_at=?3 WHERE org_run_id=?1", params![org_run_id, revision, chrono::Utc::now().to_rfc3339()], @@ -175,7 +175,7 @@ pub(super) fn stage_coordinator_presented_for_turn_with_conn( if let Some(revision) = revision { let updated = conn .execute( - "UPDATE agent_org_runtime_turn_contexts + "UPDATE agent_org_execution_turn_contexts SET coordinator_work_revision=?4,terminal_reason=NULL WHERE org_run_id=?1 AND session_id=?2 AND turn_intent_id=?3 AND turn_kind='coordinator' @@ -206,7 +206,7 @@ pub(crate) fn mark_coordinator_observed_revision_with_conn( } let updated = conn .execute( - "UPDATE agent_org_runtime_run_progress + "UPDATE agent_org_execution_run_progress SET coordinator_observed_work_revision=CASE WHEN coordinator_observed_work_revision IS NULL OR ?2>coordinator_observed_work_revision THEN ?2 @@ -228,7 +228,7 @@ pub(crate) fn mark_coordinator_observed_revision_with_conn( } conn.query_row( "SELECT coordinator_observed_work_revision - FROM agent_org_runtime_run_progress WHERE org_run_id=?1", + FROM agent_org_execution_run_progress WHERE org_run_id=?1", [org_run_id], |row| row.get(0), ) @@ -251,7 +251,7 @@ pub(super) fn record_completion_request_in_tx( let now = chrono::Utc::now().to_rfc3339(); let updated = tx .execute( - "UPDATE agent_org_runtime_run_progress + "UPDATE agent_org_execution_run_progress SET completion_requested=1,completion_requested_at=?2, completion_requested_work_revision=work_revision, completion_summary=?3,updated_at=?2 diff --git a/src-tauri/crates/agent-core/src/core/coordination/agent_org_runs/quiescence.rs b/src-tauri/crates/agent-core/src/core/coordination/agent_org_runs/quiescence.rs index c8b56fdf48..507209ae84 100644 --- a/src-tauri/crates/agent-core/src/core/coordination/agent_org_runs/quiescence.rs +++ b/src-tauri/crates/agent-core/src/core/coordination/agent_org_runs/quiescence.rs @@ -345,13 +345,13 @@ pub(crate) fn guaranteed_current_turn_effects_with_connection( let mut stmt = conn .prepare( "SELECT inbox.payload_kind,inbox.payload_json,inbox.sender_agent_id,inbox.created_at - FROM agent_org_runtime_inbox inbox - JOIN agent_org_runtime_inbox_materializations receipt + FROM agent_org_execution_inbox inbox + JOIN agent_org_execution_inbox_materializations receipt ON receipt.inbox_id=inbox.id AND receipt.session_id=?2 WHERE inbox.id=?1 AND inbox.org_run_id=?3 AND inbox.read_at IS NULL AND inbox.delivery_class='formal_work' AND NOT EXISTS ( - SELECT 1 FROM agent_org_runtime_inbox_delivery_resolutions resolution + SELECT 1 FROM agent_org_execution_inbox_delivery_resolutions resolution WHERE resolution.inbox_id=inbox.id )", ) @@ -401,7 +401,7 @@ pub(crate) fn guaranteed_current_turn_effects_with_connection( let mut active_turn_stmt = conn .prepare( "SELECT intent.created_at - FROM agent_org_runtime_turn_contexts context + FROM agent_org_execution_turn_contexts context JOIN session_turn_intents intent ON intent.session_id=context.session_id AND intent.turn_intent_id=context.turn_intent_id @@ -457,7 +457,7 @@ pub(super) fn load_and_assess( let run_row: Option<(String, Option, i64)> = conn .query_row( "SELECT status, root_session_id, activation_generation - FROM agent_org_runtime_runs WHERE id=?1", + FROM agent_org_execution_runs WHERE id=?1", params![run_id], |row| Ok((row.get(0)?, row.get(1)?, row.get(2)?)), ) @@ -521,7 +521,7 @@ pub(super) fn load_and_assess( let mut statement = conn .prepare( "SELECT DISTINCT context.session_id - FROM agent_org_runtime_turn_contexts context + FROM agent_org_execution_turn_contexts context JOIN session_turn_intents intent ON intent.session_id=context.session_id AND intent.turn_intent_id=context.turn_intent_id @@ -563,8 +563,8 @@ pub(super) fn load_and_assess( crate::coordination::agent_org_tasks::corrupt_task_row_predicate_sql(); let persisted_open_task_count: i64 = conn .query_row( - "SELECT COUNT(*) FROM agent_org_runtime_tasks task - JOIN agent_org_runtime_work_episode_tasks episode_task + "SELECT COUNT(*) FROM agent_org_execution_tasks task + JOIN agent_org_execution_work_episode_tasks episode_task ON episode_task.org_run_id=task.org_run_id AND episode_task.task_id=task.id WHERE task.org_run_id=?1 AND episode_task.work_episode_id=?2 AND task.status IN ('pending','in_progress')", @@ -602,8 +602,8 @@ pub(super) fn load_and_assess( CASE WHEN metadata_json IS NULL OR length(CAST(metadata_json AS BLOB))<={metadata_max} THEN metadata_json ELSE '!' END AS metadata_json - FROM agent_org_runtime_tasks task - JOIN agent_org_runtime_work_episode_tasks episode_task + FROM agent_org_execution_tasks task + JOIN agent_org_execution_work_episode_tasks episode_task ON episode_task.org_run_id=task.org_run_id AND episode_task.task_id=task.id WHERE task.org_run_id=?1 AND episode_task.work_episode_id=?2 ) AS bounded_tasks" @@ -641,11 +641,11 @@ pub(super) fn load_and_assess( let unread_inbox_count: i64 = conn .query_row( "SELECT COUNT(*) - FROM agent_org_runtime_inbox + FROM agent_org_execution_inbox WHERE org_run_id=?1 AND delivery_class='formal_work' AND read_at IS NULL AND NOT EXISTS ( - SELECT 1 FROM agent_org_runtime_inbox_delivery_resolutions resolution - WHERE resolution.inbox_id=agent_org_runtime_inbox.id + SELECT 1 FROM agent_org_execution_inbox_delivery_resolutions resolution + WHERE resolution.inbox_id=agent_org_execution_inbox.id )", params![run_id], |row| row.get(0), @@ -654,17 +654,17 @@ pub(super) fn load_and_assess( let blocking_unread_inbox_count: i64 = conn .query_row( "SELECT COUNT(*) - FROM agent_org_runtime_inbox inbox + FROM agent_org_execution_inbox inbox WHERE inbox.org_run_id=?1 AND inbox.delivery_class='formal_work' AND inbox.read_at IS NULL AND NOT EXISTS ( - SELECT 1 FROM agent_org_runtime_inbox_delivery_resolutions resolution + SELECT 1 FROM agent_org_execution_inbox_delivery_resolutions resolution WHERE resolution.inbox_id=inbox.id ) AND NOT ( inbox.payload_kind='shutdown_request' AND NOT EXISTS ( - SELECT 1 FROM agent_org_runtime_tasks task + SELECT 1 FROM agent_org_execution_tasks task WHERE task.org_run_id=inbox.org_run_id AND task.owner=inbox.recipient_member_id AND task.status IN ('pending','in_progress') @@ -675,7 +675,7 @@ pub(super) fn load_and_assess( OR inbox.sender_agent_id=?2 OR EXISTS ( SELECT 1 - FROM agent_org_runtime_formal_trigger_receipts receipt + FROM agent_org_execution_formal_trigger_receipts receipt WHERE receipt.inbox_id=inbox.id AND receipt.status IN ('pending','materialized') ) @@ -688,7 +688,7 @@ pub(super) fn load_and_assess( .query_row( "SELECT COUNT(*) FROM session_turn_intents intent - JOIN agent_org_runtime_turn_contexts context + JOIN agent_org_execution_turn_contexts context ON context.session_id=intent.session_id AND context.turn_intent_id=intent.turn_intent_id WHERE intent.org_run_id=?1 @@ -709,7 +709,7 @@ pub(super) fn load_and_assess( .query_row( "SELECT COUNT(*) FROM session_turn_intents intent - JOIN agent_org_runtime_turn_contexts context + JOIN agent_org_execution_turn_contexts context ON context.session_id=intent.session_id AND context.turn_intent_id=intent.turn_intent_id WHERE intent.org_run_id=?1 @@ -726,7 +726,7 @@ pub(super) fn load_and_assess( .map_err(|err| err.to_string())?; let pending_formal_materialization_count: i64 = conn .query_row( - "SELECT COUNT(*) FROM agent_org_runtime_member_materializations + "SELECT COUNT(*) FROM agent_org_execution_member_materializations WHERE org_run_id=?1 AND generation=?2 AND authority_class IN ('starting', 'formal') AND status<>'succeeded'", @@ -736,7 +736,7 @@ pub(super) fn load_and_assess( .map_err(|err| err.to_string())?; let active_recovery_reservation_count: i64 = conn .query_row( - "SELECT COUNT(*) FROM agent_org_runtime_recovery_attempts + "SELECT COUNT(*) FROM agent_org_execution_recovery_attempts WHERE org_run_id=?1 AND reservation_token IS NOT NULL", params![run_id], |row| row.get(0), @@ -745,8 +745,8 @@ pub(super) fn load_and_assess( let pending_plan_approval_count: i64 = conn .query_row( "SELECT COUNT(*) - FROM agent_org_runtime_plan_revisions revision - JOIN agent_org_runtime_plan_decisions decision + FROM agent_org_execution_plan_revisions revision + JOIN agent_org_execution_plan_decisions decision ON decision.plan_revision_id=revision.plan_revision_id WHERE revision.org_run_id=?1 AND decision.status='pending'", params![run_id], @@ -755,8 +755,8 @@ pub(super) fn load_and_assess( .map_err(|err| err.to_string())?; let unresolved_handoff_count: i64 = conn .query_row( - "SELECT COUNT(*) FROM agent_org_runtime_task_execution_handoffs handoff - JOIN agent_org_runtime_work_episode_tasks episode_task + "SELECT COUNT(*) FROM agent_org_execution_task_execution_handoffs handoff + JOIN agent_org_execution_work_episode_tasks episode_task ON episode_task.org_run_id=handoff.org_run_id AND episode_task.task_id=handoff.old_task_id WHERE handoff.org_run_id=?1 AND episode_task.work_episode_id=?2 @@ -1191,26 +1191,26 @@ mod tests { session_id TEXT,turn_intent_id TEXT,org_run_id TEXT, status TEXT,created_at TEXT ); - CREATE TABLE agent_org_runtime_turn_contexts( + CREATE TABLE agent_org_execution_turn_contexts( session_id TEXT,turn_intent_id TEXT,org_run_id TEXT, turn_kind TEXT,participant_id TEXT ); - CREATE TABLE agent_org_runtime_inbox( + CREATE TABLE agent_org_execution_inbox( id INTEGER PRIMARY KEY,org_run_id TEXT,read_at TEXT, payload_kind TEXT,payload_json TEXT,sender_agent_id TEXT,created_at TEXT, delivery_class TEXT NOT NULL DEFAULT 'formal_work' ); - CREATE TABLE agent_org_runtime_inbox_materializations( + CREATE TABLE agent_org_execution_inbox_materializations( inbox_id INTEGER,session_id TEXT ); - CREATE TABLE agent_org_runtime_inbox_delivery_resolutions(inbox_id INTEGER); + CREATE TABLE agent_org_execution_inbox_delivery_resolutions(inbox_id INTEGER); INSERT INTO session_turn_intents VALUES ('root','root-turn','run','running','2026-01-01T00:00:00Z'), ('worker','worker-turn','run','running','2026-01-01T00:00:01Z'); - INSERT INTO agent_org_runtime_turn_contexts VALUES + INSERT INTO agent_org_execution_turn_contexts VALUES ('root','root-turn','run','coordinator','coordinator'), ('worker','worker-turn','run','task_execution','member'); - INSERT INTO agent_org_runtime_inbox_materializations VALUES (7,'root');", + INSERT INTO agent_org_execution_inbox_materializations VALUES (7,'root');", ) .expect("minimal durable facts"); let idle = serde_json::to_string( @@ -1226,7 +1226,7 @@ mod tests { ) .expect("member idle json"); conn.execute( - "INSERT INTO agent_org_runtime_inbox( + "INSERT INTO agent_org_execution_inbox( id,org_run_id,read_at,payload_kind,payload_json,sender_agent_id,created_at ) VALUES (7,'run',NULL,'member_idle',?1,'_system','2026-01-01T00:00:02Z')", [&idle], @@ -1247,7 +1247,7 @@ mod tests { assert_eq!(effects.terminal_worker_turn_intents, 1); conn.execute( - "UPDATE agent_org_runtime_inbox SET created_at='2025-12-31T23:59:59Z' WHERE id=7", + "UPDATE agent_org_execution_inbox SET created_at='2025-12-31T23:59:59Z' WHERE id=7", [], ) .expect("make the idle row stale"); diff --git a/src-tauri/crates/agent-core/src/core/coordination/agent_org_runs/store/completion.rs b/src-tauri/crates/agent-core/src/core/coordination/agent_org_runs/store/completion.rs index 41e0b06370..0246347016 100644 --- a/src-tauri/crates/agent-core/src/core/coordination/agent_org_runs/store/completion.rs +++ b/src-tauri/crates/agent-core/src/core/coordination/agent_org_runs/store/completion.rs @@ -117,7 +117,7 @@ impl AgentOrgRunStore { ) -> Result { let status: Option = conn .query_row( - "SELECT status FROM agent_org_runtime_runs WHERE id=?1", + "SELECT status FROM agent_org_execution_runs WHERE id=?1", params![run_id], |row| row.get(0), ) @@ -132,7 +132,7 @@ impl AgentOrgRunStore { let unresolved_task_ids = { let mut stmt = conn .prepare( - "SELECT id FROM agent_org_runtime_tasks + "SELECT id FROM agent_org_execution_tasks WHERE org_run_id=?1 AND status IN ('pending','in_progress') ORDER BY created_at ASC, id ASC", ) diff --git a/src-tauri/crates/agent-core/src/core/coordination/agent_org_runs/store/delete.rs b/src-tauri/crates/agent-core/src/core/coordination/agent_org_runs/store/delete.rs index ca1798ed2e..a2e1d4b13d 100644 --- a/src-tauri/crates/agent-core/src/core/coordination/agent_org_runs/store/delete.rs +++ b/src-tauri/crates/agent-core/src/core/coordination/agent_org_runs/store/delete.rs @@ -21,7 +21,7 @@ fn delete_user_directed_work_for_run_with_connection( run_id: &str, ) -> Result<(), String> { conn.execute( - "DELETE FROM agent_org_runtime_user_directed_coordinator_bindings + "DELETE FROM agent_org_execution_user_directed_coordinator_bindings WHERE org_run_id=?1", params![run_id], ) @@ -32,7 +32,7 @@ fn delete_user_directed_work_for_run_with_connection( let mut remaining = conn .query_row( "SELECT COUNT(*) - FROM agent_org_runtime_user_directed_deliveries + FROM agent_org_execution_user_directed_deliveries WHERE org_run_id=?1", params![run_id], |row| row.get::<_, usize>(0), @@ -41,14 +41,14 @@ fn delete_user_directed_work_for_run_with_connection( while remaining > 0 { let deleted = conn .execute( - "DELETE FROM agent_org_runtime_user_directed_deliveries + "DELETE FROM agent_org_execution_user_directed_deliveries WHERE delivery_id IN ( SELECT parent.delivery_id - FROM agent_org_runtime_user_directed_deliveries parent + FROM agent_org_execution_user_directed_deliveries parent WHERE parent.org_run_id=?1 AND NOT EXISTS ( SELECT 1 - FROM agent_org_runtime_user_directed_deliveries child + FROM agent_org_execution_user_directed_deliveries child WHERE child.parent_delivery_id=parent.delivery_id ) )", @@ -66,7 +66,7 @@ fn delete_user_directed_work_for_run_with_connection( } conn.execute( - "DELETE FROM agent_org_runtime_user_directed_roots WHERE org_run_id=?1", + "DELETE FROM agent_org_execution_user_directed_roots WHERE org_run_id=?1", params![run_id], ) .map_err(|err| format!("failed to delete user-directed roots for {run_id}: {err}"))?; @@ -97,10 +97,10 @@ impl AgentOrgRunStore { let mut stmt = conn .prepare( "SELECT DISTINCT revision.source_session_id, revision.plan_path - FROM agent_org_runtime_plan_revisions revision + FROM agent_org_execution_plan_revisions revision WHERE revision.org_run_id=?1 AND NOT EXISTS ( - SELECT 1 FROM agent_org_runtime_plan_revisions other + SELECT 1 FROM agent_org_execution_plan_revisions other WHERE other.plan_path=revision.plan_path AND other.org_run_id<>?1 )", @@ -131,41 +131,41 @@ impl AgentOrgRunStore { ) .map_err(|err| err.to_string())?; conn.execute( - "DELETE FROM agent_org_runtime_inbox_materializations + "DELETE FROM agent_org_execution_inbox_materializations WHERE inbox_id IN ( - SELECT id FROM agent_org_runtime_inbox WHERE org_run_id=?1 + SELECT id FROM agent_org_execution_inbox WHERE org_run_id=?1 )", params![run_id], ) .map_err(|err| { - format!("failed to delete agent_org_runtime_inbox_materializations rows for {run_id}: {err}") + format!("failed to delete agent_org_execution_inbox_materializations rows for {run_id}: {err}") })?; conn.execute( - "DELETE FROM agent_org_runtime_plan_decisions + "DELETE FROM agent_org_execution_plan_decisions WHERE plan_revision_id IN ( - SELECT plan_revision_id FROM agent_org_runtime_plan_revisions + SELECT plan_revision_id FROM agent_org_execution_plan_revisions WHERE org_run_id=?1 )", params![run_id], ) .map_err(|err| { - format!("failed to delete agent_org_runtime_plan_decisions rows for {run_id}: {err}") + format!("failed to delete agent_org_execution_plan_decisions rows for {run_id}: {err}") })?; for table in [ - "agent_org_runtime_plan_revisions", - "agent_org_runtime_recovery_attempts", + "agent_org_execution_plan_revisions", + "agent_org_execution_recovery_attempts", // Handoffs retain exact old/replacement Task identities. Delete // the run-owned receipts before their Task rows so permanent Team // deletion preserves foreign-key enforcement instead of relying // on disabled or deferred constraints. - "agent_org_runtime_task_execution_handoffs", - "agent_org_runtime_task_annotations", - "agent_org_runtime_task_events", - "agent_org_runtime_tasks", - "agent_org_runtime_inbox_delivery_resolutions", - "agent_org_runtime_inbox", - "agent_org_runtime_member_interventions", - "agent_org_runtime_run_progress", + "agent_org_execution_task_execution_handoffs", + "agent_org_execution_task_annotations", + "agent_org_execution_task_events", + "agent_org_execution_tasks", + "agent_org_execution_inbox_delivery_resolutions", + "agent_org_execution_inbox", + "agent_org_execution_member_interventions", + "agent_org_execution_run_progress", ] { conn.execute( &format!("DELETE FROM {table} WHERE org_run_id=?1"), @@ -175,7 +175,7 @@ impl AgentOrgRunStore { } let deleted = conn .execute( - "DELETE FROM agent_org_runtime_runs WHERE id=?1", + "DELETE FROM agent_org_execution_runs WHERE id=?1", params![run_id], ) .map_err(|err| err.to_string())? diff --git a/src-tauri/crates/agent-core/src/core/coordination/agent_org_runs/store/lifecycle.rs b/src-tauri/crates/agent-core/src/core/coordination/agent_org_runs/store/lifecycle.rs index 615943e6cd..73fc428180 100644 --- a/src-tauri/crates/agent-core/src/core/coordination/agent_org_runs/store/lifecycle.rs +++ b/src-tauri/crates/agent-core/src/core/coordination/agent_org_runs/store/lifecycle.rs @@ -192,7 +192,7 @@ impl AgentOrgRunStore { let run: Option<(String, i64, Option)> = conn .query_row( "SELECT status,activation_generation,org_snapshot_json - FROM agent_org_runtime_runs WHERE id=?1", + FROM agent_org_execution_runs WHERE id=?1", [run_id], |row| Ok((row.get(0)?, row.get(1)?, row.get(2)?)), ) @@ -295,7 +295,7 @@ impl AgentOrgRunStore { let now = chrono::Utc::now().to_rfc3339(); let changed = conn .execute( - "UPDATE agent_org_runtime_runs + "UPDATE agent_org_execution_runs SET status='running',activation_generation=?2,updated_at=?3, idled_at=NULL,last_activity_outcome=NULL WHERE id=?1 AND status=?5 AND activation_generation=?4", @@ -316,7 +316,7 @@ impl AgentOrgRunStore { for turn in turns { let marked = conn .execute( - "UPDATE agent_org_runtime_turn_contexts + "UPDATE agent_org_execution_turn_contexts SET activation_generation=?4 WHERE session_id=?1 AND turn_intent_id=?2 AND org_run_id=?3 AND participant_id='coordinator' AND turn_kind='coordinator' diff --git a/src-tauri/crates/agent-core/src/core/coordination/agent_org_runs/store/next_work.rs b/src-tauri/crates/agent-core/src/core/coordination/agent_org_runs/store/next_work.rs index bad0dfebba..4cb19d08d9 100644 --- a/src-tauri/crates/agent-core/src/core/coordination/agent_org_runs/store/next_work.rs +++ b/src-tauri/crates/agent-core/src/core/coordination/agent_org_runs/store/next_work.rs @@ -13,9 +13,9 @@ pub(super) fn accepted_user_turns( ) -> Result, String> { let mut statement = conn .prepare( - "SELECT context.turn_intent_id FROM agent_org_runtime_turn_contexts context + "SELECT context.turn_intent_id FROM agent_org_execution_turn_contexts context JOIN session_turn_intents intent USING(session_id,turn_intent_id) - JOIN agent_org_runtime_runs run ON run.id=context.org_run_id + JOIN agent_org_execution_runs run ON run.id=context.org_run_id WHERE run.id=?1 AND run.root_session_id=?2 AND context.session_id=?2 AND context.activation_generation=?4 AND intent.org_run_id=?1 AND context.participant_id='coordinator' AND context.turn_kind='coordinator' diff --git a/src-tauri/crates/agent-core/src/core/coordination/agent_org_runs/store/queries.rs b/src-tauri/crates/agent-core/src/core/coordination/agent_org_runs/store/queries.rs index 9053714794..2b355aea51 100644 --- a/src-tauri/crates/agent-core/src/core/coordination/agent_org_runs/store/queries.rs +++ b/src-tauri/crates/agent-core/src/core/coordination/agent_org_runs/store/queries.rs @@ -44,7 +44,7 @@ impl AgentOrgRunStore { idled_at, archived_at, archive_receipt_id - FROM agent_org_runtime_runs + FROM agent_org_execution_runs WHERE root_session_id IN ({placeholders}) ORDER BY updated_at DESC, id DESC" ); @@ -92,7 +92,7 @@ impl AgentOrgRunStore { idled_at, archived_at, archive_receipt_id - FROM agent_org_runtime_runs + FROM agent_org_execution_runs WHERE root_session_id IS NOT NULL ORDER BY updated_at DESC LIMIT ?1", @@ -150,7 +150,7 @@ impl AgentOrgRunStore { idled_at, archived_at, archive_receipt_id - FROM agent_org_runtime_runs + FROM agent_org_execution_runs WHERE root_session_id IS NOT NULL AND status='running' AND (?1 IS NULL OR id>?1) @@ -197,7 +197,7 @@ impl AgentOrgRunStore { idled_at, archived_at, archive_receipt_id - FROM agent_org_runtime_runs + FROM agent_org_execution_runs WHERE root_session_id IS NOT NULL AND status = ?1 ORDER BY updated_at ASC, id ASC @@ -226,7 +226,7 @@ impl AgentOrgRunStore { ) -> Result, String> { let status_raw: Option = conn .query_row( - "SELECT status FROM agent_org_runtime_runs WHERE id = ?1 LIMIT 1", + "SELECT status FROM agent_org_execution_runs WHERE id = ?1 LIMIT 1", params![run_id], |row| row.get(0), ) diff --git a/src-tauri/crates/agent-core/src/core/coordination/agent_org_runs/store/quiescence.rs b/src-tauri/crates/agent-core/src/core/coordination/agent_org_runs/store/quiescence.rs index 1ad840d003..638a51e821 100644 --- a/src-tauri/crates/agent-core/src/core/coordination/agent_org_runs/store/quiescence.rs +++ b/src-tauri/crates/agent-core/src/core/coordination/agent_org_runs/store/quiescence.rs @@ -58,7 +58,7 @@ impl AgentOrgRunStore { .map(|certificate| certificate.outcome.last_activity_outcome()); let changed = tx .execute( - "UPDATE agent_org_runtime_runs + "UPDATE agent_org_execution_runs SET status='idle', summary=COALESCE(?1, summary), last_activity_outcome=?2, @@ -67,8 +67,8 @@ impl AgentOrgRunStore { WHERE id=?4 AND status='running' AND activation_generation=?5 AND EXISTS ( - SELECT 1 FROM agent_org_runtime_run_progress progress - WHERE progress.org_run_id=agent_org_runtime_runs.id + SELECT 1 FROM agent_org_execution_run_progress progress + WHERE progress.org_run_id=agent_org_execution_runs.id AND progress.work_revision=?6 )", params![ diff --git a/src-tauri/crates/agent-core/src/core/coordination/agent_org_runs/store/session_lookup.rs b/src-tauri/crates/agent-core/src/core/coordination/agent_org_runs/store/session_lookup.rs index 01cacef1c0..81b15ff29d 100644 --- a/src-tauri/crates/agent-core/src/core/coordination/agent_org_runs/store/session_lookup.rs +++ b/src-tauri/crates/agent-core/src/core/coordination/agent_org_runs/store/session_lookup.rs @@ -56,7 +56,7 @@ impl AgentOrgRunStore { let conn = get_connection().map_err(|err| err.to_string())?; let root_session_id: Option = conn .query_row( - "SELECT root_session_id FROM agent_org_runtime_runs WHERE id = ?1", + "SELECT root_session_id FROM agent_org_execution_runs WHERE id = ?1", params![org_run_id], |row| row.get::<_, Option>(0), ) @@ -78,7 +78,7 @@ impl AgentOrgRunStore { tracing::warn!( session_id = %session_id, cycle_at = %current_id, - "[agent_org_runtime_runs] parent_session_id chain has a cycle; aborting walk" + "[agent_org_execution_runs] parent_session_id chain has a cycle; aborting walk" ); return Ok(None); } @@ -89,7 +89,7 @@ impl AgentOrgRunStore { tracing::warn!( session_id = %session_id, last_visited = %current_id, - "[agent_org_runtime_runs] parent_session_id walk exceeded max depth ({}); giving up", + "[agent_org_execution_runs] parent_session_id walk exceeded max depth ({}); giving up", MAX_PARENT_WALK_DEPTH ); return Ok(None); diff --git a/src-tauri/crates/agent-core/src/core/coordination/agent_org_runs/store/starting.rs b/src-tauri/crates/agent-core/src/core/coordination/agent_org_runs/store/starting.rs index cee4f31f1a..093328f4d7 100644 --- a/src-tauri/crates/agent-core/src/core/coordination/agent_org_runs/store/starting.rs +++ b/src-tauri/crates/agent-core/src/core/coordination/agent_org_runs/store/starting.rs @@ -213,8 +213,8 @@ impl AgentOrgRunStore { .query_row( "SELECT materialization.agent_id, materialization.session_id, run.root_session_id, materialization.status - FROM agent_org_runtime_member_materializations materialization - JOIN agent_org_runtime_runs run ON run.id=materialization.org_run_id + FROM agent_org_execution_member_materializations materialization + JOIN agent_org_execution_runs run ON run.id=materialization.org_run_id WHERE materialization.org_run_id=?1 AND materialization.member_id=?2 AND materialization.generation=?3 @@ -266,7 +266,7 @@ impl AgentOrgRunStore { } let changed = transaction .execute( - "UPDATE agent_org_runtime_member_materializations + "UPDATE agent_org_execution_member_materializations SET status='succeeded', error_code=NULL, error_json=NULL, updated_at=?5 WHERE org_run_id=?1 AND member_id=?2 AND generation=?3 @@ -299,7 +299,7 @@ impl AgentOrgRunStore { let run: Option<(String, String, i64, bool)> = transaction .query_row( "SELECT status, root_session_id, activation_generation, has_initial_work - FROM agent_org_runtime_runs WHERE id=?1", + FROM agent_org_execution_runs WHERE id=?1", [run_id], |row| { Ok(( @@ -329,7 +329,7 @@ impl AgentOrgRunStore { let invalid_materialized_identities: i64 = transaction .query_row( "SELECT COUNT(*) - FROM agent_org_runtime_member_materializations materialization + FROM agent_org_execution_member_materializations materialization LEFT JOIN agent_sessions session ON session.session_id=materialization.session_id WHERE materialization.org_run_id=?1 @@ -373,7 +373,7 @@ impl AgentOrgRunStore { } let incomplete_materializations: i64 = transaction .query_row( - "SELECT COUNT(*) FROM agent_org_runtime_member_materializations + "SELECT COUNT(*) FROM agent_org_execution_member_materializations WHERE org_run_id=?1 AND generation=?2 AND status<>'succeeded'", params![run_id, expected_generation], |row| row.get(0), @@ -423,7 +423,7 @@ impl AgentOrgRunStore { )?; transaction .execute( - "UPDATE agent_org_runtime_initial_inputs + "UPDATE agent_org_execution_initial_inputs SET status='queued', updated_at=?2 WHERE org_run_id=?1 AND status='pending_persistence'", params![run_id, chrono::Utc::now().to_rfc3339()], @@ -443,7 +443,7 @@ impl AgentOrgRunStore { let now = chrono::Utc::now().to_rfc3339(); let changed = transaction .execute( - "UPDATE agent_org_runtime_runs + "UPDATE agent_org_execution_runs SET status=?1, updated_at=?2, idled_at=CASE WHEN ?1='idle' THEN ?2 ELSE NULL END WHERE id=?3 AND status='starting' @@ -469,7 +469,7 @@ impl AgentOrgRunStore { let connection = get_connection().map_err(|error| error.to_string())?; let changed = connection .execute( - "UPDATE agent_org_runtime_initial_inputs + "UPDATE agent_org_execution_initial_inputs SET status='dispatched', updated_at=?3 WHERE org_run_id=?1 AND turn_intent_id=?2 AND status IN ('queued', 'dispatched')", @@ -499,7 +499,7 @@ impl AgentOrgRunStore { .map_err(|err| err.to_string())?; let changed = tx .execute( - "UPDATE agent_org_runtime_runs + "UPDATE agent_org_execution_runs SET status = 'failed', last_error = ?2, failure_json = ?3, diff --git a/src-tauri/crates/agent-core/src/core/coordination/agent_org_runs/store/worker_sessions.rs b/src-tauri/crates/agent-core/src/core/coordination/agent_org_runs/store/worker_sessions.rs index 637d6a4f10..f969a9c217 100644 --- a/src-tauri/crates/agent-core/src/core/coordination/agent_org_runs/store/worker_sessions.rs +++ b/src-tauri/crates/agent-core/src/core/coordination/agent_org_runs/store/worker_sessions.rs @@ -47,7 +47,7 @@ impl AgentOrgRunStore { "SELECT s.session_id, s.status, s.updated_at - FROM agent_org_runtime_runs r + FROM agent_org_execution_runs r JOIN agent_sessions s ON s.session_id = r.root_session_id WHERE r.id = ?1 LIMIT 1", @@ -121,7 +121,7 @@ impl AgentOrgRunStore { ) -> Result>, String> { let snapshot_json: Option = conn .query_row( - "SELECT org_snapshot_json FROM agent_org_runtime_runs WHERE id=?1", + "SELECT org_snapshot_json FROM agent_org_execution_runs WHERE id=?1", params![org_run_id], |row| row.get(0), ) @@ -159,7 +159,7 @@ impl AgentOrgRunStore { ) -> Result, String> { let root_session_id: Option = conn .query_row( - "SELECT root_session_id FROM agent_org_runtime_runs WHERE id = ?1", + "SELECT root_session_id FROM agent_org_execution_runs WHERE id = ?1", params![org_run_id], |row| row.get::<_, Option>(0), ) @@ -182,7 +182,7 @@ impl AgentOrgRunStore { FROM agent_sessions child WHERE child.parent_session_id = ?1 AND NOT EXISTS ( - SELECT 1 FROM agent_org_runtime_runs nested + SELECT 1 FROM agent_org_execution_runs nested WHERE nested.id <> ?2 AND nested.root_session_id = child.session_id ) @@ -191,7 +191,7 @@ impl AgentOrgRunStore { FROM agent_sessions s JOIN descendants d ON s.parent_session_id = d.session_id WHERE NOT EXISTS ( - SELECT 1 FROM agent_org_runtime_runs nested + SELECT 1 FROM agent_org_execution_runs nested WHERE nested.id <> ?2 AND nested.root_session_id = s.session_id ) diff --git a/src-tauri/crates/agent-core/src/core/coordination/agent_org_runs/tests.rs b/src-tauri/crates/agent-core/src/core/coordination/agent_org_runs/tests.rs index bcc2fd5aea..685c107ff9 100644 --- a/src-tauri/crates/agent-core/src/core/coordination/agent_org_runs/tests.rs +++ b/src-tauri/crates/agent-core/src/core/coordination/agent_org_runs/tests.rs @@ -48,7 +48,7 @@ fn canonical_schema_snapshot_contains_only_the_long_lived_run_states() { let run_ddl: String = conn .query_row( "SELECT sql FROM sqlite_master - WHERE type='table' AND name='agent_org_runtime_runs'", + WHERE type='table' AND name='agent_org_execution_runs'", [], |row| row.get(0), ) @@ -73,7 +73,7 @@ fn canonical_schema_snapshot_contains_only_the_long_lived_run_states() { let materialization_ddl: String = conn .query_row( "SELECT sql FROM sqlite_master - WHERE type='table' AND name='agent_org_runtime_member_materializations'", + WHERE type='table' AND name='agent_org_execution_member_materializations'", [], |row| row.get(0), ) @@ -84,7 +84,7 @@ fn canonical_schema_snapshot_contains_only_the_long_lived_run_states() { let initial_input_ddl: String = conn .query_row( "SELECT sql FROM sqlite_master - WHERE type='table' AND name='agent_org_runtime_initial_inputs'", + WHERE type='table' AND name='agent_org_execution_initial_inputs'", [], |row| row.get(0), ) @@ -241,14 +241,14 @@ fn seed_delivered_certificate_for_quiescence(run_id: &str) { let (root_session_id, generation): (String, i64) = conn .query_row( "SELECT root_session_id,activation_generation - FROM agent_org_runtime_runs WHERE id=?1", + FROM agent_org_execution_runs WHERE id=?1", [run_id], |row| Ok((row.get(0)?, row.get(1)?)), ) .expect("current run identity"); let work_revision: i64 = conn .query_row( - "SELECT work_revision FROM agent_org_runtime_run_progress WHERE org_run_id=?1", + "SELECT work_revision FROM agent_org_execution_run_progress WHERE org_run_id=?1", [run_id], |row| row.get(0), ) @@ -267,7 +267,7 @@ fn seed_delivered_certificate_for_quiescence(run_id: &str) { let certificate_id = format!("quiescence-certificate-{run_id}"); let request_id = format!("quiescence-request-{run_id}"); conn.execute( - "INSERT INTO agent_org_runtime_run_completion_certificates ( + "INSERT INTO agent_org_execution_run_completion_certificates ( id,org_run_id,activation_generation,work_revision,request_id,request_digest, outcome,summary,coordinator_session_id,coordinator_turn_intent_id, evidence_task_ids_json,closure_task_ids_json,task_output_refs_json, @@ -302,7 +302,7 @@ fn seed_delivered_certificate_for_quiescence(run_id: &str) { ) .expect("close fixture work episode"); conn.execute( - "INSERT INTO agent_org_runtime_final_summary_receipts ( + "INSERT INTO agent_org_execution_final_summary_receipts ( receipt_id,org_run_id,activation_generation,certificate_id,evidence_digest, attempt,status,coordinator_session_id,turn_intent_id,started_at,terminal_at, event_id,created_at,updated_at @@ -468,7 +468,7 @@ fn starting_finish_requires_exact_member_and_input_durability_then_is_idempotent let context: (i64, String, String, Option) = conn .query_row( "SELECT COUNT(*), turn_kind, source_kind, member_dispatch_sequence - FROM agent_org_runtime_turn_contexts + FROM agent_org_execution_turn_contexts WHERE session_id='starting-root' AND turn_intent_id='starting-turn'", [], |row| Ok((row.get(0)?, row.get(1)?, row.get(2)?, row.get(3)?)), @@ -503,7 +503,7 @@ fn starting_without_initial_work_finishes_idle() { let conn = database::db::get_connection().expect("db"); let context_count: i64 = conn .query_row( - "SELECT COUNT(*) FROM agent_org_runtime_turn_contexts WHERE org_run_id=?1", + "SELECT COUNT(*) FROM agent_org_execution_turn_contexts WHERE org_run_id=?1", [&run.id], |row| row.get(0), ) @@ -612,7 +612,7 @@ fn delete_by_id_cascades_all_run_owned_state_and_plan_artifact() { .expect("attach managed workspace to source session"); let now = chrono::Utc::now().to_rfc3339(); conn.execute( - "INSERT INTO agent_org_runtime_plan_revisions ( + "INSERT INTO agent_org_execution_plan_revisions ( plan_revision_id,org_run_id,source_task_id,source_member_id, source_session_id,source_turn_intent_id,root_session_id, revision_number,plan_title,plan_path,plan_content,content_digest,created_at @@ -628,7 +628,7 @@ fn delete_by_id_cascades_all_run_owned_state_and_plan_artifact() { ) .unwrap(); conn.execute( - "INSERT INTO agent_org_runtime_plan_decisions ( + "INSERT INTO agent_org_execution_plan_decisions ( approval_id,plan_revision_id,request_id,policy,status,created_at ) VALUES ('delete-approval','delete-revision','delete-request', 'coordinator','pending',?1)", @@ -636,7 +636,7 @@ fn delete_by_id_cascades_all_run_owned_state_and_plan_artifact() { ) .unwrap(); conn.execute( - "INSERT INTO agent_org_runtime_plan_revisions ( + "INSERT INTO agent_org_execution_plan_revisions ( plan_revision_id,org_run_id,source_task_id,source_member_id, source_session_id,source_turn_intent_id,root_session_id, revision_number,previous_plan_revision_id,plan_title,plan_path, @@ -653,7 +653,7 @@ fn delete_by_id_cascades_all_run_owned_state_and_plan_artifact() { ) .unwrap(); conn.execute( - "INSERT INTO agent_org_runtime_plan_decisions ( + "INSERT INTO agent_org_execution_plan_decisions ( approval_id,plan_revision_id,request_id,policy,status,decision_by, created_at,resolved_at ) VALUES ('external-approval','external-revision','external-request', @@ -662,7 +662,7 @@ fn delete_by_id_cascades_all_run_owned_state_and_plan_artifact() { ) .unwrap(); conn.execute( - "INSERT INTO agent_org_runtime_recovery_attempts + "INSERT INTO agent_org_execution_recovery_attempts (org_run_id, action_kind, target_key, reason_fingerprint, attempts, next_allowed_at, updated_at) VALUES (?1,'member_rewake','member-w1','delete',1,?2,?2)", @@ -670,7 +670,7 @@ fn delete_by_id_cascades_all_run_owned_state_and_plan_artifact() { ) .unwrap(); conn.execute( - "INSERT INTO agent_org_runtime_task_annotations + "INSERT INTO agent_org_execution_task_annotations (id, org_run_id, task_id, kind, body, actor_kind, actor_participant_id, created_at) VALUES ('delete-note', ?1, 'delete-task', 'audit_note', 'delete', @@ -689,14 +689,14 @@ fn delete_by_id_cascades_all_run_owned_state_and_plan_artifact() { AgentOrgRunStore::delete_by_id(&run.id).expect("delete run-owned state"); for table in [ - "agent_org_runtime_run_progress", - "agent_org_runtime_tasks", - "agent_org_runtime_task_events", - "agent_org_runtime_task_annotations", - "agent_org_runtime_inbox", - "agent_org_runtime_member_interventions", - "agent_org_runtime_plan_revisions", - "agent_org_runtime_recovery_attempts", + "agent_org_execution_run_progress", + "agent_org_execution_tasks", + "agent_org_execution_task_events", + "agent_org_execution_task_annotations", + "agent_org_execution_inbox", + "agent_org_execution_member_interventions", + "agent_org_execution_plan_revisions", + "agent_org_execution_recovery_attempts", ] { let count: i64 = conn .query_row( @@ -709,7 +709,7 @@ fn delete_by_id_cascades_all_run_owned_state_and_plan_artifact() { } let decision_count: i64 = conn .query_row( - "SELECT COUNT(*) FROM agent_org_runtime_plan_decisions + "SELECT COUNT(*) FROM agent_org_execution_plan_decisions WHERE approval_id IN ('delete-approval','external-approval')", [], |row| row.get(0), @@ -944,7 +944,7 @@ fn idle_run_stages_a_coordinator_read_snapshot() { let run = create_run_for_root(&org, "coord-root-idle-read-snapshot"); let conn = database::db::get_connection().expect("test sqlite connection"); conn.execute( - "UPDATE agent_org_runtime_runs SET status='idle' WHERE id=?1", + "UPDATE agent_org_execution_runs SET status='idle' WHERE id=?1", [&run.id], ) .expect("move run to Idle"); @@ -1440,7 +1440,7 @@ fn delivered_candidate_uses_stable_episode_across_pause_resume_generation() { let conn = database::db::get_connection().expect("test sqlite connection"); let now = chrono::Utc::now().to_rfc3339(); conn.execute( - "INSERT INTO agent_org_runtime_member_materializations ( + "INSERT INTO agent_org_execution_member_materializations ( org_run_id,member_id,agent_id,generation,session_id, authority_class,status,error_code,error_json,created_at,updated_at ) VALUES (?1,?2,'agent-coord',1,?3,'formal','succeeded',NULL,NULL,?4,?4)", @@ -1461,7 +1461,7 @@ fn delivered_candidate_uses_stable_episode_across_pause_resume_generation() { }) .expect("create output-backed completed Task"); conn.execute( - "UPDATE agent_org_runtime_runs SET activation_generation=3 WHERE id=?1", + "UPDATE agent_org_execution_runs SET activation_generation=3 WHERE id=?1", [&run.id], ) .expect("simulate Pause/Resume authorization generations"); @@ -1534,7 +1534,7 @@ fn delivered_candidate_uses_stable_episode_across_pause_resume_generation() { let idled_at = chrono::Utc::now().to_rfc3339(); conn.execute( - "UPDATE agent_org_runtime_runs + "UPDATE agent_org_execution_runs SET status='idle',idled_at=?2,last_activity_outcome='completed' WHERE id=?1", params![&run.id, &idled_at], @@ -1610,7 +1610,7 @@ fn quiescence_transitions_run_to_idle_when_all_tasks_completed() { ) .expect("seed pending turn intent"); conn.execute( - "INSERT INTO agent_org_runtime_turn_contexts ( + "INSERT INTO agent_org_execution_turn_contexts ( session_id,turn_intent_id,org_run_id,participant_id,turn_kind, source_kind,source_id,activation_generation,created_at ) VALUES (?1,'final-turn',?2,'coordinator','coordinator', @@ -1661,7 +1661,7 @@ fn quiescence_transitions_run_to_idle_when_all_tasks_completed() { "a {terminal_status} turn intent must not keep the run open" ); conn.execute( - "UPDATE agent_org_runtime_runs SET status='running', idled_at=NULL WHERE id=?1", + "UPDATE agent_org_execution_runs SET status='running', idled_at=NULL WHERE id=?1", params![&run.id], ) .expect("reset run for next terminal status"); @@ -1796,7 +1796,7 @@ fn resolved_undeliverable_inbox_stays_unread_but_no_longer_blocks_quiescence() { }; let conn = database::db::get_connection().expect("test sqlite connection"); conn.execute( - "INSERT INTO agent_org_runtime_inbox ( + "INSERT INTO agent_org_execution_inbox ( recipient_agent_id, recipient_member_id, sender_agent_id, sender_member_id, org_run_id, payload_kind, payload_json, created_at diff --git a/src-tauri/crates/agent-core/src/core/coordination/agent_org_task_execution_fence.rs b/src-tauri/crates/agent-core/src/core/coordination/agent_org_task_execution_fence.rs index 96f1ae41bc..04005abf16 100644 --- a/src-tauri/crates/agent-core/src/core/coordination/agent_org_task_execution_fence.rs +++ b/src-tauri/crates/agent-core/src/core/coordination/agent_org_task_execution_fence.rs @@ -186,7 +186,7 @@ pub(crate) fn begin_external_effect( .ok_or_else(|| "task_execution_external_effect_authority_stale".to_string())?; let changed = tx .execute( - "UPDATE agent_org_runtime_tasks SET external_effect_unknown=1 + "UPDATE agent_org_execution_tasks SET external_effect_unknown=1 WHERE org_run_id=?1 AND id=?2 AND status='in_progress' AND owner=?3 AND activation_generation=?4", params![ @@ -219,7 +219,7 @@ pub(crate) fn restore_external_effect_after_success( .ok_or_else(|| "task_execution_external_effect_authority_stale".to_string())?; let changed = tx .execute( - "UPDATE agent_org_runtime_tasks SET external_effect_unknown=?5 + "UPDATE agent_org_execution_tasks SET external_effect_unknown=?5 WHERE org_run_id=?1 AND id=?2 AND status='in_progress' AND owner=?3 AND activation_generation=?4", params![ @@ -245,13 +245,13 @@ fn external_effect_state_for_exact_execution( ) -> Result, String> { conn.query_row( "SELECT task.external_effect_unknown - FROM agent_org_runtime_tasks task - JOIN agent_org_runtime_runs run ON run.id=task.org_run_id + FROM agent_org_execution_tasks task + JOIN agent_org_execution_runs run ON run.id=task.org_run_id WHERE task.org_run_id=?1 AND task.id=?2 AND task.status='in_progress' AND task.owner=?3 AND task.activation_generation=?4 AND run.status='running' AND run.activation_generation=?4 AND EXISTS ( - SELECT 1 FROM agent_org_runtime_turn_contexts context + SELECT 1 FROM agent_org_execution_turn_contexts context JOIN session_turn_intents intent ON intent.session_id=context.session_id AND intent.turn_intent_id=context.turn_intent_id @@ -282,7 +282,7 @@ pub(crate) fn external_effect_unknown_with_connection( task_id: &str, ) -> Result { conn.query_row( - "SELECT external_effect_unknown FROM agent_org_runtime_tasks + "SELECT external_effect_unknown FROM agent_org_execution_tasks WHERE org_run_id=?1 AND id=?2", params![org_run_id, task_id], |row| Ok(row.get::<_, i64>(0)? != 0), @@ -299,7 +299,7 @@ pub(crate) fn clear_external_effect_unknown_in_tx( ) -> Result<(), String> { let changed = conn .execute( - "UPDATE agent_org_runtime_tasks SET external_effect_unknown=0 + "UPDATE agent_org_execution_tasks SET external_effect_unknown=0 WHERE org_run_id=?1 AND id=?2", params![org_run_id, task_id], ) diff --git a/src-tauri/crates/agent-core/src/core/coordination/agent_org_task_handoffs.rs b/src-tauri/crates/agent-core/src/core/coordination/agent_org_task_handoffs.rs index dc3938068a..9b07bcc0b5 100644 --- a/src-tauri/crates/agent-core/src/core/coordination/agent_org_task_handoffs.rs +++ b/src-tauri/crates/agent-core/src/core/coordination/agent_org_task_handoffs.rs @@ -136,7 +136,7 @@ pub struct HandoffResolutionAcceptance { pub(crate) fn create_schema(conn: &Connection) -> rusqlite::Result<()> { conn.execute_batch( - "CREATE TABLE IF NOT EXISTS agent_org_runtime_task_execution_handoffs ( + "CREATE TABLE IF NOT EXISTS agent_org_execution_task_execution_handoffs ( id TEXT PRIMARY KEY, org_run_id TEXT NOT NULL, activation_generation INTEGER NOT NULL CHECK(activation_generation >= 1), @@ -167,9 +167,9 @@ pub(crate) fn create_schema(conn: &Connection) -> rusqlite::Result<()> { UNIQUE(org_run_id, activation_generation, resolution_request_id), UNIQUE(org_run_id, activation_generation, old_task_id, old_turn_intent_id), FOREIGN KEY (org_run_id, old_task_id) - REFERENCES agent_org_runtime_tasks(org_run_id, id), + REFERENCES agent_org_execution_tasks(org_run_id, id), FOREIGN KEY (org_run_id, replacement_task_id) - REFERENCES agent_org_runtime_tasks(org_run_id, id), + REFERENCES agent_org_execution_tasks(org_run_id, id), CHECK((old_session_id IS NULL) = (old_turn_intent_id IS NULL)), CHECK((runtime_lease_id IS NULL) = (dialog_turn_generation IS NULL)), CHECK(runtime_lease_id IS NULL OR old_session_id IS NOT NULL), @@ -187,10 +187,10 @@ pub(crate) fn create_schema(conn: &Connection) -> rusqlite::Result<()> { resolved_at IS NOT NULL AND resolution=requested_resolution )) ); - CREATE INDEX IF NOT EXISTS idx_agent_org_runtime_task_execution_handoffs_run - ON agent_org_runtime_task_execution_handoffs(org_run_id, activation_generation, state, requested_at, id); - CREATE UNIQUE INDEX IF NOT EXISTS idx_agent_org_runtime_task_execution_handoffs_replacement - ON agent_org_runtime_task_execution_handoffs(org_run_id, replacement_task_id) + CREATE INDEX IF NOT EXISTS idx_agent_org_execution_task_execution_handoffs_run + ON agent_org_execution_task_execution_handoffs(org_run_id, activation_generation, state, requested_at, id); + CREATE UNIQUE INDEX IF NOT EXISTS idx_agent_org_execution_task_execution_handoffs_replacement + ON agent_org_execution_task_execution_handoffs(org_run_id, replacement_task_id) WHERE replacement_task_id IS NOT NULL;", ) } @@ -211,7 +211,7 @@ pub fn running_target( .prepare( "SELECT context.session_id,context.turn_intent_id, context.owner_member_id,context.activation_generation - FROM agent_org_runtime_turn_contexts context + FROM agent_org_execution_turn_contexts context JOIN session_turn_intents base ON base.session_id=context.session_id AND base.turn_intent_id=context.turn_intent_id @@ -254,7 +254,7 @@ pub fn terminal_task_is_quiesced_with_connection( let task_state = conn .query_row( "SELECT status,external_effect_unknown - FROM agent_org_runtime_tasks + FROM agent_org_execution_tasks WHERE org_run_id=?1 AND id=?2", params![org_run_id, task_id], |row| Ok((row.get::<_, String>(0)?, row.get::<_, i64>(1)? != 0)), @@ -295,7 +295,7 @@ pub fn create_in_tx( .ok_or_else(|| "task_execution_handoff_requires_old_owner".to_string())?; let generation: i64 = conn .query_row( - "SELECT activation_generation FROM agent_org_runtime_runs + "SELECT activation_generation FROM agent_org_execution_runs WHERE id=?1 AND status='running'", [&request.old_task.org_run_id], |row| row.get(0), @@ -346,7 +346,7 @@ pub fn create_in_tx( TaskExecutionHandoffState::Unknown }; conn.execute( - "INSERT INTO agent_org_runtime_task_execution_handoffs ( + "INSERT INTO agent_org_execution_task_execution_handoffs ( id,org_run_id,activation_generation,request_id,request_digest, old_task_id,old_owner_member_id,old_session_id,old_turn_intent_id, runtime_lease_id,dialog_turn_generation,replacement_task_id,state, @@ -400,8 +400,8 @@ pub fn load_current_by_request( conn.query_row( &format!( "SELECT {handoff_columns} - FROM agent_org_runtime_task_execution_handoffs handoff - JOIN agent_org_runtime_runs run ON run.id=handoff.org_run_id + FROM agent_org_execution_task_execution_handoffs handoff + JOIN agent_org_execution_runs run ON run.id=handoff.org_run_id WHERE handoff.org_run_id=?1 AND handoff.request_id=?2 AND handoff.activation_generation=run.activation_generation" ), @@ -421,7 +421,7 @@ pub fn load_current_for_task_with_connection( conn.query_row( &format!( "SELECT {HANDOFF_COLUMNS} - FROM agent_org_runtime_task_execution_handoffs + FROM agent_org_execution_task_execution_handoffs WHERE org_run_id=?1 AND activation_generation=?2 AND old_task_id=?3 ORDER BY requested_at DESC,id DESC LIMIT 1" ), @@ -440,7 +440,7 @@ pub fn list_current_with_connection( let mut statement = conn .prepare(&format!( "SELECT {HANDOFF_COLUMNS} - FROM agent_org_runtime_task_execution_handoffs + FROM agent_org_execution_task_execution_handoffs WHERE org_run_id=?1 AND activation_generation=?2 ORDER BY requested_at ASC,id ASC" )) @@ -465,8 +465,8 @@ pub(crate) fn blocked_replacement_task_ids_with_connection( let mut statement = conn .prepare( "SELECT handoff.replacement_task_id - FROM agent_org_runtime_task_execution_handoffs handoff - JOIN agent_org_runtime_runs run ON run.id=handoff.org_run_id + FROM agent_org_execution_task_execution_handoffs handoff + JOIN agent_org_execution_runs run ON run.id=handoff.org_run_id WHERE handoff.org_run_id=?1 AND handoff.activation_generation=run.activation_generation AND handoff.replacement_task_id IS NOT NULL @@ -499,7 +499,7 @@ pub(crate) fn reconcile_after_restart(conn: &Connection) -> Result Result Result Result Connection { let conn = Connection::open_in_memory().unwrap(); conn.execute_batch( - "CREATE TABLE agent_org_runtime_runs( + "CREATE TABLE agent_org_execution_runs( id TEXT PRIMARY KEY,status TEXT,activation_generation INTEGER ); - CREATE TABLE agent_org_runtime_tasks( + CREATE TABLE agent_org_execution_tasks( org_run_id TEXT,id TEXT,status TEXT NOT NULL DEFAULT 'in_progress', external_effect_unknown INTEGER NOT NULL DEFAULT 0, PRIMARY KEY(org_run_id,id) @@ -1103,15 +1103,15 @@ mod tests { session_id TEXT,turn_intent_id TEXT,org_run_id TEXT,status TEXT, PRIMARY KEY(session_id,turn_intent_id) ); - CREATE TABLE agent_org_runtime_turn_contexts( + CREATE TABLE agent_org_execution_turn_contexts( context_id INTEGER PRIMARY KEY AUTOINCREMENT, session_id TEXT,turn_intent_id TEXT,org_run_id TEXT, task_id TEXT,turn_kind TEXT,owner_member_id TEXT, activation_generation INTEGER ); - INSERT INTO agent_org_runtime_runs VALUES ('run','running',1); - INSERT INTO agent_org_runtime_tasks(org_run_id,id) VALUES ('run','old'); - INSERT INTO agent_org_runtime_tasks(org_run_id,id,status) + INSERT INTO agent_org_execution_runs VALUES ('run','running',1); + INSERT INTO agent_org_execution_tasks(org_run_id,id) VALUES ('run','old'); + INSERT INTO agent_org_execution_tasks(org_run_id,id,status) VALUES ('run','replacement','pending');", ) .unwrap(); @@ -1119,7 +1119,7 @@ mod tests { conn.execute_batch( "INSERT INTO session_turn_intents VALUES ('session','turn','run','running'); - INSERT INTO agent_org_runtime_turn_contexts( + INSERT INTO agent_org_execution_turn_contexts( session_id,turn_intent_id,org_run_id,task_id,turn_kind, owner_member_id,activation_generation ) VALUES ('session','turn','run','old','task_execution','member',1);", @@ -1225,7 +1225,7 @@ mod tests { assert_eq!(receipt.state, TaskExecutionHandoffState::Requested); conn.execute( - "UPDATE agent_org_runtime_task_execution_handoffs SET state='yielding' WHERE id=?1", + "UPDATE agent_org_execution_task_execution_handoffs SET state='yielding' WHERE id=?1", [&receipt.id], ) .unwrap(); @@ -1238,14 +1238,14 @@ mod tests { fn terminal_task_quiescence_requires_no_running_turn_or_external_uncertainty() { let conn = fixture(false); conn.execute( - "UPDATE agent_org_runtime_tasks SET status='cancelled' WHERE id='old'", + "UPDATE agent_org_execution_tasks SET status='cancelled' WHERE id='old'", [], ) .unwrap(); assert!(terminal_task_is_quiesced_with_connection(&conn, "run", "old").unwrap()); conn.execute( - "UPDATE agent_org_runtime_tasks SET external_effect_unknown=1 WHERE id='old'", + "UPDATE agent_org_execution_tasks SET external_effect_unknown=1 WHERE id='old'", [], ) .unwrap(); @@ -1254,7 +1254,7 @@ mod tests { let running = fixture(true); running .execute( - "UPDATE agent_org_runtime_tasks SET status='cancelled' WHERE id='old'", + "UPDATE agent_org_execution_tasks SET status='cancelled' WHERE id='old'", [], ) .unwrap(); @@ -1399,7 +1399,7 @@ mod tests { ) .unwrap(); conn.execute( - "UPDATE agent_org_runtime_task_execution_handoffs SET state='failed' WHERE id=?1", + "UPDATE agent_org_execution_task_execution_handoffs SET state='failed' WHERE id=?1", [&receipt.id], ) .unwrap(); @@ -1464,7 +1464,7 @@ mod tests { ) .unwrap(); conn.execute( - "UPDATE agent_org_runtime_task_execution_handoffs SET state='failed' WHERE id=?1", + "UPDATE agent_org_execution_task_execution_handoffs SET state='failed' WHERE id=?1", [&receipt.id], ) .unwrap(); @@ -1518,7 +1518,7 @@ mod tests { ); let count: i64 = conn .query_row( - "SELECT COUNT(*) FROM agent_org_runtime_task_execution_handoffs", + "SELECT COUNT(*) FROM agent_org_execution_task_execution_handoffs", [], |row| row.get(0), ) diff --git a/src-tauri/crates/agent-core/src/core/coordination/agent_org_tasks/actor.rs b/src-tauri/crates/agent-core/src/core/coordination/agent_org_tasks/actor.rs index faacd1e8ef..5329a067b6 100644 --- a/src-tauri/crates/agent-core/src/core/coordination/agent_org_tasks/actor.rs +++ b/src-tauri/crates/agent-core/src/core/coordination/agent_org_tasks/actor.rs @@ -56,7 +56,7 @@ impl TaskGraphWriterAdmin { )?; let root_session_id: Option = conn .query_row( - "SELECT root_session_id FROM agent_org_runtime_runs WHERE id=?1", + "SELECT root_session_id FROM agent_org_execution_runs WHERE id=?1", [org_run_id], |row| row.get(0), ) @@ -240,7 +240,7 @@ impl UserTaskHandoffAdmin { let row: Option<(String, i64, Option)> = conn .query_row( "SELECT status,activation_generation,root_session_id - FROM agent_org_runtime_runs WHERE id=?1", + FROM agent_org_execution_runs WHERE id=?1", [org_run_id], |row| Ok((row.get(0)?, row.get(1)?, row.get(2)?)), ) @@ -371,8 +371,8 @@ impl SystemArchiveOrRecovery { let archive: Option<(String, i64, i64)> = conn .query_row( "SELECT run.status,run.activation_generation,archive.archive_generation - FROM agent_org_runtime_archive_episodes archive - JOIN agent_org_runtime_runs run ON run.id=archive.org_run_id + FROM agent_org_execution_archive_episodes archive + JOIN agent_org_execution_runs run ON run.id=archive.org_run_id WHERE archive.org_run_id=?1 AND archive.archive_receipt_id=?2", params![org_run_id, &self.receipt_id], |row| Ok((row.get(0)?, row.get(1)?, row.get(2)?)), @@ -407,7 +407,7 @@ impl SystemArchiveOrRecovery { let receipt: Option<(String, i64)> = conn .query_row( "SELECT action_kind, attempts - FROM agent_org_runtime_recovery_attempts + FROM agent_org_execution_recovery_attempts WHERE org_run_id=?1 AND reservation_token=?2 AND action_kind=?3 AND target_key=?4", params![org_run_id, &self.receipt_id, action_kind, target_key], @@ -525,7 +525,7 @@ fn load_run_snapshot( let row: Option<(String, i64, Option)> = conn .query_row( "SELECT status, activation_generation, org_snapshot_json - FROM agent_org_runtime_runs WHERE id=?1", + FROM agent_org_execution_runs WHERE id=?1", [org_run_id], |row| Ok((row.get(0)?, row.get(1)?, row.get(2)?)), ) diff --git a/src-tauri/crates/agent-core/src/core/coordination/agent_org_tasks/helpers.rs b/src-tauri/crates/agent-core/src/core/coordination/agent_org_tasks/helpers.rs index c9701d7b93..641217bb5d 100644 --- a/src-tauri/crates/agent-core/src/core/coordination/agent_org_tasks/helpers.rs +++ b/src-tauri/crates/agent-core/src/core/coordination/agent_org_tasks/helpers.rs @@ -205,7 +205,7 @@ pub(super) fn insert_task_history_event( "system" }; tx.execute( - "INSERT INTO agent_org_runtime_task_events ( + "INSERT INTO agent_org_execution_task_events ( id, org_run_id, task_id, event_type, previous_owner, next_owner, previous_status, next_status, actor_member_id, actor_kind, source_turn_intent_id, created_at @@ -238,7 +238,7 @@ pub(super) fn insert_task_history_event_as( actor: &super::actor::TaskActorAudit, ) -> Result<(), String> { tx.execute( - "INSERT INTO agent_org_runtime_task_events ( + "INSERT INTO agent_org_execution_task_events ( id, org_run_id, task_id, event_type, previous_owner, next_owner, previous_status, next_status, actor_member_id, actor_kind, source_turn_intent_id, created_at @@ -267,7 +267,7 @@ pub(super) fn list_tasks_with_conn( org_run_id: &str, ) -> Result, String> { let sql = format!( - "SELECT {SELECT_COLUMNS} FROM agent_org_runtime_tasks + "SELECT {SELECT_COLUMNS} FROM agent_org_execution_tasks WHERE org_run_id = ?1 ORDER BY created_at ASC, id ASC" ); diff --git a/src-tauri/crates/agent-core/src/core/coordination/agent_org_tasks/mod.rs b/src-tauri/crates/agent-core/src/core/coordination/agent_org_tasks/mod.rs index f3ac88d6e3..60b40f1905 100644 --- a/src-tauri/crates/agent-core/src/core/coordination/agent_org_tasks/mod.rs +++ b/src-tauri/crates/agent-core/src/core/coordination/agent_org_tasks/mod.rs @@ -673,14 +673,14 @@ pub fn init_schema(conn: &Connection) -> SqliteResult<()> { pub(crate) fn create_history_page_index(conn: &Connection) -> SqliteResult<()> { conn.execute_batch( - "CREATE INDEX IF NOT EXISTS idx_agent_org_runtime_tasks_history_page - ON agent_org_runtime_tasks(org_run_id, status, updated_at, id);", + "CREATE INDEX IF NOT EXISTS idx_agent_org_execution_tasks_history_page + ON agent_org_execution_tasks(org_run_id, status, updated_at, id);", ) } pub(crate) fn create_schema(conn: &Connection) -> SqliteResult<()> { conn.execute_batch( - "CREATE TABLE IF NOT EXISTS agent_org_runtime_tasks ( + "CREATE TABLE IF NOT EXISTS agent_org_execution_tasks ( id TEXT NOT NULL, org_run_id TEXT NOT NULL, activation_generation INTEGER NOT NULL CHECK(activation_generation >= 1), @@ -705,7 +705,7 @@ pub(crate) fn create_schema(conn: &Connection) -> SqliteResult<()> { updated_at TEXT NOT NULL, PRIMARY KEY (org_run_id, id), FOREIGN KEY (org_run_id, replaces_task_id) - REFERENCES agent_org_runtime_tasks(org_run_id, id), + REFERENCES agent_org_execution_tasks(org_run_id, id), CHECK(owner IS NULL OR (trim(owner) <> '' AND owner <> 'coordinator')), CHECK(replaces_task_id IS NULL OR replaces_task_id <> id), CHECK(json_valid(blocked_by_json)=1 AND json_type(blocked_by_json)='array'), @@ -725,13 +725,13 @@ pub(crate) fn create_schema(conn: &Connection) -> SqliteResult<()> { OR (status='cancelled' AND output_json IS NULL AND failure_reason_json IS NULL AND cancel_reason_json IS NOT NULL) ) ); - CREATE INDEX IF NOT EXISTS idx_agent_org_runtime_tasks_page - ON agent_org_runtime_tasks(org_run_id, status, created_at, id); - CREATE INDEX IF NOT EXISTS idx_agent_org_runtime_tasks_owner - ON agent_org_runtime_tasks(org_run_id, owner, status); - CREATE INDEX IF NOT EXISTS idx_agent_org_runtime_tasks_replacement - ON agent_org_runtime_tasks(org_run_id, replaces_task_id); - CREATE TABLE IF NOT EXISTS agent_org_runtime_task_events ( + CREATE INDEX IF NOT EXISTS idx_agent_org_execution_tasks_page + ON agent_org_execution_tasks(org_run_id, status, created_at, id); + CREATE INDEX IF NOT EXISTS idx_agent_org_execution_tasks_owner + ON agent_org_execution_tasks(org_run_id, owner, status); + CREATE INDEX IF NOT EXISTS idx_agent_org_execution_tasks_replacement + ON agent_org_execution_tasks(org_run_id, replaces_task_id); + CREATE TABLE IF NOT EXISTS agent_org_execution_task_events ( id TEXT PRIMARY KEY, org_run_id TEXT NOT NULL, task_id TEXT NOT NULL, @@ -745,11 +745,11 @@ pub(crate) fn create_schema(conn: &Connection) -> SqliteResult<()> { source_turn_intent_id TEXT, created_at TEXT NOT NULL ); - CREATE INDEX IF NOT EXISTS idx_agent_org_runtime_task_events_run - ON agent_org_runtime_task_events(org_run_id, created_at, id); - CREATE INDEX IF NOT EXISTS idx_agent_org_runtime_task_events_task - ON agent_org_runtime_task_events(org_run_id, task_id, created_at, id); - CREATE TABLE IF NOT EXISTS agent_org_runtime_task_annotations ( + CREATE INDEX IF NOT EXISTS idx_agent_org_execution_task_events_run + ON agent_org_execution_task_events(org_run_id, created_at, id); + CREATE INDEX IF NOT EXISTS idx_agent_org_execution_task_events_task + ON agent_org_execution_task_events(org_run_id, task_id, created_at, id); + CREATE TABLE IF NOT EXISTS agent_org_execution_task_annotations ( id TEXT PRIMARY KEY, org_run_id TEXT NOT NULL, task_id TEXT NOT NULL, @@ -760,10 +760,10 @@ pub(crate) fn create_schema(conn: &Connection) -> SqliteResult<()> { source_turn_intent_id TEXT, created_at TEXT NOT NULL, FOREIGN KEY (org_run_id, task_id) - REFERENCES agent_org_runtime_tasks(org_run_id, id) ON DELETE CASCADE + REFERENCES agent_org_execution_tasks(org_run_id, id) ON DELETE CASCADE ); - CREATE INDEX IF NOT EXISTS idx_agent_org_runtime_task_annotations_page - ON agent_org_runtime_task_annotations(org_run_id, task_id, created_at, id);", + CREATE INDEX IF NOT EXISTS idx_agent_org_execution_task_annotations_page + ON agent_org_execution_task_annotations(org_run_id, task_id, created_at, id);", )?; create_history_page_index(conn) } @@ -1010,7 +1010,7 @@ fn persist_task_assignment_fact_in_tx( // delivery cannot escape their settlement or create a new Coordinator wake. let (current_status, current_owner, current_generation): (String, Option, i64) = conn .query_row( - "SELECT status,owner,activation_generation FROM agent_org_runtime_tasks + "SELECT status,owner,activation_generation FROM agent_org_execution_tasks WHERE org_run_id=?1 AND id=?2", rusqlite::params![&task.org_run_id, &task.id], |row| Ok((row.get(0)?, row.get(1)?, row.get(2)?)), @@ -1022,7 +1022,7 @@ fn persist_task_assignment_fact_in_tx( if obsolete { let row = AgentInboxStore::insert_in_tx_without_formal_trigger(conn, owner_delivery)?; conn.execute( - "INSERT INTO agent_org_runtime_inbox_delivery_resolutions ( + "INSERT INTO agent_org_execution_inbox_delivery_resolutions ( inbox_id,org_run_id,resolution_kind,resolved_by_member_id,reason,created_at ) VALUES (?1,?2,'cancelled','system:task_assignment',?3,?4)", rusqlite::params![ @@ -1072,7 +1072,7 @@ fn persist_task_assignment_fact_in_tx( let coordinator_agent_id: String = conn .query_row( - "SELECT coordinator_agent_id FROM agent_org_runtime_runs WHERE id=?1", + "SELECT coordinator_agent_id FROM agent_org_execution_runs WHERE id=?1", [&task.org_run_id], |row| row.get(0), ) diff --git a/src-tauri/crates/agent-core/src/core/coordination/agent_org_tasks/store/annotations.rs b/src-tauri/crates/agent-core/src/core/coordination/agent_org_tasks/store/annotations.rs index 6857ecc560..2de2ca3bae 100644 --- a/src-tauri/crates/agent-core/src/core/coordination/agent_org_tasks/store/annotations.rs +++ b/src-tauri/crates/agent-core/src/core/coordination/agent_org_tasks/store/annotations.rs @@ -121,7 +121,7 @@ impl AgentOrgTaskStore { let cursor = after_annotation_id .map(|id| { conn.query_row( - "SELECT created_at, id FROM agent_org_runtime_task_annotations + "SELECT created_at, id FROM agent_org_execution_task_annotations WHERE org_run_id=?1 AND task_id=?2 AND id=?3", params![org_run_id, task_id, id], |row| Ok((row.get::<_, String>(0)?, row.get::<_, String>(1)?)), @@ -139,7 +139,7 @@ impl AgentOrgTaskStore { .prepare( "SELECT id, org_run_id, task_id, kind, body, actor_kind, actor_participant_id, source_turn_intent_id, created_at - FROM agent_org_runtime_task_annotations + FROM agent_org_execution_task_annotations WHERE org_run_id=?1 AND task_id=?2 AND (?3 IS NULL OR created_at>?3 OR (created_at=?3 AND id>?4)) ORDER BY created_at ASC, id ASC LIMIT ?5", @@ -254,7 +254,7 @@ fn append_annotation_in_tx( )?; ensure_run_allows_task_mutation(conn, org_run_id)?; let sql = format!( - "SELECT {SELECT_COLUMNS} FROM agent_org_runtime_tasks + "SELECT {SELECT_COLUMNS} FROM agent_org_execution_tasks WHERE org_run_id=?1 AND id=?2" ); let task = conn @@ -275,7 +275,7 @@ fn append_annotation_in_tx( created_at: now_rfc3339(), }; conn.execute( - "INSERT INTO agent_org_runtime_task_annotations( + "INSERT INTO agent_org_execution_task_annotations( id, org_run_id, task_id, kind, body, actor_kind, actor_participant_id, source_turn_intent_id, created_at ) VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9)", diff --git a/src-tauri/crates/agent-core/src/core/coordination/agent_org_tasks/store/create.rs b/src-tauri/crates/agent-core/src/core/coordination/agent_org_tasks/store/create.rs index 045604e268..e4199390b2 100644 --- a/src-tauri/crates/agent-core/src/core/coordination/agent_org_tasks/store/create.rs +++ b/src-tauri/crates/agent-core/src/core/coordination/agent_org_tasks/store/create.rs @@ -117,7 +117,7 @@ impl AgentOrgTaskStore { let mut candidate_tasks = list_tasks_with_conn(&tx, ¶ms.org_run_id)?; let activation_generation: i64 = tx .query_row( - "SELECT activation_generation FROM agent_org_runtime_runs WHERE id=?1", + "SELECT activation_generation FROM agent_org_execution_runs WHERE id=?1", [¶ms.org_run_id], |row| row.get(0), ) @@ -180,7 +180,7 @@ impl AgentOrgTaskStore { let output_json = encode_optional_json("task output", task.output.as_ref())?; tx.execute( - "INSERT INTO agent_org_runtime_tasks ( + "INSERT INTO agent_org_execution_tasks ( id, org_run_id, activation_generation, subject, description, active_form, owner, status, execution_mode, blocked_by_json, metadata_json, output_json, failure_reason_json, cancel_reason_json, @@ -374,7 +374,7 @@ impl AgentOrgTaskStore { let now = now_rfc3339(); let activation_generation: i64 = tx .query_row( - "SELECT activation_generation FROM agent_org_runtime_runs WHERE id=?1", + "SELECT activation_generation FROM agent_org_execution_runs WHERE id=?1", [&org_run_id], |row| row.get(0), ) @@ -419,7 +419,7 @@ impl AgentOrgTaskStore { let metadata_json = encode_metadata(task.metadata.as_ref())?; let output_json = encode_optional_json("task output", task.output.as_ref())?; tx.execute( - "INSERT INTO agent_org_runtime_tasks ( + "INSERT INTO agent_org_execution_tasks ( id, org_run_id, activation_generation, subject, description, active_form, owner, status, execution_mode, blocked_by_json, metadata_json, output_json, failure_reason_json, cancel_reason_json, diff --git a/src-tauri/crates/agent-core/src/core/coordination/agent_org_tasks/store/delete.rs b/src-tauri/crates/agent-core/src/core/coordination/agent_org_tasks/store/delete.rs index 048210809b..9f9f95824f 100644 --- a/src-tauri/crates/agent-core/src/core/coordination/agent_org_tasks/store/delete.rs +++ b/src-tauri/crates/agent-core/src/core/coordination/agent_org_tasks/store/delete.rs @@ -80,7 +80,7 @@ impl AgentOrgTaskStore { .query_row( "SELECT EXISTS( SELECT 1 - FROM agent_org_runtime_inbox_delivery_resolutions + FROM agent_org_execution_inbox_delivery_resolutions WHERE org_run_id=?1 AND replacement_task_id=?2 )", params![org_run_id, task_id], @@ -109,7 +109,7 @@ impl AgentOrgTaskStore { )?; let n = tx .execute( - "DELETE FROM agent_org_runtime_tasks WHERE org_run_id = ?1 AND id = ?2", + "DELETE FROM agent_org_execution_tasks WHERE org_run_id = ?1 AND id = ?2", params![org_run_id, task_id], ) .map_err(|err| err.to_string())?; diff --git a/src-tauri/crates/agent-core/src/core/coordination/agent_org_tasks/store/dependencies.rs b/src-tauri/crates/agent-core/src/core/coordination/agent_org_tasks/store/dependencies.rs index f9857c661e..57d9659957 100644 --- a/src-tauri/crates/agent-core/src/core/coordination/agent_org_tasks/store/dependencies.rs +++ b/src-tauri/crates/agent-core/src/core/coordination/agent_org_tasks/store/dependencies.rs @@ -36,7 +36,7 @@ pub(super) fn persist_canonical_blocked_by_for_test_fixture( ) -> Result<(), String> { let mut stmt = conn .prepare( - "UPDATE agent_org_runtime_tasks + "UPDATE agent_org_execution_tasks SET blocked_by_json=?1 WHERE org_run_id=?2 AND id=?3 AND blocked_by_json<>?1", ) @@ -56,7 +56,7 @@ pub(super) fn run_is_safe_for_operational_projection( ) -> Result { let count: i64 = conn .query_row( - "SELECT COUNT(*) FROM agent_org_runtime_tasks + "SELECT COUNT(*) FROM agent_org_execution_tasks WHERE org_run_id=?1 AND status IN ('pending','in_progress')", params![run_id], |row| row.get(0), @@ -72,11 +72,11 @@ pub(super) fn run_is_safe_for_operational_projection( let sql = format!( "WITH operational_ids(id) AS ( SELECT id - FROM agent_org_runtime_tasks + FROM agent_org_execution_tasks WHERE org_run_id=?1 AND status IN ('pending','in_progress') UNION SELECT CAST(edge.value AS TEXT) - FROM agent_org_runtime_tasks open_task, + FROM agent_org_execution_tasks open_task, json_each( CASE WHEN json_valid(open_task.blocked_by_json) THEN open_task.blocked_by_json ELSE '[]' END @@ -97,7 +97,7 @@ pub(super) fn run_is_safe_for_operational_projection( CASE WHEN metadata_json IS NULL OR length(CAST(metadata_json AS BLOB))<={metadata_max} THEN metadata_json ELSE '!' END AS metadata_json - FROM agent_org_runtime_tasks + FROM agent_org_execution_tasks WHERE org_run_id=?1 AND id IN (SELECT id FROM operational_ids) ) AS bounded_tasks" ); diff --git a/src-tauri/crates/agent-core/src/core/coordination/agent_org_tasks/store/fsm.rs b/src-tauri/crates/agent-core/src/core/coordination/agent_org_tasks/store/fsm.rs index 91f30b6937..984cf4e20d 100644 --- a/src-tauri/crates/agent-core/src/core/coordination/agent_org_tasks/store/fsm.rs +++ b/src-tauri/crates/agent-core/src/core/coordination/agent_org_tasks/store/fsm.rs @@ -71,8 +71,8 @@ fn task_assignment_is_materialized_for_turn( .prepare( "SELECT EXISTS( SELECT 1 - FROM agent_org_runtime_inbox inbox - JOIN agent_org_runtime_inbox_materializations materialization + FROM agent_org_execution_inbox inbox + JOIN agent_org_execution_inbox_materializations materialization ON materialization.inbox_id=inbox.id AND materialization.session_id=?2 WHERE inbox.id=?1 @@ -86,7 +86,7 @@ fn task_assignment_is_materialized_for_turn( AND json_extract(inbox.payload_json,'$.task_id')=?5 AND NOT EXISTS ( SELECT 1 - FROM agent_org_runtime_inbox_delivery_resolutions resolution + FROM agent_org_execution_inbox_delivery_resolutions resolution WHERE resolution.inbox_id=inbox.id ) )", @@ -903,7 +903,7 @@ impl AgentOrgTaskStore { ) -> Result<(TaskMutationOutcome, T), String> { let current_status: Option = conn .query_row( - "SELECT status FROM agent_org_runtime_tasks + "SELECT status FROM agent_org_execution_tasks WHERE org_run_id=?1 AND id=?2", params![org_run_id, task_id], |row| row.get(0), @@ -1298,7 +1298,7 @@ impl AgentOrgTaskStore { ) -> Result<(), String> { let replaced_status: Option = tx .query_row( - "SELECT status FROM agent_org_runtime_tasks WHERE org_run_id=?1 AND id=?2", + "SELECT status FROM agent_org_execution_tasks WHERE org_run_id=?1 AND id=?2", params![org_run_id, replaced_id], |row| row.get(0), ) @@ -1349,7 +1349,7 @@ fn insert_task_row(tx: &rusqlite::Connection, task: &Task) -> Result<(), String> let cancel_reason_json = encode_optional_json("task cancel reason", task.cancel_reason.as_ref())?; tx.execute( - "INSERT INTO agent_org_runtime_tasks ( + "INSERT INTO agent_org_execution_tasks ( id, org_run_id, activation_generation, subject, description, active_form, owner, status, execution_mode, blocked_by_json, metadata_json, output_json, failure_reason_json, cancel_reason_json, created_by_participant_id, @@ -1423,9 +1423,9 @@ fn ensure_no_active_episode_semantic_duplicate( return Ok(()); }; let sql = format!( - "SELECT {SELECT_COLUMNS} FROM agent_org_runtime_tasks + "SELECT {SELECT_COLUMNS} FROM agent_org_execution_tasks WHERE org_run_id=?1 AND id IN ( - SELECT task_id FROM agent_org_runtime_work_episode_tasks + SELECT task_id FROM agent_org_execution_work_episode_tasks WHERE org_run_id=?1 AND work_episode_id=?2 )" ); @@ -1545,7 +1545,7 @@ fn update_task_row(tx: &rusqlite::Connection, task: &Task) -> Result<(), String> encode_optional_json("task cancel reason", task.cancel_reason.as_ref())?; let changed = tx .execute( - "UPDATE agent_org_runtime_tasks SET + "UPDATE agent_org_execution_tasks SET subject=?1, description=?2, active_form=?3, owner=?4, status=?5, execution_mode=?6, blocked_by_json=?7, metadata_json=?8, output_json=?9, failure_reason_json=?10, cancel_reason_json=?11, @@ -1572,6 +1572,7 @@ fn update_task_row(tx: &rusqlite::Connection, task: &Task) -> Result<(), String> if changed != 1 { return Err(format!("task_not_found: {}", task.id)); } + crate::coordination::agent_org_history_store::mirror_task_output(tx, task)?; Ok(()) } @@ -1606,7 +1607,7 @@ fn mutate_lifecycle_in_tx( ) -> Result<(TaskMutationOutcome, T), String> { ensure_run_allows_task_mutation(conn, org_run_id)?; let sql = format!( - "SELECT {SELECT_COLUMNS} FROM agent_org_runtime_tasks + "SELECT {SELECT_COLUMNS} FROM agent_org_execution_tasks WHERE org_run_id=?1 AND id=?2" ); let previous: Task = conn diff --git a/src-tauri/crates/agent-core/src/core/coordination/agent_org_tasks/store/plan_completion.rs b/src-tauri/crates/agent-core/src/core/coordination/agent_org_tasks/store/plan_completion.rs index 0bce4c92d1..52d621ab16 100644 --- a/src-tauri/crates/agent-core/src/core/coordination/agent_org_tasks/store/plan_completion.rs +++ b/src-tauri/crates/agent-core/src/core/coordination/agent_org_tasks/store/plan_completion.rs @@ -55,7 +55,7 @@ impl AgentOrgTaskStore { plan_revision_id, )?; let sql = format!( - "SELECT {SELECT_COLUMNS} FROM agent_org_runtime_tasks + "SELECT {SELECT_COLUMNS} FROM agent_org_execution_tasks WHERE org_run_id = ?1 AND id = ?2" ); let previous: Option = tx @@ -98,7 +98,7 @@ impl AgentOrgTaskStore { let output_json = encode_optional_json("task output", current.output.as_ref())?; let changed = tx .execute( - "UPDATE agent_org_runtime_tasks + "UPDATE agent_org_execution_tasks SET status = ?1, output_json = ?2, updated_at = ?3 WHERE org_run_id = ?4 AND id = ?5 AND status = ?6 AND owner = ?7", params![ @@ -118,6 +118,7 @@ impl AgentOrgTaskStore { super::TASK_MUTATION_CONFLICT_ERROR )); } + crate::coordination::agent_org_history_store::mirror_task_output(tx, ¤t)?; insert_task_history_event_as( tx, org_run_id, @@ -170,8 +171,8 @@ fn validate_plan_decision_authority( .query_row( "SELECT EXISTS( SELECT 1 - FROM agent_org_runtime_plan_revisions revision - JOIN agent_org_runtime_plan_decisions decision + FROM agent_org_execution_plan_revisions revision + JOIN agent_org_execution_plan_decisions decision ON decision.plan_revision_id=revision.plan_revision_id WHERE revision.plan_revision_id=?1 AND revision.org_run_id=?2 AND revision.source_task_id=?3 AND revision.source_member_id=?4 @@ -197,7 +198,7 @@ fn validate_plan_decision_authority( let (status_raw, generation, root_session_id): (String, i64, Option) = conn .query_row( "SELECT status,activation_generation,root_session_id - FROM agent_org_runtime_runs WHERE id=?1", + FROM agent_org_execution_runs WHERE id=?1", [org_run_id], |row| Ok((row.get(0)?, row.get(1)?, row.get(2)?)), ) diff --git a/src-tauri/crates/agent-core/src/core/coordination/agent_org_tasks/store/read.rs b/src-tauri/crates/agent-core/src/core/coordination/agent_org_tasks/store/read.rs index c68c30597d..b31c5f1282 100644 --- a/src-tauri/crates/agent-core/src/core/coordination/agent_org_tasks/store/read.rs +++ b/src-tauri/crates/agent-core/src/core/coordination/agent_org_tasks/store/read.rs @@ -101,7 +101,7 @@ impl AgentOrgTaskStore { pub fn get(org_run_id: &str, task_id: &str) -> Result, String> { let conn = get_connection().map_err(|error| error.to_string())?; let sql = format!( - "SELECT {SELECT_COLUMNS} FROM agent_org_runtime_tasks + "SELECT {SELECT_COLUMNS} FROM agent_org_execution_tasks WHERE org_run_id=?1 AND id=?2" ); let mut task = conn @@ -115,7 +115,7 @@ impl AgentOrgTaskStore { let mut stmt = conn .prepare( "SELECT downstream.id - FROM agent_org_runtime_tasks downstream, + FROM agent_org_execution_tasks downstream, json_each(downstream.blocked_by_json) edge WHERE downstream.org_run_id=?1 AND edge.value=?2 ORDER BY downstream.created_at ASC, downstream.id ASC", @@ -137,8 +137,8 @@ impl AgentOrgTaskStore { run_id: &str, episode_id: &str, ) -> Result, String> { - let sql=format!("SELECT {SELECT_COLUMNS} FROM agent_org_runtime_tasks task - WHERE org_run_id=?1 AND EXISTS(SELECT 1 FROM agent_org_runtime_work_episode_tasks episode_task + let sql=format!("SELECT {SELECT_COLUMNS} FROM agent_org_execution_tasks task + WHERE org_run_id=?1 AND EXISTS(SELECT 1 FROM agent_org_execution_work_episode_tasks episode_task WHERE episode_task.org_run_id=task.org_run_id AND episode_task.task_id=task.id AND episode_task.work_episode_id=?2) ORDER BY created_at,id"); let mut stmt = conn.prepare(&sql).map_err(|e| e.to_string())?; @@ -177,11 +177,11 @@ impl AgentOrgTaskStore { .prepare( "WITH operational_ids(id) AS ( SELECT id - FROM agent_org_runtime_tasks + FROM agent_org_execution_tasks WHERE org_run_id=?1 AND status IN ('pending','in_progress') UNION SELECT CAST(edge.value AS TEXT) - FROM agent_org_runtime_tasks open_task, + FROM agent_org_execution_tasks open_task, json_each( CASE WHEN json_valid(open_task.blocked_by_json) THEN open_task.blocked_by_json ELSE '[]' END @@ -200,7 +200,7 @@ impl AgentOrgTaskStore { THEN json_extract(task.metadata_json,'$.eligible_member_ids') ELSE '[]' END, task.created_at, task.updated_at - FROM agent_org_runtime_tasks task + FROM agent_org_execution_tasks task JOIN operational_ids ON operational_ids.id=task.id WHERE task.org_run_id=?1 ORDER BY task.created_at ASC, task.id ASC", @@ -288,7 +288,7 @@ impl AgentOrgTaskStore { let cursor = after_task_id .map(|task_id| { conn.query_row( - "SELECT created_at,id FROM agent_org_runtime_tasks + "SELECT created_at,id FROM agent_org_execution_tasks WHERE org_run_id=?1 AND id=?2", params![org_run_id, task_id], |row| Ok((row.get::<_, String>(0)?, row.get::<_, String>(1)?)), @@ -384,7 +384,7 @@ impl AgentOrgTaskStore { let bucket_wire = bucket.map(TaskPageBucket::as_wire); let filtered_total: i64 = if bucket.is_none() { conn.query_row( - "SELECT COUNT(*) FROM agent_org_runtime_tasks + "SELECT COUNT(*) FROM agent_org_execution_tasks WHERE org_run_id=?1 AND (?2 IS NULL OR status=?2) AND (?3 IS NULL OR owner=?3)", params![org_run_id, status_wire, owner], @@ -418,11 +418,11 @@ impl AgentOrgTaskStore { ( "COALESCE((SELECT json_group_array(id) FROM ( SELECT downstream.id AS id - FROM agent_org_runtime_tasks downstream, json_each(downstream.blocked_by_json) edge + FROM agent_org_execution_tasks downstream, json_each(downstream.blocked_by_json) edge WHERE downstream.org_run_id=task.org_run_id AND edge.value=task.id ORDER BY downstream.created_at, downstream.id LIMIT ?9 )),'[]')", - "(SELECT COUNT(*) FROM agent_org_runtime_tasks downstream, json_each(downstream.blocked_by_json) edge + "(SELECT COUNT(*) FROM agent_org_execution_tasks downstream, json_each(downstream.blocked_by_json) edge WHERE downstream.org_run_id=task.org_run_id AND edge.value=task.id)", ) } else { @@ -449,7 +449,7 @@ impl AgentOrgTaskStore { NOT EXISTS ( SELECT 1 FROM json_each(task.blocked_by_json) edge - LEFT JOIN agent_org_runtime_tasks blocker + LEFT JOIN agent_org_execution_tasks blocker ON blocker.org_run_id=task.org_run_id AND blocker.id=edge.value WHERE blocker.id IS NULL OR blocker.status<>'completed' @@ -476,7 +476,7 @@ impl AgentOrgTaskStore { task.failure_reason_json, task.cancel_reason_json, task.replaces_task_id, task.created_at, task.updated_at, task.activation_generation, {corrupt_predicate} - FROM agent_org_runtime_tasks task + FROM agent_org_execution_tasks task WHERE task.org_run_id=?1 AND (?2 IS NULL OR task.status=?2) AND (?3 IS NULL OR task.owner=?3) @@ -658,7 +658,7 @@ impl AgentOrgTaskStore { let bounded_limit = limit.clamp(1, 500); let mut stmt = conn .prepare( - "SELECT id FROM agent_org_runtime_tasks + "SELECT id FROM agent_org_execution_tasks WHERE org_run_id=?1 AND status IN ('pending','in_progress') ORDER BY created_at ASC,id ASC LIMIT ?2", ) @@ -698,7 +698,7 @@ impl AgentOrgTaskStore { "SELECT id,org_run_id,task_id,event_type,previous_owner,next_owner, previous_status,next_status,actor_member_id,actor_kind, source_turn_intent_id,created_at - FROM agent_org_runtime_task_events WHERE org_run_id=?1 + FROM agent_org_execution_task_events WHERE org_run_id=?1 ORDER BY created_at ASC,id ASC", ) .map_err(|error| error.to_string())?; diff --git a/src-tauri/crates/agent-core/src/core/coordination/agent_org_tasks/store/repair.rs b/src-tauri/crates/agent-core/src/core/coordination/agent_org_tasks/store/repair.rs index bdaa0d01aa..cb30d56e18 100644 --- a/src-tauri/crates/agent-core/src/core/coordination/agent_org_tasks/store/repair.rs +++ b/src-tauri/crates/agent-core/src/core/coordination/agent_org_tasks/store/repair.rs @@ -47,20 +47,20 @@ impl AgentOrgTaskStore { .prepare( "SELECT task.org_run_id,task.id,task.owner, latest.id,materialization.agent_id - FROM agent_org_runtime_tasks task - JOIN agent_org_runtime_runs run + FROM agent_org_execution_tasks task + JOIN agent_org_execution_runs run ON run.id=task.org_run_id AND run.status='running' - JOIN agent_org_runtime_task_events latest + JOIN agent_org_execution_task_events latest ON latest.rowid=( SELECT MAX(event.rowid) - FROM agent_org_runtime_task_events event + FROM agent_org_execution_task_events event WHERE event.org_run_id=task.org_run_id AND event.task_id=task.id ) - JOIN agent_org_runtime_member_materializations materialization + JOIN agent_org_execution_member_materializations materialization ON materialization.rowid=( SELECT MAX(candidate.rowid) - FROM agent_org_runtime_member_materializations candidate + FROM agent_org_execution_member_materializations candidate WHERE candidate.org_run_id=task.org_run_id AND candidate.member_id=task.owner AND candidate.status='succeeded' @@ -68,19 +68,19 @@ impl AgentOrgTaskStore { WHERE task.status='pending' AND task.owner IS NOT NULL AND NOT EXISTS ( SELECT 1 FROM json_each(task.blocked_by_json) dependency - LEFT JOIN agent_org_runtime_tasks blocker + LEFT JOIN agent_org_execution_tasks blocker ON blocker.org_run_id=task.org_run_id AND blocker.id=dependency.value WHERE blocker.id IS NULL OR blocker.status<>'completed' ) AND NOT EXISTS ( - SELECT 1 FROM agent_org_task_execution_leases lease + SELECT 1 FROM agent_org_execution_task_execution_leases lease WHERE lease.org_run_id=task.org_run_id AND lease.task_id=task.id AND lease.state='active' ) AND NOT EXISTS ( SELECT 1 - FROM agent_org_runtime_turn_contexts context + FROM agent_org_execution_turn_contexts context JOIN session_turn_intents intent ON intent.session_id=context.session_id AND intent.turn_intent_id=context.turn_intent_id @@ -90,7 +90,7 @@ impl AgentOrgTaskStore { AND intent.status IN ('optimistic','queued','running') ) AND NOT EXISTS ( - SELECT 1 FROM agent_org_runtime_inbox inbox + SELECT 1 FROM agent_org_execution_inbox inbox WHERE inbox.org_run_id=task.org_run_id AND inbox.recipient_member_id=task.owner AND inbox.payload_kind='task_assigned' @@ -99,12 +99,12 @@ impl AgentOrgTaskStore { AND json_extract(inbox.payload_json,'$.task_id')=task.id AND NOT EXISTS ( SELECT 1 - FROM agent_org_runtime_inbox_delivery_resolutions resolution + FROM agent_org_execution_inbox_delivery_resolutions resolution WHERE resolution.inbox_id=inbox.id ) ) AND NOT EXISTS ( - SELECT 1 FROM agent_org_runtime_recovery_attempts repaired + SELECT 1 FROM agent_org_execution_recovery_attempts repaired WHERE repaired.org_run_id=task.org_run_id AND repaired.action_kind=?1 AND repaired.target_key=task.id @@ -164,8 +164,8 @@ impl AgentOrgTaskStore { let coordinator_receipt_id = tx .query_row( "SELECT receipt.receipt_id - FROM agent_org_runtime_inbox observer - JOIN agent_org_runtime_formal_trigger_receipts receipt + FROM agent_org_execution_inbox observer + JOIN agent_org_execution_formal_trigger_receipts receipt ON receipt.inbox_id=observer.id WHERE observer.causation_inbox_id=?1 AND observer.org_run_id=?2 @@ -188,7 +188,7 @@ impl AgentOrgTaskStore { })?; let now = chrono::Utc::now().to_rfc3339(); tx.execute( - "INSERT INTO agent_org_runtime_recovery_attempts( + "INSERT INTO agent_org_execution_recovery_attempts( org_run_id,action_kind,target_key,reason_fingerprint, attempts,next_allowed_at,updated_at,reservation_token ) VALUES (?1,?2,?3,?4,1,?5,?5,NULL) diff --git a/src-tauri/crates/agent-core/src/core/coordination/agent_org_tasks/store/requeue.rs b/src-tauri/crates/agent-core/src/core/coordination/agent_org_tasks/store/requeue.rs index 86dcabae51..acf2f388be 100644 --- a/src-tauri/crates/agent-core/src/core/coordination/agent_org_tasks/store/requeue.rs +++ b/src-tauri/crates/agent-core/src/core/coordination/agent_org_tasks/store/requeue.rs @@ -129,11 +129,11 @@ fn recover_task_execution_failure_inner( failed_turn_intent_id, )?; let sql = format!( - "SELECT {SELECT_COLUMNS} FROM agent_org_runtime_tasks task + "SELECT {SELECT_COLUMNS} FROM agent_org_execution_tasks task WHERE task.org_run_id=?1 AND task.id=?2 AND task.owner=?3 AND task.status='in_progress' AND NOT EXISTS ( - SELECT 1 FROM agent_org_task_execution_leases live + SELECT 1 FROM agent_org_execution_task_execution_leases live WHERE live.org_run_id=task.org_run_id AND live.task_id=task.id AND live.state='active' @@ -143,7 +143,7 @@ fn recover_task_execution_failure_inner( ) ) AND EXISTS ( - SELECT 1 FROM agent_org_runtime_task_events event + SELECT 1 FROM agent_org_execution_task_events event WHERE event.org_run_id=task.org_run_id AND event.task_id=task.id AND event.previous_status='pending' @@ -154,7 +154,7 @@ fn recover_task_execution_failure_inner( AND event.created_at=task.updated_at AND event.rowid=( SELECT MAX(latest.rowid) - FROM agent_org_runtime_task_events latest + FROM agent_org_execution_task_events latest WHERE latest.org_run_id=task.org_run_id AND latest.task_id=task.id ) @@ -343,7 +343,7 @@ fn release_owned_tasks_for_shutdown( .map_err(|error| error.to_string())?; let audit = actor.validate(&tx, org_run_id, owner_member_id)?; let sql = format!( - "SELECT {SELECT_COLUMNS} FROM agent_org_runtime_tasks + "SELECT {SELECT_COLUMNS} FROM agent_org_execution_tasks WHERE org_run_id=?1 AND owner=?2 AND status IN ('pending','in_progress') ORDER BY created_at ASC,id ASC" ); @@ -408,7 +408,7 @@ fn recover_task_in_tx( encode_optional_json("task failure reason", task.failure_reason.as_ref())?; let changed = tx .execute( - "UPDATE agent_org_runtime_tasks + "UPDATE agent_org_execution_tasks SET owner=?1,status=?2,metadata_json=?3,failure_reason_json=?4, output_json=NULL,cancel_reason_json=NULL,updated_at=?5 WHERE org_run_id=?6 AND id=?7 AND owner=?8 @@ -448,7 +448,7 @@ fn recover_task_in_tx( "Owner turn failed; Task was restored to ownerless pending" }; tx.execute( - "INSERT INTO agent_org_runtime_task_annotations( + "INSERT INTO agent_org_execution_task_annotations( id,org_run_id,task_id,kind,body,actor_kind, actor_participant_id,source_turn_intent_id,created_at ) VALUES (?1,?2,?3,?4,?5,?6,?7,?8,?9)", @@ -479,7 +479,7 @@ fn release_reservation_in_tx( ) -> Result<(), String> { let changed = tx .execute( - "UPDATE agent_org_runtime_recovery_attempts SET reservation_token=NULL + "UPDATE agent_org_execution_recovery_attempts SET reservation_token=NULL WHERE org_run_id=?1 AND reservation_token=?2 AND action_kind=?3 AND target_key=?4", params![ diff --git a/src-tauri/crates/agent-core/src/core/coordination/agent_org_tasks/store/update.rs b/src-tauri/crates/agent-core/src/core/coordination/agent_org_tasks/store/update.rs index e8434ad58c..3d2fcb3f04 100644 --- a/src-tauri/crates/agent-core/src/core/coordination/agent_org_tasks/store/update.rs +++ b/src-tauri/crates/agent-core/src/core/coordination/agent_org_tasks/store/update.rs @@ -275,7 +275,7 @@ impl AgentOrgTaskStore { encode_optional_json("task cancel reason", task.cancel_reason.as_ref())?; tx.execute( - "UPDATE agent_org_runtime_tasks SET + "UPDATE agent_org_execution_tasks SET subject = ?1, description = ?2, active_form = ?3, diff --git a/src-tauri/crates/agent-core/src/core/coordination/agent_org_tasks/store/validation.rs b/src-tauri/crates/agent-core/src/core/coordination/agent_org_tasks/store/validation.rs index 2ac690ea98..bf2ad304ab 100644 --- a/src-tauri/crates/agent-core/src/core/coordination/agent_org_tasks/store/validation.rs +++ b/src-tauri/crates/agent-core/src/core/coordination/agent_org_tasks/store/validation.rs @@ -70,7 +70,7 @@ pub(super) fn ensure_run_allows_task_mutation( let run: Option<(String, i64)> = conn .query_row( "SELECT status,activation_generation - FROM agent_org_runtime_runs WHERE id=?1", + FROM agent_org_execution_runs WHERE id=?1", params![org_run_id], |row| Ok((row.get(0)?, row.get(1)?)), ) @@ -105,7 +105,7 @@ pub(super) fn ensure_current_generation_has_no_certificate( let raw_generation_certificate: bool = conn .query_row( "SELECT EXISTS( - SELECT 1 FROM agent_org_runtime_run_completion_certificates + SELECT 1 FROM agent_org_execution_run_completion_certificates WHERE org_run_id=?1 AND activation_generation=?2 )", params![org_run_id, activation_generation], @@ -281,7 +281,7 @@ pub(super) fn validate_task_persistence_invariants( let snapshot_json: Option = conn .query_row( - "SELECT org_snapshot_json FROM agent_org_runtime_runs WHERE id=?1", + "SELECT org_snapshot_json FROM agent_org_execution_runs WHERE id=?1", params![org_run_id], |row| row.get(0), ) @@ -509,7 +509,7 @@ pub(super) fn validate_task_model_invariants( let snapshot_json: String = conn .query_row( - "SELECT org_snapshot_json FROM agent_org_runtime_runs WHERE id=?1", + "SELECT org_snapshot_json FROM agent_org_execution_runs WHERE id=?1", params![&task.org_run_id], |row| row.get::<_, Option>(0), ) diff --git a/src-tauri/crates/agent-core/src/core/coordination/agent_org_tasks/task_assignment_race_tests.rs b/src-tauri/crates/agent-core/src/core/coordination/agent_org_tasks/task_assignment_race_tests.rs index 71e396d0cc..b685657f7f 100644 --- a/src-tauri/crates/agent-core/src/core/coordination/agent_org_tasks/task_assignment_race_tests.rs +++ b/src-tauri/crates/agent-core/src/core/coordination/agent_org_tasks/task_assignment_race_tests.rs @@ -44,8 +44,8 @@ fn complete(task: &Task) { fn assert_cancelled(conn: &rusqlite::Connection, id: i64) { let (read_at, kind, reason): (Option, String, String) = conn.query_row( "SELECT inbox.read_at,resolution.resolution_kind,resolution.reason - FROM agent_org_runtime_inbox inbox - JOIN agent_org_runtime_inbox_delivery_resolutions resolution ON resolution.inbox_id=inbox.id + FROM agent_org_execution_inbox inbox + JOIN agent_org_execution_inbox_delivery_resolutions resolution ON resolution.inbox_id=inbox.id WHERE inbox.id=?1", [id], |row| Ok((row.get(0)?, row.get(1)?, row.get(2)?)), ).expect("obsolete delivery has an exact disposition"); assert!(read_at.is_none(), "system disposition is not model read"); @@ -54,8 +54,8 @@ fn assert_cancelled(conn: &rusqlite::Connection, id: i64) { assert_eq!(reason["code"], "obsolete_task_assignment"); let extra: i64 = conn .query_row( - "SELECT (SELECT COUNT(*) FROM agent_org_runtime_inbox WHERE causation_inbox_id=?1) - + (SELECT COUNT(*) FROM agent_org_runtime_formal_trigger_receipts WHERE inbox_id=?1)", + "SELECT (SELECT COUNT(*) FROM agent_org_execution_inbox WHERE causation_inbox_id=?1) + + (SELECT COUNT(*) FROM agent_org_execution_formal_trigger_receipts WHERE inbox_id=?1)", [id], |row| row.get(0), ) @@ -99,8 +99,8 @@ fn task_assignment_race_owner_changed_keeps_new_delivery_and_exact_old_dispositi let conn = get_connection().unwrap(); assert_cancelled(&conn, deliver(&snapshot).unwrap()); let state: (bool, i64) = conn.query_row( - "SELECT NOT EXISTS(SELECT 1 FROM agent_org_runtime_inbox_delivery_resolutions WHERE inbox_id=?1), - (SELECT COUNT(*) FROM agent_org_runtime_inbox WHERE causation_inbox_id=?1 AND payload_kind='task_assignment_committed')", + "SELECT NOT EXISTS(SELECT 1 FROM agent_org_execution_inbox_delivery_resolutions WHERE inbox_id=?1), + (SELECT COUNT(*) FROM agent_org_execution_inbox WHERE causation_inbox_id=?1 AND payload_kind='task_assignment_committed')", [fresh], |row| Ok((row.get(0)?, row.get(1)?)), ).unwrap(); assert_eq!( @@ -117,13 +117,15 @@ fn task_assignment_race_disposition_failure_rolls_back_delivery_and_is_a_real_er complete(&snapshot); let conn = get_connection().unwrap(); let count = || { - conn.query_row("SELECT COUNT(*) FROM agent_org_runtime_inbox", [], |row| { - row.get::<_, i64>(0) - }) + conn.query_row( + "SELECT COUNT(*) FROM agent_org_execution_inbox", + [], + |row| row.get::<_, i64>(0), + ) .unwrap() }; let before = count(); - conn.execute_batch("CREATE TRIGGER reject_late_disposition BEFORE INSERT ON agent_org_runtime_inbox_delivery_resolutions + conn.execute_batch("CREATE TRIGGER reject_late_disposition BEFORE INSERT ON agent_org_execution_inbox_delivery_resolutions BEGIN SELECT RAISE(ABORT, 'disposition storage failure'); END;").unwrap(); assert!(deliver(&snapshot) .unwrap_err() diff --git a/src-tauri/crates/agent-core/src/core/coordination/agent_org_tasks/task_store_contract_tests.rs b/src-tauri/crates/agent-core/src/core/coordination/agent_org_tasks/task_store_contract_tests.rs index 99abb0beae..4cb107ee6b 100644 --- a/src-tauri/crates/agent-core/src/core/coordination/agent_org_tasks/task_store_contract_tests.rs +++ b/src-tauri/crates/agent-core/src/core/coordination/agent_org_tasks/task_store_contract_tests.rs @@ -94,7 +94,7 @@ fn fixture() -> Fixture { }) .to_string(); conn.execute( - "INSERT INTO agent_org_runtime_runs( + "INSERT INTO agent_org_execution_runs( id,org_id,coordinator_agent_id,root_session_id,org_snapshot_json, entry_mode,status,activation_generation,created_at,updated_at ) VALUES (?1,'task-store-contract-org','agent-coordinator',?2,?3, @@ -140,7 +140,7 @@ fn insert_member_materialization( ) { let now = chrono::Utc::now().to_rfc3339(); conn.execute( - "INSERT INTO agent_org_runtime_member_materializations( + "INSERT INTO agent_org_execution_member_materializations( org_run_id,member_id,agent_id,generation,session_id, authority_class,status,created_at,updated_at ) VALUES (?1,?2,?3,?4,?5,'formal','succeeded',?6,?6)", @@ -164,7 +164,7 @@ fn insert_coordinator_context(conn: &rusqlite::Connection, turn_id: &str, genera insert_base_turn(conn, ROOT_SESSION, turn_id); let now = chrono::Utc::now().to_rfc3339(); conn.execute( - "INSERT INTO agent_org_runtime_turn_contexts( + "INSERT INTO agent_org_execution_turn_contexts( session_id,turn_intent_id,org_run_id,participant_id,turn_kind, source_kind,source_id,activation_generation,created_at ) VALUES (?1,?2,?3,'coordinator','coordinator','root_turn',?2,?4,?5)", @@ -186,7 +186,7 @@ fn insert_group_root_context(conn: &rusqlite::Connection, turn_id: &str, generat ) .expect("GroupRoot source event"); conn.execute( - "INSERT INTO agent_org_runtime_turn_contexts( + "INSERT INTO agent_org_execution_turn_contexts( session_id,turn_intent_id,org_run_id,participant_id,turn_kind, source_kind,source_id,activation_generation,created_at ) VALUES (?1,?2,?3,'coordinator','coordinator','group_root',?4,?5,?6)", @@ -212,7 +212,7 @@ fn insert_user_coordinator_context(conn: &rusqlite::Connection, turn_id: &str, g ) .expect("user Coordinator Turn"); conn.execute( - "INSERT INTO agent_org_runtime_turn_contexts( + "INSERT INTO agent_org_execution_turn_contexts( session_id,turn_intent_id,org_run_id,participant_id,turn_kind, source_kind,source_id,activation_generation,created_at ) VALUES (?1,?2,?3,'coordinator','coordinator','root_turn',?2,?4,?5)", @@ -233,7 +233,7 @@ fn insert_owner_context( let sequence: i64 = conn .query_row( "SELECT COALESCE(MAX(member_dispatch_sequence),0)+1 - FROM agent_org_runtime_turn_contexts + FROM agent_org_execution_turn_contexts WHERE org_run_id=?1 AND dispatch_member_id=?2", params![RUN_ID, member_id], |row| row.get(0), @@ -241,7 +241,7 @@ fn insert_owner_context( .expect("next sequence"); let now = chrono::Utc::now().to_rfc3339(); conn.execute( - "INSERT INTO agent_org_runtime_turn_contexts( + "INSERT INTO agent_org_execution_turn_contexts( session_id,turn_intent_id,org_run_id,participant_id,turn_kind, task_id,owner_member_id,dispatch_member_id,member_dispatch_sequence, source_kind,source_id,activation_generation,created_at @@ -255,7 +255,7 @@ fn insert_owner_context( fn grant_additional_writer(conn: &rusqlite::Connection, member_id: &str) { let snapshot: String = conn .query_row( - "SELECT org_snapshot_json FROM agent_org_runtime_runs WHERE id=?1", + "SELECT org_snapshot_json FROM agent_org_execution_runs WHERE id=?1", [RUN_ID], |row| row.get(0), ) @@ -264,7 +264,7 @@ fn grant_additional_writer(conn: &rusqlite::Connection, member_id: &str) { serde_json::from_str(&snapshot).expect("decode launch snapshot"); snapshot["additionalTaskGraphWriterMemberIds"] = serde_json::json!([member_id]); conn.execute( - "UPDATE agent_org_runtime_runs SET org_snapshot_json=?2 WHERE id=?1", + "UPDATE agent_org_execution_runs SET org_snapshot_json=?2 WHERE id=?1", params![RUN_ID, snapshot.to_string()], ) .expect("grant additional Writer in immutable test snapshot"); @@ -301,14 +301,14 @@ fn insert_direct_context( let sequence: i64 = conn .query_row( "SELECT COALESCE(MAX(member_dispatch_sequence),0)+1 - FROM agent_org_runtime_turn_contexts + FROM agent_org_execution_turn_contexts WHERE org_run_id=?1 AND dispatch_member_id=?2", params![RUN_ID, member_id], |row| row.get(0), ) .expect("next direct sequence"); conn.execute( - "INSERT INTO agent_org_runtime_turn_contexts( + "INSERT INTO agent_org_execution_turn_contexts( session_id,turn_intent_id,org_run_id,participant_id,turn_kind, dispatch_member_id,member_dispatch_sequence,source_kind,source_id, root_authority_turn_id,actor_version,created_at @@ -499,7 +499,7 @@ fn insert_materialized_task_deliveries( for (inbox_id, suffix) in [(bound.id, "bound"), (formal.id, "formal")] { conn.execute( - "INSERT INTO agent_org_runtime_inbox_materializations( + "INSERT INTO agent_org_execution_inbox_materializations( inbox_id,session_id,transcript_message_id,transcript_intent_id,materialized_at ) VALUES (?1,?2,?3,?4,?5)", params![ @@ -513,7 +513,7 @@ fn insert_materialized_task_deliveries( .expect("materialize exact Inbox row"); } conn.execute( - "UPDATE agent_org_runtime_formal_trigger_receipts + "UPDATE agent_org_execution_formal_trigger_receipts SET status='materialized',current_attempt=1, materialized_input_id=?2,materialized_event_id=?3,updated_at=?4 WHERE receipt_id=?1", @@ -526,7 +526,7 @@ fn insert_materialized_task_deliveries( ) .expect("materialize formal receipt"); conn.execute( - "INSERT INTO agent_org_runtime_formal_trigger_attempts( + "INSERT INTO agent_org_execution_formal_trigger_attempts( receipt_id,attempt,session_id,turn_intent_id,status, materialized_input_id,materialized_event_id,queued_at,started_at,updated_at ) VALUES (?1,1,?2,?3,'running',?4,?5,?6,?6,?6)", @@ -588,10 +588,10 @@ fn terminal_task_settles_only_its_exact_deliveries_and_formal_attempts() { let state: (bool, bool) = conn .query_row( "SELECT EXISTS( - SELECT 1 FROM agent_org_runtime_inbox_delivery_resolutions + SELECT 1 FROM agent_org_execution_inbox_delivery_resolutions WHERE inbox_id=?1 ), EXISTS( - SELECT 1 FROM agent_org_runtime_inbox_materializations + SELECT 1 FROM agent_org_execution_inbox_materializations WHERE inbox_id=?1 )", [inbox_id], @@ -603,8 +603,8 @@ fn terminal_task_settles_only_its_exact_deliveries_and_formal_attempts() { let task_a_formal: (String, String) = conn .query_row( "SELECT receipt.status,attempt.status - FROM agent_org_runtime_formal_trigger_receipts receipt - JOIN agent_org_runtime_formal_trigger_attempts attempt + FROM agent_org_execution_formal_trigger_receipts receipt + JOIN agent_org_execution_formal_trigger_attempts attempt ON attempt.receipt_id=receipt.receipt_id WHERE receipt.receipt_id=?1", [&task_a.formal_receipt_id], @@ -620,10 +620,10 @@ fn terminal_task_settles_only_its_exact_deliveries_and_formal_attempts() { let state: (bool, bool) = conn .query_row( "SELECT EXISTS( - SELECT 1 FROM agent_org_runtime_inbox_delivery_resolutions + SELECT 1 FROM agent_org_execution_inbox_delivery_resolutions WHERE inbox_id=?1 ), EXISTS( - SELECT 1 FROM agent_org_runtime_inbox_materializations + SELECT 1 FROM agent_org_execution_inbox_materializations WHERE inbox_id=?1 )", [inbox_id], @@ -635,8 +635,8 @@ fn terminal_task_settles_only_its_exact_deliveries_and_formal_attempts() { let task_b_formal: (String, String) = conn .query_row( "SELECT receipt.status,attempt.status - FROM agent_org_runtime_formal_trigger_receipts receipt - JOIN agent_org_runtime_formal_trigger_attempts attempt + FROM agent_org_execution_formal_trigger_receipts receipt + JOIN agent_org_execution_formal_trigger_attempts attempt ON attempt.receipt_id=receipt.receipt_id WHERE receipt.receipt_id=?1", [&task_b.formal_receipt_id], @@ -746,10 +746,10 @@ fn fail_cancel_replace_and_reassign_each_settle_the_exact_task_delivery() { let state: (bool, bool) = conn .query_row( "SELECT EXISTS( - SELECT 1 FROM agent_org_runtime_inbox_delivery_resolutions + SELECT 1 FROM agent_org_execution_inbox_delivery_resolutions WHERE inbox_id=?1 ), EXISTS( - SELECT 1 FROM agent_org_runtime_inbox_materializations + SELECT 1 FROM agent_org_execution_inbox_materializations WHERE inbox_id=?1 )", [inbox_id], @@ -761,8 +761,8 @@ fn fail_cancel_replace_and_reassign_each_settle_the_exact_task_delivery() { let formal_state: (String, String) = conn .query_row( "SELECT receipt.status,attempt.status - FROM agent_org_runtime_formal_trigger_receipts receipt - JOIN agent_org_runtime_formal_trigger_attempts attempt + FROM agent_org_execution_formal_trigger_receipts receipt + JOIN agent_org_execution_formal_trigger_attempts attempt ON attempt.receipt_id=receipt.receipt_id WHERE receipt.receipt_id=?1", [&delivery.formal_receipt_id], @@ -780,10 +780,10 @@ fn fail_cancel_replace_and_reassign_each_settle_the_exact_task_delivery() { let state: (bool, bool) = conn .query_row( "SELECT EXISTS( - SELECT 1 FROM agent_org_runtime_inbox_delivery_resolutions + SELECT 1 FROM agent_org_execution_inbox_delivery_resolutions WHERE inbox_id=?1 ), EXISTS( - SELECT 1 FROM agent_org_runtime_inbox_materializations + SELECT 1 FROM agent_org_execution_inbox_materializations WHERE inbox_id=?1 )", [inbox_id], @@ -802,7 +802,7 @@ fn task_terminal_write_rolls_back_when_exact_delivery_settlement_fails() { let delivery = insert_materialized_task_deliveries(&conn, "settlement-rollback"); conn.execute_batch( "CREATE TRIGGER reject_exact_delivery_settlement - BEFORE INSERT ON agent_org_runtime_inbox_delivery_resolutions + BEFORE INSERT ON agent_org_execution_inbox_delivery_resolutions BEGIN SELECT RAISE(ABORT, 'settlement fault'); END;", ) .unwrap(); @@ -830,10 +830,10 @@ fn task_terminal_write_rolls_back_when_exact_delivery_settlement_fails() { let state: (bool, bool) = conn .query_row( "SELECT EXISTS( - SELECT 1 FROM agent_org_runtime_inbox_delivery_resolutions + SELECT 1 FROM agent_org_execution_inbox_delivery_resolutions WHERE inbox_id=?1 ), EXISTS( - SELECT 1 FROM agent_org_runtime_inbox_materializations + SELECT 1 FROM agent_org_execution_inbox_materializations WHERE inbox_id=?1 )", [delivery.bound_inbox_id], @@ -871,14 +871,14 @@ fn coordinator_task_mutations_advance_exact_context_and_materialize_one_terminal .query_row( "SELECT progress.work_revision,context.coordinator_work_revision, recheck.work_revision,recheck.status,recheck.inbox_id - FROM agent_org_runtime_runs run - JOIN agent_org_runtime_run_progress progress + FROM agent_org_execution_runs run + JOIN agent_org_execution_run_progress progress ON progress.org_run_id=run.id - JOIN agent_org_runtime_turn_contexts context + JOIN agent_org_execution_turn_contexts context ON context.org_run_id=run.id AND context.session_id=?2 AND context.turn_intent_id=?3 - JOIN agent_org_coordinator_completion_rechecks recheck + JOIN agent_org_execution_coordinator_completion_rechecks recheck ON recheck.org_run_id=run.id AND recheck.source_session_id=context.session_id AND recheck.source_turn_intent_id=context.turn_intent_id @@ -930,12 +930,12 @@ fn coordinator_task_mutations_advance_exact_context_and_materialize_one_terminal .query_row( "SELECT intent.status,recheck.status,recheck.work_revision, (SELECT COUNT(*) - FROM agent_org_runtime_formal_trigger_receipts trigger + FROM agent_org_execution_formal_trigger_receipts trigger WHERE trigger.org_run_id=?1 AND trigger.source_kind='coordinator_completion_recheck' AND trigger.source_turn_intent_id=?3) FROM session_turn_intents intent - JOIN agent_org_coordinator_completion_rechecks recheck + JOIN agent_org_execution_coordinator_completion_rechecks recheck ON recheck.source_session_id=intent.session_id AND recheck.source_turn_intent_id=intent.turn_intent_id WHERE intent.session_id=?2 AND intent.turn_intent_id=?3", @@ -1009,7 +1009,7 @@ fn restart_reconciliation_keeps_provenance_owner_and_settles_only_duplicate_sour ) .unwrap(); conn.execute( - "INSERT INTO agent_org_runtime_inbox_materializations( + "INSERT INTO agent_org_execution_inbox_materializations( inbox_id,session_id,transcript_message_id,transcript_intent_id,materialized_at ) VALUES (?1,?2,'duplicate-message','turn-duplicate-loser',?3)", params![source.id, MEMBER_A_SESSION, chrono::Utc::now().to_rfc3339()], @@ -1035,7 +1035,7 @@ fn restart_reconciliation_keeps_provenance_owner_and_settles_only_duplicate_sour .query_row( "SELECT intent.status,reconciliation.reason_code FROM session_turn_intents intent - JOIN agent_org_task_execution_reconciliations reconciliation + JOIN agent_org_execution_task_execution_reconciliations reconciliation ON reconciliation.session_id=intent.session_id AND reconciliation.turn_intent_id=intent.turn_intent_id WHERE intent.session_id=?1 @@ -1056,10 +1056,10 @@ fn restart_reconciliation_keeps_provenance_owner_and_settles_only_duplicate_sour .query_row( "SELECT resolution.reason, EXISTS( - SELECT 1 FROM agent_org_runtime_inbox_materializations materialization + SELECT 1 FROM agent_org_execution_inbox_materializations materialization WHERE materialization.inbox_id=resolution.inbox_id ) - FROM agent_org_runtime_inbox_delivery_resolutions resolution + FROM agent_org_execution_inbox_delivery_resolutions resolution WHERE resolution.inbox_id=?1", [source.id], |row| Ok((row.get(0)?, row.get(1)?)), @@ -1178,7 +1178,7 @@ fn idle_group_root_atomically_activates_formal_work_before_task_write() { let _fixture = fixture(); let conn = get_connection().expect("Task Store contract test database"); conn.execute( - "UPDATE agent_org_runtime_runs SET status='idle' WHERE id=?1", + "UPDATE agent_org_execution_runs SET status='idle' WHERE id=?1", [RUN_ID], ) .expect("Idle Team"); @@ -1217,8 +1217,8 @@ fn idle_group_root_atomically_activates_formal_work_before_task_write() { let (status, generation, context_generation): (String, i64, i64) = conn .query_row( "SELECT run.status,run.activation_generation,context.activation_generation - FROM agent_org_runtime_runs run - JOIN agent_org_runtime_turn_contexts context ON context.org_run_id=run.id + FROM agent_org_execution_runs run + JOIN agent_org_execution_turn_contexts context ON context.org_run_id=run.id WHERE run.id=?1 AND context.session_id=?2 AND context.turn_intent_id=?3", params![RUN_ID, ROOT_SESSION, GROUP_ROOT_TURN], |row| Ok((row.get(0)?, row.get(1)?, row.get(2)?)), @@ -1373,7 +1373,7 @@ fn current_generation_certificate_freezes_every_task_write_path() { let conn = get_connection().unwrap(); let now = chrono::Utc::now().to_rfc3339(); conn.execute( - "INSERT INTO agent_org_runtime_run_completion_certificates( + "INSERT INTO agent_org_execution_run_completion_certificates( id,org_run_id,activation_generation,work_revision,request_id,request_digest, outcome,summary,coordinator_session_id,coordinator_turn_intent_id, evidence_task_ids_json,closure_task_ids_json,task_output_refs_json, @@ -1452,7 +1452,7 @@ fn recovery_attempts(task_id: &str) -> i64 { get_connection() .unwrap() .query_row( - "SELECT attempts FROM agent_org_runtime_recovery_attempts + "SELECT attempts FROM agent_org_execution_recovery_attempts WHERE org_run_id=?1 AND action_kind='task_failure_recovery' AND target_key=?2", params![RUN_ID, task_id], @@ -1467,7 +1467,7 @@ fn recovery_event_count() -> i64 { get_connection() .unwrap() .query_row( - "SELECT COUNT(*) FROM agent_org_runtime_recovery_attempts + "SELECT COUNT(*) FROM agent_org_execution_recovery_attempts WHERE org_run_id=?1 AND action_kind='task_failure_recovery_event'", [RUN_ID], |row| row.get(0), @@ -1509,7 +1509,7 @@ fn canonical_schema_and_five_state_semantics_are_frozen() { let _fixture = fixture(); let conn = get_connection().unwrap(); let columns = conn - .prepare("PRAGMA table_info(agent_org_runtime_tasks)") + .prepare("PRAGMA table_info(agent_org_execution_tasks)") .unwrap() .query_map([], |row| row.get::<_, String>(1)) .unwrap() @@ -1603,7 +1603,7 @@ fn user_directed_graph_authority_is_denied_for_workers_allowed_for_writer_and_pa assert_eq!(written.source_turn_intent_id, "direct-writer-allowed"); conn.execute( - "UPDATE agent_org_runtime_runs SET status='paused' WHERE id=?1", + "UPDATE agent_org_execution_runs SET status='paused' WHERE id=?1", [RUN_ID], ) .expect("pause Team"); @@ -1629,7 +1629,7 @@ fn idle_user_directed_writer_activates_team_and_task_atomically() { let conn = get_connection().expect("test sqlite connection"); grant_additional_writer(&conn, MEMBER_A); conn.execute( - "UPDATE agent_org_runtime_runs SET status='idle' WHERE id=?1", + "UPDATE agent_org_execution_runs SET status='idle' WHERE id=?1", [RUN_ID], ) .expect("idle Team"); @@ -1656,9 +1656,9 @@ fn idle_user_directed_writer_activates_team_and_task_atomically() { let (status, generation, task_count): (String, i64, i64) = conn .query_row( "SELECT run.status,run.activation_generation, - (SELECT COUNT(*) FROM agent_org_runtime_tasks task + (SELECT COUNT(*) FROM agent_org_execution_tasks task WHERE task.org_run_id=run.id AND task.id='direct-idle-activation') - FROM agent_org_runtime_runs run WHERE run.id=?1", + FROM agent_org_execution_runs run WHERE run.id=?1", [RUN_ID], |row| Ok((row.get(0)?, row.get(1)?, row.get(2)?)), ) @@ -1854,7 +1854,7 @@ fn repeated_owner_start_acknowledges_the_running_task_without_a_second_event() { assert!(first.status_changed); let event_count_before: i64 = conn .query_row( - "SELECT COUNT(*) FROM agent_org_runtime_task_events + "SELECT COUNT(*) FROM agent_org_execution_task_events WHERE org_run_id=?1 AND task_id=?2", rusqlite::params![RUN_ID, "idempotent-start"], |row| row.get(0), @@ -1862,7 +1862,7 @@ fn repeated_owner_start_acknowledges_the_running_task_without_a_second_event() { .unwrap(); let work_revision_before: i64 = conn .query_row( - "SELECT work_revision FROM agent_org_runtime_run_progress + "SELECT work_revision FROM agent_org_execution_run_progress WHERE org_run_id=?1", [RUN_ID], |row| row.get(0), @@ -1878,7 +1878,7 @@ fn repeated_owner_start_acknowledges_the_running_task_without_a_second_event() { assert_eq!(acknowledged.current.status, TaskStatus::InProgress); let event_count_after: i64 = conn .query_row( - "SELECT COUNT(*) FROM agent_org_runtime_task_events + "SELECT COUNT(*) FROM agent_org_execution_task_events WHERE org_run_id=?1 AND task_id=?2", rusqlite::params![RUN_ID, "idempotent-start"], |row| row.get(0), @@ -1886,7 +1886,7 @@ fn repeated_owner_start_acknowledges_the_running_task_without_a_second_event() { .unwrap(); let work_revision_after: i64 = conn .query_row( - "SELECT work_revision FROM agent_org_runtime_run_progress + "SELECT work_revision FROM agent_org_execution_run_progress WHERE org_run_id=?1", [RUN_ID], |row| row.get(0), @@ -2307,7 +2307,7 @@ fn run_view_cancel_records_user_scope_removal_with_exact_request_audit() { let receipt_audit: (String, String, String, String) = conn .query_row( "SELECT target_task_id,root_user_event_id,request_id,status - FROM agent_org_scope_removal_receipts + FROM agent_org_execution_scope_removal_receipts WHERE receipt_id=?1", [receipt_id], |row| Ok((row.get(0)?, row.get(1)?, row.get(2)?, row.get(3)?)), @@ -2368,7 +2368,7 @@ fn run_view_cancel_records_user_scope_removal_with_exact_request_audit() { ] { let resolution_count: i64 = conn .query_row( - "SELECT COUNT(*) FROM agent_org_scope_resolution_receipts + "SELECT COUNT(*) FROM agent_org_execution_scope_resolution_receipts WHERE root_receipt_id=?1 AND resolution_kind=?2", params![receipt_id, kind], |row| row.get(0), @@ -2379,7 +2379,7 @@ fn run_view_cancel_records_user_scope_removal_with_exact_request_audit() { let audit_exists: bool = conn .query_row( "SELECT EXISTS( - SELECT 1 FROM agent_org_runtime_task_events + SELECT 1 FROM agent_org_execution_task_events WHERE org_run_id=?1 AND task_id='user-cancelled' AND next_status='cancelled' AND actor_kind='system' AND actor_member_id='user:task_handoff:ui-cancel-request-1' @@ -2489,7 +2489,7 @@ fn stale_generation_and_wrong_turn_binding_fail_without_partial_write() { 1, ); conn.execute( - "UPDATE agent_org_runtime_runs SET activation_generation=2 WHERE id=?1", + "UPDATE agent_org_execution_runs SET activation_generation=2 WHERE id=?1", [RUN_ID], ) .unwrap(); @@ -2628,7 +2628,7 @@ fn task_pages_keep_current_graph_order_and_show_recent_history_first() { let insert = |id: &str, status: &str, created_at: &str, updated_at: &str, output_json: Option<&str>| { conn.execute( - "INSERT INTO agent_org_runtime_tasks( + "INSERT INTO agent_org_execution_tasks( id,org_run_id,activation_generation,subject,description,owner,status,execution_mode, blocked_by_json,metadata_json,output_json, created_by_participant_id,source_turn_intent_id,created_at,updated_at @@ -2755,7 +2755,7 @@ fn ten_thousand_task_history_uses_bounded_keyset_pages() { { let mut insert = tx .prepare( - "INSERT INTO agent_org_runtime_tasks( + "INSERT INTO agent_org_execution_tasks( id,org_run_id,activation_generation,subject,description,owner,status,execution_mode, blocked_by_json,metadata_json,output_json, created_by_participant_id,source_turn_intent_id,created_at,updated_at @@ -2865,7 +2865,7 @@ fn ten_thousand_task_history_uses_bounded_keyset_pages() { }) .to_string(); conn.execute( - "UPDATE agent_org_runtime_tasks + "UPDATE agent_org_execution_tasks SET output_json=?1, updated_at=?2 WHERE org_run_id=?3 AND id=?4", params![ @@ -2896,7 +2896,7 @@ fn ten_thousand_task_history_uses_bounded_keyset_pages() { let plan = conn .prepare( "EXPLAIN QUERY PLAN - SELECT id FROM agent_org_runtime_tasks + SELECT id FROM agent_org_execution_tasks WHERE org_run_id=?1 AND status='completed' AND (updated_at CreateTaskParams { let conn = get_connection().expect("task test database"); let now = chrono::Utc::now().to_rfc3339(); conn.execute( - "INSERT OR IGNORE INTO agent_org_runtime_runs + "INSERT OR IGNORE INTO agent_org_execution_runs (id, org_id, coordinator_agent_id, entry_mode, status, created_at, updated_at) VALUES (?1, 'task-test-org', 'task-test-coordinator', 'standalone_session', 'running', ?2, ?2)", rusqlite::params![org_run_id, now], @@ -48,7 +48,7 @@ fn make_params(org_run_id: &str, id: &str, subject: &str) -> CreateTaskParams { }) .to_string(); conn.execute( - "UPDATE agent_org_runtime_runs + "UPDATE agent_org_execution_runs SET activation_generation=1, org_snapshot_json=COALESCE(org_snapshot_json,?2) WHERE id=?1", @@ -172,7 +172,7 @@ fn task_mutations_require_running_parent_run() { crate::coordination::agent_org_runs::init_schema(&conn).expect("run schema"); let now = chrono::Utc::now().to_rfc3339(); conn.execute( - "INSERT INTO agent_org_runtime_runs + "INSERT INTO agent_org_execution_runs (id, org_id, coordinator_agent_id, entry_mode, status, created_at, updated_at) VALUES ('guarded-run', 'org', 'coord', 'standalone_session', 'paused', ?1, ?1)", rusqlite::params![now], @@ -189,7 +189,7 @@ fn task_mutations_require_running_parent_run() { assert!(create_error.contains("agent_org_run_not_mutable")); conn.execute( - "UPDATE agent_org_runtime_runs SET status='running' WHERE id='guarded-run'", + "UPDATE agent_org_execution_runs SET status='running' WHERE id='guarded-run'", [], ) .unwrap(); @@ -201,7 +201,7 @@ fn task_mutations_require_running_parent_run() { )) .expect("running run permits create"); conn.execute( - "UPDATE agent_org_runtime_runs + "UPDATE agent_org_execution_runs SET status='archived',activation_generation=activation_generation+1, archived_at=?1,archive_receipt_id='guarded-run-archive-receipt' WHERE id='guarded-run'", @@ -439,7 +439,7 @@ fn delete_rejects_task_used_as_an_inbox_delivery_replacement() { let conn = get_connection().expect("test sqlite connection"); let now = chrono::Utc::now().to_rfc3339(); conn.execute( - "INSERT INTO agent_org_runtime_inbox ( + "INSERT INTO agent_org_execution_inbox ( recipient_agent_id, sender_agent_id, org_run_id, payload_kind, payload_json, created_at ) VALUES ( @@ -451,7 +451,7 @@ fn delete_rejects_task_used_as_an_inbox_delivery_replacement() { .expect("seed source inbox evidence"); let inbox_id = conn.last_insert_rowid(); conn.execute( - "INSERT INTO agent_org_runtime_inbox_delivery_resolutions ( + "INSERT INTO agent_org_execution_inbox_delivery_resolutions ( inbox_id, org_run_id, resolution_kind, resolved_by_member_id, reason, replacement_task_id, created_at ) VALUES (?1, ?2, 'superseded', 'coordinator', 'Moved to task', @@ -480,14 +480,14 @@ fn delete_fails_closed_when_delivery_resolution_schema_is_missing() { .expect("create guarded task"); let conn = get_connection().expect("test sqlite connection"); conn.execute( - "DROP TABLE agent_org_runtime_inbox_delivery_resolutions", + "DROP TABLE agent_org_execution_inbox_delivery_resolutions", [], ) .expect("simulate damaged delivery-resolution schema"); let error = AgentOrgTaskStore::delete(&run_id, "schema-guarded-task") .expect_err("schema failure must not be treated as an unreferenced task"); - assert!(error.contains("agent_org_runtime_inbox_delivery_resolutions")); + assert!(error.contains("agent_org_execution_inbox_delivery_resolutions")); assert!(AgentOrgTaskStore::get(&run_id, "schema-guarded-task") .expect("reload guarded task") .is_some()); @@ -569,7 +569,7 @@ fn corrupt_predicate_flags_ownerless_in_progress_and_spaced_eligibility() { conn.execute_batch("PRAGMA ignore_check_constraints=ON;") .expect("allow corruption fixture"); conn.execute( - "INSERT INTO agent_org_runtime_tasks + "INSERT INTO agent_org_execution_tasks (id, org_run_id, activation_generation, subject, description, active_form, owner, status, execution_mode, blocked_by_json, metadata_json, created_by_participant_id, source_turn_intent_id, created_at, updated_at) @@ -583,7 +583,7 @@ fn corrupt_predicate_flags_ownerless_in_progress_and_spaced_eligibility() { ) .expect("seed ownerless in-progress row"); conn.execute( - "INSERT INTO agent_org_runtime_tasks + "INSERT INTO agent_org_execution_tasks (id, org_run_id, activation_generation, subject, description, active_form, owner, status, execution_mode, blocked_by_json, metadata_json, created_by_participant_id, source_turn_intent_id, created_at, updated_at) @@ -604,7 +604,7 @@ fn corrupt_predicate_flags_ownerless_in_progress_and_spaced_eligibility() { let corrupt_count: i64 = conn .query_row( &format!( - "SELECT COUNT(*) FROM agent_org_runtime_tasks WHERE org_run_id=?1 AND {predicate}" + "SELECT COUNT(*) FROM agent_org_execution_tasks WHERE org_run_id=?1 AND {predicate}" ), rusqlite::params![&run_id], |row| row.get(0), @@ -624,7 +624,7 @@ fn summary_filtered_total_matches_rows_after_scalar_corruption_filtering() { let oversized_id = "x".repeat(crate::coordination::agent_org_payload_limits::TASK_IDENTIFIER_MAX_CHARS + 1); conn.execute( - "INSERT INTO agent_org_runtime_tasks + "INSERT INTO agent_org_execution_tasks (id, org_run_id, activation_generation, subject, description, active_form, owner, status, execution_mode, blocked_by_json, metadata_json, created_by_participant_id, source_turn_intent_id, created_at, updated_at) @@ -735,7 +735,7 @@ fn store_rejects_malformed_reserved_dispatch_metadata() { let conn = get_connection().expect("task database"); let now = chrono::Utc::now().to_rfc3339(); conn.execute( - "INSERT INTO agent_org_runtime_tasks + "INSERT INTO agent_org_execution_tasks (id, org_run_id, activation_generation, subject, description, active_form, owner, status, execution_mode, blocked_by_json, metadata_json, output_json, created_by_participant_id, source_turn_intent_id, created_at, updated_at) @@ -754,7 +754,7 @@ fn store_rejects_malformed_reserved_dispatch_metadata() { let classified: bool = conn .query_row( &format!( - "SELECT {predicate} FROM agent_org_runtime_tasks + "SELECT {predicate} FROM agent_org_execution_tasks WHERE org_run_id=?1 AND id='historical-output-producer'" ), rusqlite::params![&run_id], @@ -777,7 +777,7 @@ fn store_rejects_malformed_reserved_dispatch_metadata() { }, }); conn.execute( - "INSERT INTO agent_org_runtime_tasks + "INSERT INTO agent_org_execution_tasks (id, org_run_id, activation_generation, subject, description, active_form, owner, status, execution_mode, blocked_by_json, metadata_json, output_json, created_by_participant_id, source_turn_intent_id, created_at, updated_at) @@ -795,7 +795,7 @@ fn store_rejects_malformed_reserved_dispatch_metadata() { let classified: bool = conn .query_row( &format!( - "SELECT {predicate} FROM agent_org_runtime_tasks + "SELECT {predicate} FROM agent_org_execution_tasks WHERE org_run_id=?1 AND id='historical-output-zone'" ), rusqlite::params![&run_id], diff --git a/src-tauri/crates/agent-core/src/core/coordination/agent_org_tool_receipts.rs b/src-tauri/crates/agent-core/src/core/coordination/agent_org_tool_receipts.rs index 815bb9daba..d307c333f2 100644 --- a/src-tauri/crates/agent-core/src/core/coordination/agent_org_tool_receipts.rs +++ b/src-tauri/crates/agent-core/src/core/coordination/agent_org_tool_receipts.rs @@ -16,7 +16,7 @@ use crate::coordination::agent_org_payload_limits::{ }; use crate::tools::traits::{CallContext, ToolError}; -pub(super) const TABLE_NAME: &str = "agent_org_runtime_tool_call_receipts"; +pub(super) const TABLE_NAME: &str = "agent_org_execution_tool_call_receipts"; const TOOL_NAME_MAX_BYTES: usize = 128; const OPERATION_MAX_BYTES: usize = 128; @@ -40,7 +40,7 @@ pub(super) fn create_schema(conn: &Connection) -> rusqlite::Result<()> { created_at TEXT NOT NULL, PRIMARY KEY (org_run_id, session_id, turn_intent_id, call_id), FOREIGN KEY (org_run_id) - REFERENCES agent_org_runtime_runs(id) ON DELETE CASCADE, + REFERENCES agent_org_execution_runs(id) ON DELETE CASCADE, CHECK (trim(org_run_id) <> '' AND org_run_id = trim(org_run_id)), CHECK (trim(session_id) <> '' AND session_id = trim(session_id)), CHECK (trim(turn_intent_id) <> '' AND turn_intent_id = trim(turn_intent_id)), @@ -388,7 +388,7 @@ mod tests { .expect("shared Turn fixture schema"); init_agent_org_schemas(&conn).expect("Agent Org schema"); conn.execute( - "INSERT INTO agent_org_runtime_runs ( + "INSERT INTO agent_org_execution_runs ( id,org_id,coordinator_agent_id,entry_mode,status,created_at,updated_at ) VALUES ('run-a','org-a','agent-a','standalone_session','running',?1,?1)", [chrono::Utc::now().to_rfc3339()], @@ -605,7 +605,7 @@ mod tests { |_| Ok(Ok("created".to_string())), ) .expect("receipt"); - conn.execute("DELETE FROM agent_org_runtime_runs WHERE id='run-a'", []) + conn.execute("DELETE FROM agent_org_execution_runs WHERE id='run-a'", []) .expect("delete Team"); let count: i64 = conn .query_row(&format!("SELECT COUNT(*) FROM {TABLE_NAME}"), [], |row| { diff --git a/src-tauri/crates/agent-core/src/core/coordination/agent_org_turn_contexts.rs b/src-tauri/crates/agent-core/src/core/coordination/agent_org_turn_contexts.rs index 88179dc05c..488c694826 100644 --- a/src-tauri/crates/agent-core/src/core/coordination/agent_org_turn_contexts.rs +++ b/src-tauri/crates/agent-core/src/core/coordination/agent_org_turn_contexts.rs @@ -20,7 +20,7 @@ const TASK_WAKE_CANDIDATE_LIMIT: i64 = const TASK_ASSISTANT_PERSISTENCE_TARGET_SQL: &str = "SELECT task.status, EXISTS( SELECT 1 - FROM agent_org_runtime_task_events event + FROM agent_org_execution_task_events event WHERE event.org_run_id=task.org_run_id AND event.task_id=task.id AND event.previous_owner=?3 @@ -33,12 +33,12 @@ const TASK_ASSISTANT_PERSISTENCE_TARGET_SQL: &str = "SELECT task.status, AND event.created_at=task.updated_at AND event.rowid=( SELECT MAX(latest.rowid) - FROM agent_org_runtime_task_events latest + FROM agent_org_execution_task_events latest WHERE latest.org_run_id=task.org_run_id AND latest.task_id=task.id ) ) - FROM agent_org_runtime_tasks task + FROM agent_org_execution_tasks task WHERE task.org_run_id=?1 AND task.id=?2 AND task.owner=?3"; pub(crate) const TURN_CONTEXT_INVARIANT_PREFIX: &str = "agent_org_turn_context_invalid:"; @@ -414,15 +414,15 @@ impl AgentOrgTurnAdmission { pub(super) fn create_schema(conn: &Connection) -> rusqlite::Result<()> { conn.execute_batch( - "CREATE TABLE IF NOT EXISTS agent_org_runtime_member_dispatch_allocators ( + "CREATE TABLE IF NOT EXISTS agent_org_execution_member_dispatch_allocators ( org_run_id TEXT NOT NULL, member_id TEXT NOT NULL CHECK(length(trim(member_id)) > 0), next_sequence INTEGER NOT NULL CHECK(next_sequence >= 1), PRIMARY KEY(org_run_id, member_id), - FOREIGN KEY(org_run_id) REFERENCES agent_org_runtime_runs(id) ON DELETE CASCADE + FOREIGN KEY(org_run_id) REFERENCES agent_org_execution_runs(id) ON DELETE CASCADE ); - CREATE TABLE IF NOT EXISTS agent_org_runtime_turn_contexts ( + CREATE TABLE IF NOT EXISTS agent_org_execution_turn_contexts ( context_id INTEGER PRIMARY KEY AUTOINCREMENT, session_id TEXT NOT NULL CHECK(length(trim(session_id)) > 0), turn_intent_id TEXT NOT NULL CHECK(length(trim(turn_intent_id)) > 0), @@ -453,7 +453,7 @@ pub(super) fn create_schema(conn: &Connection) -> rusqlite::Result<()> { REFERENCES session_turn_intents(session_id, turn_intent_id) ON DELETE CASCADE, FOREIGN KEY(org_run_id) - REFERENCES agent_org_runtime_runs(id) ON DELETE CASCADE, + REFERENCES agent_org_execution_runs(id) ON DELETE CASCADE, CHECK( (turn_kind='coordinator' AND participant_id='coordinator' @@ -508,20 +508,20 @@ pub(super) fn create_schema(conn: &Connection) -> rusqlite::Result<()> { )) ) ); - CREATE UNIQUE INDEX IF NOT EXISTS idx_agent_org_runtime_turn_contexts_member_sequence - ON agent_org_runtime_turn_contexts( + CREATE UNIQUE INDEX IF NOT EXISTS idx_agent_org_execution_turn_contexts_member_sequence + ON agent_org_execution_turn_contexts( org_run_id, dispatch_member_id, member_dispatch_sequence ) WHERE dispatch_member_id IS NOT NULL; - CREATE INDEX IF NOT EXISTS idx_agent_org_runtime_turn_contexts_source - ON agent_org_runtime_turn_contexts( + CREATE INDEX IF NOT EXISTS idx_agent_org_execution_turn_contexts_source + ON agent_org_execution_turn_contexts( org_run_id, source_kind, source_id, context_id ); - CREATE INDEX IF NOT EXISTS idx_agent_org_runtime_turn_contexts_group_root_session - ON agent_org_runtime_turn_contexts(session_id, context_id, source_id) + CREATE INDEX IF NOT EXISTS idx_agent_org_execution_turn_contexts_group_root_session + ON agent_org_execution_turn_contexts(session_id, context_id, source_id) WHERE source_kind='group_root'; - CREATE INDEX IF NOT EXISTS idx_agent_org_runtime_turn_contexts_public_timeline - ON agent_org_runtime_turn_contexts(org_run_id, created_at, context_id) + CREATE INDEX IF NOT EXISTS idx_agent_org_execution_turn_contexts_public_timeline + ON agent_org_execution_turn_contexts(org_run_id, created_at, context_id) WHERE source_kind IN ('group_root','group_mention');", ) } @@ -540,7 +540,7 @@ pub(crate) fn member_dispatch_is_fifo_head_with_connection( conn.query_row( "SELECT NOT EXISTS( SELECT 1 - FROM agent_org_runtime_turn_contexts earlier + FROM agent_org_execution_turn_contexts earlier JOIN session_turn_intents intent ON intent.session_id=earlier.session_id AND intent.turn_intent_id=earlier.turn_intent_id @@ -658,11 +658,11 @@ fn has_live_pause_continuation( conn.query_row( "SELECT EXISTS( SELECT 1 - FROM agent_org_runtime_pause_handoffs handoff - JOIN agent_org_runtime_pause_episodes episode + FROM agent_org_execution_pause_handoffs handoff + JOIN agent_org_execution_pause_episodes episode ON episode.episode_id=handoff.episode_id - JOIN agent_org_runtime_runs run ON run.id=handoff.org_run_id - JOIN agent_org_runtime_turn_contexts context + JOIN agent_org_execution_runs run ON run.id=handoff.org_run_id + JOIN agent_org_execution_turn_contexts context ON context.session_id=handoff.session_id AND context.turn_intent_id=handoff.continuation_turn_intent_id JOIN session_turn_intents intent @@ -689,6 +689,7 @@ pub(crate) fn revalidate_context_with_connection( session_id: &str, turn_intent_id: &str, ) -> Result { + super::agent_org_history_store::require_writable(conn, session_id)?; let context = revalidate_live_context_with_connection(conn, session_id, turn_intent_id)?; if context.turn_kind == AgentOrgTurnKind::TaskExecution { let task_id = context @@ -712,6 +713,7 @@ pub(crate) fn revalidate_assistant_persistence_with_connection( session_id: &str, turn_intent_id: &str, ) -> Result { + super::agent_org_history_store::require_writable(conn, session_id)?; let context = revalidate_live_context_with_connection(conn, session_id, turn_intent_id)?; validate_assistant_persistence_base_turn(conn, &context)?; if context.turn_kind == AgentOrgTurnKind::TaskExecution { @@ -739,7 +741,7 @@ fn revalidate_live_context_with_connection( let run: Option<(Option, Option, i64, String)> = conn .query_row( "SELECT root_session_id, org_snapshot_json, activation_generation, status - FROM agent_org_runtime_runs WHERE id=?1", + FROM agent_org_execution_runs WHERE id=?1", [&context.org_run_id], |row| Ok((row.get(0)?, row.get(1)?, row.get(2)?, row.get(3)?)), ) @@ -848,8 +850,8 @@ fn revalidate_live_context_with_connection( .query_row( "SELECT EXISTS( SELECT 1 - FROM agent_org_runtime_user_directed_coordinator_bindings binding - JOIN agent_org_runtime_inbox inbox ON inbox.id=binding.source_inbox_id + FROM agent_org_execution_user_directed_coordinator_bindings binding + JOIN agent_org_execution_inbox inbox ON inbox.id=binding.source_inbox_id WHERE binding.org_run_id=?1 AND binding.session_id=?2 AND binding.turn_intent_id=?3 @@ -945,7 +947,7 @@ fn revalidate_live_context_with_connection( AgentOrgTurnSourceKind::GroupMention | AgentOrgTurnSourceKind::MemberInbox => conn .query_row( "SELECT EXISTS( - SELECT 1 FROM agent_org_runtime_inbox + SELECT 1 FROM agent_org_execution_inbox WHERE id=CAST(?1 AS INTEGER) AND org_run_id=?2 AND recipient_member_id=?3 AND delivery_class='user_directed' @@ -966,7 +968,7 @@ fn revalidate_live_context_with_connection( .query_row( "SELECT EXISTS( SELECT 1 - FROM agent_org_runtime_user_directed_deliveries delivery + FROM agent_org_execution_user_directed_deliveries delivery WHERE delivery.org_run_id=?1 AND delivery.session_id=?2 AND delivery.turn_intent_id=?3 @@ -1102,7 +1104,7 @@ pub(crate) fn unique_running_task_execution_turn_for_recovery( let mut statement = conn .prepare( "SELECT context.turn_intent_id - FROM agent_org_runtime_turn_contexts context + FROM agent_org_execution_turn_contexts context JOIN session_turn_intents base ON base.session_id=context.session_id AND base.turn_intent_id=context.turn_intent_id @@ -1152,7 +1154,7 @@ fn resolve_next_task_wake_binding( ) -> Result, String> { let generation: Option = conn .query_row( - "SELECT activation_generation FROM agent_org_runtime_runs + "SELECT activation_generation FROM agent_org_execution_runs WHERE id=?1 AND status='running'", [org_run_id], |row| row.get(0), @@ -1166,21 +1168,21 @@ fn resolve_next_task_wake_binding( let mut statement = conn .prepare( "SELECT id, payload_kind, payload_json - FROM agent_org_runtime_inbox + FROM agent_org_execution_inbox WHERE org_run_id=?1 AND recipient_member_id=?2 AND delivery_class='formal_work' AND read_at IS NULL AND payload_kind IN ('task_assigned','plan_approval_response') AND NOT EXISTS ( - SELECT 1 FROM agent_org_task_execution_leases lease + SELECT 1 FROM agent_org_execution_task_execution_leases lease JOIN session_turn_intents intent USING(session_id,turn_intent_id) - WHERE lease.continuation_receipt_id='inbox:' || agent_org_runtime_inbox.id + WHERE lease.continuation_receipt_id='inbox:' || agent_org_execution_inbox.id AND intent.status NOT IN ('queued','running','optimistic') ) AND NOT EXISTS ( - SELECT 1 FROM agent_org_runtime_inbox_delivery_resolutions resolution - WHERE resolution.inbox_id=agent_org_runtime_inbox.id + SELECT 1 FROM agent_org_execution_inbox_delivery_resolutions resolution + WHERE resolution.inbox_id=agent_org_execution_inbox.id ) ORDER BY id ASC LIMIT ?3", @@ -1313,13 +1315,13 @@ fn task_is_pending_and_ready( } conn.query_row( "SELECT EXISTS( - SELECT 1 FROM agent_org_runtime_tasks task + SELECT 1 FROM agent_org_execution_tasks task WHERE task.org_run_id=?1 AND task.id=?2 AND task.owner=?3 AND task.status='pending' AND NOT EXISTS ( SELECT 1 FROM json_each(task.blocked_by_json) edge - LEFT JOIN agent_org_runtime_tasks blocker + LEFT JOIN agent_org_execution_tasks blocker ON blocker.org_run_id=task.org_run_id AND blocker.id=CAST(edge.value AS TEXT) WHERE edge.type<>'text' @@ -1342,13 +1344,13 @@ fn planning_revision_task( ) -> Result, String> { conn.query_row( "SELECT revision.source_task_id - FROM agent_org_runtime_plan_revisions revision - JOIN agent_org_runtime_plan_decisions decision + FROM agent_org_execution_plan_revisions revision + JOIN agent_org_execution_plan_decisions decision ON decision.plan_revision_id=revision.plan_revision_id - JOIN agent_org_runtime_tasks task + JOIN agent_org_execution_tasks task ON task.org_run_id=revision.org_run_id AND task.id=revision.source_task_id - JOIN agent_org_runtime_turn_contexts source_context + JOIN agent_org_execution_turn_contexts source_context ON source_context.session_id=revision.source_session_id AND source_context.turn_intent_id=revision.source_turn_intent_id AND source_context.org_run_id=revision.org_run_id @@ -1379,7 +1381,7 @@ fn validate_task_execution_target( ) -> Result<(), String> { let target: Option = conn .query_row( - "SELECT status FROM agent_org_runtime_tasks + "SELECT status FROM agent_org_execution_tasks WHERE org_run_id=?1 AND id=?2 AND owner=?3", params![org_run_id, task_id, owner_member_id], |row| row.get(0), @@ -1471,6 +1473,7 @@ pub(crate) fn accept_with_connection( conn: &Connection, request: &AgentOrgTurnAdmission, ) -> Result { + super::agent_org_history_store::require_writable(conn, &request.session_id)?; validate_non_empty(request)?; let base = read_base(conn, &request.session_id, &request.turn_intent_id)?; @@ -1532,7 +1535,7 @@ pub(crate) fn accept_with_connection( let now = chrono::Utc::now().to_rfc3339(); conn.execute( - "INSERT INTO agent_org_runtime_turn_contexts ( + "INSERT INTO agent_org_execution_turn_contexts ( session_id, turn_intent_id, org_run_id, participant_id, turn_kind, task_id, owner_member_id, dispatch_member_id, member_dispatch_sequence, source_kind, source_id, root_authority_turn_id, actor_version, @@ -1650,7 +1653,7 @@ fn resolve_canonical_admission( let run: Option<(Option, Option, i64, String)> = conn .query_row( "SELECT root_session_id, org_snapshot_json, activation_generation, status - FROM agent_org_runtime_runs WHERE id=?1", + FROM agent_org_execution_runs WHERE id=?1", [&request.org_run_id], |row| Ok((row.get(0)?, row.get(1)?, row.get(2)?, row.get(3)?)), ) @@ -1807,7 +1810,7 @@ fn resolve_canonical_admission( resolve_materialization_version(conn, request, owner_member_id, agent_id)?; let task_owner: Option> = conn .query_row( - "SELECT owner FROM agent_org_runtime_tasks + "SELECT owner FROM agent_org_execution_tasks WHERE org_run_id=?1 AND id=?2", params![&request.org_run_id, task_id], |row| row.get(0), @@ -1978,7 +1981,7 @@ fn resolve_materialization_version( let version: Option = conn .query_row( "SELECT materialization.generation - FROM agent_org_runtime_member_materializations materialization + FROM agent_org_execution_member_materializations materialization JOIN agent_sessions session ON session.session_id=materialization.session_id WHERE materialization.org_run_id=?1 @@ -1990,7 +1993,7 @@ fn resolve_materialization_version( AND session.org_member_id=?2 AND materialization.generation=( SELECT MAX(latest.generation) - FROM agent_org_runtime_member_materializations latest + FROM agent_org_execution_member_materializations latest WHERE latest.org_run_id=?1 AND latest.member_id=?2 AND latest.status='succeeded' @@ -2023,7 +2026,7 @@ fn resolve_materialization_version_for_context( let version: Option = conn .query_row( "SELECT materialization.generation - FROM agent_org_runtime_member_materializations materialization + FROM agent_org_execution_member_materializations materialization JOIN agent_sessions session ON session.session_id=materialization.session_id WHERE materialization.org_run_id=?1 @@ -2035,7 +2038,7 @@ fn resolve_materialization_version_for_context( AND session.org_member_id=?2 AND materialization.generation=( SELECT MAX(latest.generation) - FROM agent_org_runtime_member_materializations latest + FROM agent_org_execution_member_materializations latest WHERE latest.org_run_id=?1 AND latest.member_id=?2 AND latest.status='succeeded' @@ -2080,7 +2083,7 @@ fn validate_source_inbox( let valid: bool = conn .query_row( "SELECT EXISTS( - SELECT 1 FROM agent_org_runtime_inbox + SELECT 1 FROM agent_org_execution_inbox WHERE id=?1 AND org_run_id=?2 AND recipient_member_id=?3 AND delivery_class='user_directed' )", @@ -2102,7 +2105,7 @@ fn allocate_member_sequence( member_id: &str, ) -> Result { conn.query_row( - "INSERT INTO agent_org_runtime_member_dispatch_allocators ( + "INSERT INTO agent_org_execution_member_dispatch_allocators ( org_run_id, member_id, next_sequence ) VALUES (?1, ?2, 2) ON CONFLICT(org_run_id, member_id) DO UPDATE @@ -2367,7 +2370,7 @@ fn coordinator_wait_gate( let has_completion_certificate: bool = tx .query_row( "SELECT EXISTS( - SELECT 1 FROM agent_org_runtime_run_completion_certificates + SELECT 1 FROM agent_org_execution_run_completion_certificates WHERE org_run_id=?1 AND coordinator_session_id=?2 AND coordinator_turn_intent_id=?3 @@ -2383,7 +2386,7 @@ fn coordinator_wait_gate( let work_revision: i64 = tx .query_row( "SELECT work_revision - FROM agent_org_runtime_run_progress WHERE org_run_id=?1", + FROM agent_org_execution_run_progress WHERE org_run_id=?1", [org_run_id], |row| row.get(0), ) @@ -2391,7 +2394,7 @@ fn coordinator_wait_gate( let newer_formal_fact: bool = tx .query_row( "SELECT EXISTS( - SELECT 1 FROM agent_org_runtime_formal_trigger_receipts + SELECT 1 FROM agent_org_execution_formal_trigger_receipts WHERE org_run_id=?1 AND status='pending' )", [org_run_id], @@ -2410,20 +2413,20 @@ fn coordinator_wait_gate( .query_row( "SELECT EXISTS( SELECT 1 - FROM agent_org_runtime_runs run - JOIN agent_org_runtime_initial_inputs initial + FROM agent_org_execution_runs run + JOIN agent_org_execution_initial_inputs initial ON initial.org_run_id=run.id WHERE run.id=?1 AND run.root_session_id=?2 AND run.has_initial_work=1 AND initial.turn_intent_id=?3 AND NOT EXISTS ( - SELECT 1 FROM agent_org_runtime_tasks task + SELECT 1 FROM agent_org_execution_tasks task WHERE task.org_run_id=run.id ) AND NOT EXISTS ( SELECT 1 - FROM agent_org_runtime_run_completion_certificates certificate + FROM agent_org_execution_run_completion_certificates certificate WHERE certificate.org_run_id=run.id ) )", @@ -2437,7 +2440,7 @@ fn coordinator_wait_gate( } let updated = tx .execute( - "UPDATE agent_org_runtime_turn_contexts + "UPDATE agent_org_execution_turn_contexts SET terminal_reason='waiting_for_org_event' WHERE org_run_id=?1 AND session_id=?2 AND turn_intent_id=?3 AND turn_kind='coordinator' @@ -2495,7 +2498,7 @@ pub(crate) fn claim_coordinator_task_observation( let work_revision: i64 = tx .query_row( "SELECT work_revision - FROM agent_org_runtime_run_progress WHERE org_run_id=?1", + FROM agent_org_execution_run_progress WHERE org_run_id=?1", [org_run_id], |row| row.get(0), ) @@ -2503,7 +2506,7 @@ pub(crate) fn claim_coordinator_task_observation( let newer_formal_fact: bool = tx .query_row( "SELECT EXISTS( - SELECT 1 FROM agent_org_runtime_formal_trigger_receipts + SELECT 1 FROM agent_org_execution_formal_trigger_receipts WHERE org_run_id=?1 AND status='pending' )", [org_run_id], @@ -2522,7 +2525,7 @@ pub(crate) fn claim_coordinator_task_observation( .any(|observed| observed == task_id) { tx.execute( - "UPDATE agent_org_runtime_turn_contexts + "UPDATE agent_org_execution_turn_contexts SET terminal_reason='waiting_for_org_event' WHERE context_id=?1 AND terminal_reason IS NULL", [context.context_id], @@ -2540,7 +2543,7 @@ pub(crate) fn claim_coordinator_task_observation( observed.push(task_id.to_string()); let observed_json = serde_json::to_string(&observed).map_err(|error| error.to_string())?; tx.execute( - "UPDATE agent_org_runtime_turn_contexts + "UPDATE agent_org_execution_turn_contexts SET coordinator_observed_task_ids_json=?2 WHERE context_id=?1 AND terminal_reason IS NULL", params![context.context_id, observed_json], @@ -2599,7 +2602,7 @@ fn group_root_source_event_ids_for_session_with_connection( let mut stmt = conn .prepare_cached( "SELECT source_id - FROM agent_org_runtime_turn_contexts + FROM agent_org_execution_turn_contexts WHERE session_id=?1 AND source_kind='group_root' ORDER BY context_id ASC", ) @@ -2647,7 +2650,7 @@ pub(crate) fn validate_formal_turn_generation_with_connection( } let run: Option<(String, i64)> = conn .query_row( - "SELECT status,activation_generation FROM agent_org_runtime_runs WHERE id=?1", + "SELECT status,activation_generation FROM agent_org_execution_runs WHERE id=?1", [&context.org_run_id], |row| Ok((row.get(0)?, row.get(1)?)), ) @@ -2685,7 +2688,7 @@ fn read_context_optional( activation_generation, coordinator_work_revision, coordinator_observed_task_ids_json, terminal_reason, created_at - FROM agent_org_runtime_turn_contexts + FROM agent_org_execution_turn_contexts WHERE session_id=?1 AND turn_intent_id=?2", params![session_id, turn_intent_id], decode_context, @@ -2758,7 +2761,7 @@ pub fn reconcile_in_flight_after_restart(conn: &Connection) -> Result Result Result Result Result Result Result Result Result Result Result Result Result Result Result Result Result Result Connection { fn insert_task_assignment(conn: &Connection, task_id: &str) -> i64 { conn.execute( - "INSERT OR IGNORE INTO agent_org_runtime_work_episode_tasks ( + "INSERT OR IGNORE INTO agent_org_execution_work_episode_tasks ( org_run_id,work_episode_id,task_id,associated_at ) VALUES (?1,'episode-a',?2,'now')", params![RUN_ID, task_id], @@ -265,7 +265,7 @@ fn insert_task_assignment(conn: &Connection, task_id: &str) -> i64 { }; let payload = serde_json::to_string(&message).expect("serialize TaskAssigned"); conn.execute( - "INSERT INTO agent_org_runtime_inbox ( + "INSERT INTO agent_org_execution_inbox ( recipient_agent_id,org_run_id,recipient_member_id,sender_agent_id, sender_member_id,payload_kind,payload_json,created_at ) VALUES ('agent-member',?1,?2,'_system',NULL,'task_assigned',?3,'now')", @@ -285,7 +285,7 @@ fn insert_bound_coordinator_reply( text: "Continue and complete the current task.".into(), }; conn.execute( - "INSERT INTO agent_org_runtime_inbox ( + "INSERT INTO agent_org_execution_inbox ( recipient_agent_id,org_run_id,recipient_member_id,sender_agent_id, sender_member_id,payload_kind,payload_json,created_at ) VALUES ('agent-member',?1,?2,'agent-coordinator','coordinator','plain',?3,'now')", @@ -401,7 +401,7 @@ fn row_count(conn: &Connection, table: &str) -> i64 { fn seed_final_summary_receipt(conn: &Connection, status: &str) { conn.execute( - "INSERT INTO agent_org_runtime_run_completion_certificates ( + "INSERT INTO agent_org_execution_run_completion_certificates ( id,org_run_id,activation_generation,work_revision,request_id, request_digest,outcome,summary,coordinator_session_id, coordinator_turn_intent_id,evidence_task_ids_json, @@ -436,7 +436,7 @@ fn seed_final_summary_receipt(conn: &Connection, status: &str) { other => panic!("unsupported final summary fixture status: {other}"), }; conn.execute( - "INSERT INTO agent_org_runtime_final_summary_receipts ( + "INSERT INTO agent_org_execution_final_summary_receipts ( receipt_id,org_run_id,activation_generation,certificate_id, evidence_digest,attempt,status,coordinator_session_id, turn_intent_id,started_at,terminal_at,event_id,typed_error, @@ -499,7 +499,7 @@ fn final_summary_active_states_reject_every_new_user_admission_atomically() { ); } - assert_eq!(row_count(&conn, "agent_org_runtime_turn_contexts"), 0); + assert_eq!(row_count(&conn, "agent_org_execution_turn_contexts"), 0); assert_eq!(row_count(&conn, "session_turn_intents"), 0); } } @@ -520,7 +520,7 @@ fn user_admission_committed_before_finalizing_remains_idempotently_accepted() { let replay = accept_in_transaction(&mut conn, &request) .expect("the exact accepted Turn must remain replayable while finalizing"); assert_eq!(replay, accepted); - assert_eq!(row_count(&conn, "agent_org_runtime_turn_contexts"), 1); + assert_eq!(row_count(&conn, "agent_org_execution_turn_contexts"), 1); assert_eq!(row_count(&conn, "session_turn_intents"), 1); } @@ -600,7 +600,7 @@ fn coordinator_is_root_scoped_and_never_allocates_member_sequence() { assert_eq!(first.activation_generation, Some(1)); assert_eq!(first.member_dispatch_sequence, None); assert_eq!( - row_count(&conn, "agent_org_runtime_member_dispatch_allocators"), + row_count(&conn, "agent_org_execution_member_dispatch_allocators"), 0 ); @@ -675,7 +675,7 @@ fn group_root_is_typed_exact_replayable_and_never_allocates_member_authority() { .prepare( "EXPLAIN QUERY PLAN SELECT source_id - FROM agent_org_runtime_turn_contexts + FROM agent_org_execution_turn_contexts WHERE session_id=?1 AND source_kind='group_root' ORDER BY context_id ASC", ) @@ -685,18 +685,19 @@ fn group_root_is_typed_exact_replayable_and_never_allocates_member_authority() { }) .expect("explain GroupRoot visibility authority query"); assert!( - query_plan.iter().any(|detail| detail.contains( - "idx_agent_org_runtime_turn_contexts_group_root_session" - )), + query_plan + .iter() + .any(|detail| detail + .contains("idx_agent_org_execution_turn_contexts_group_root_session")), "unexpected query plan: {query_plan:?}" ); assert_eq!( - row_count(&conn, "agent_org_runtime_member_dispatch_allocators"), + row_count(&conn, "agent_org_execution_member_dispatch_allocators"), 0 ); conn.execute( - "UPDATE agent_org_runtime_turn_contexts + "UPDATE agent_org_execution_turn_contexts SET coordinator_work_revision=0, coordinator_observed_task_ids_json=json_array('task-a'), terminal_reason='waiting_for_org_event' @@ -726,7 +727,7 @@ fn group_root_is_typed_exact_replayable_and_never_allocates_member_authority() { assert!(error.contains("base Turn replay mismatch"), "{error}"); conn.execute( - "UPDATE agent_org_runtime_runs SET status='paused' WHERE id=?1", + "UPDATE agent_org_execution_runs SET status='paused' WHERE id=?1", [RUN_ID], ) .expect("pause Team"); @@ -749,7 +750,7 @@ fn group_root_is_typed_exact_replayable_and_never_allocates_member_authority() { fn idle_root_coordinator_turn_runs_and_persists_without_activating_team() { let mut conn = connection(); conn.execute( - "UPDATE agent_org_runtime_runs SET status='idle' WHERE id=?1", + "UPDATE agent_org_execution_runs SET status='idle' WHERE id=?1", [RUN_ID], ) .unwrap(); @@ -774,7 +775,7 @@ fn idle_root_coordinator_turn_runs_and_persists_without_activating_team() { .expect("Idle Root can persist its final assistant answer"); let status: String = conn .query_row( - "SELECT status FROM agent_org_runtime_runs WHERE id=?1", + "SELECT status FROM agent_org_execution_runs WHERE id=?1", [RUN_ID], |row| row.get(0), ) @@ -786,7 +787,7 @@ fn idle_root_coordinator_turn_runs_and_persists_without_activating_team() { fn member_wake_binds_oldest_dependency_ready_assignment_and_revalidates_at_start() { let mut conn = connection(); conn.execute_batch( - "INSERT INTO agent_org_runtime_tasks + "INSERT INTO agent_org_execution_tasks (org_run_id,id,owner,status,execution_mode,blocked_by_json) VALUES ('run-a','blocker','member-a','failed','build','[]'), @@ -820,7 +821,7 @@ fn member_wake_binds_oldest_dependency_ready_assignment_and_revalidates_at_start ); let still_unread: i64 = conn .query_row( - "SELECT COUNT(*) FROM agent_org_runtime_inbox + "SELECT COUNT(*) FROM agent_org_execution_inbox WHERE id IN (?1,?2) AND read_at IS NULL", params![blocked_inbox_id, ready_inbox_id], |row| row.get(0), @@ -832,7 +833,7 @@ fn member_wake_binds_oldest_dependency_ready_assignment_and_revalidates_at_start ); conn.execute( - "UPDATE agent_org_runtime_tasks SET owner='member-reassigned' + "UPDATE agent_org_execution_tasks SET owner='member-reassigned' WHERE org_run_id=?1 AND id='task-a'", [RUN_ID], ) @@ -848,7 +849,7 @@ fn coordinator_reply_resumes_the_same_in_progress_task_execution() { let original = accept_in_transaction(&mut conn, &task_request("turn-original-task")) .expect("accept original TaskExecution"); conn.execute( - "UPDATE agent_org_runtime_tasks SET status='in_progress' WHERE id='task-a'", + "UPDATE agent_org_execution_tasks SET status='in_progress' WHERE id='task-a'", [], ) .expect("start Task"); @@ -905,7 +906,7 @@ fn unbound_plain_message_cannot_resume_task_execution() { accept_in_transaction(&mut conn, &task_request("turn-original-task")) .expect("accept original TaskExecution"); conn.execute( - "UPDATE agent_org_runtime_tasks SET status='in_progress' WHERE id='task-a'", + "UPDATE agent_org_execution_tasks SET status='in_progress' WHERE id='task-a'", [], ) .expect("start Task"); @@ -915,7 +916,7 @@ fn unbound_plain_message_cannot_resume_task_execution() { }) .expect("serialize peer chat"); conn.execute( - "INSERT INTO agent_org_runtime_inbox ( + "INSERT INTO agent_org_execution_inbox ( recipient_agent_id,org_run_id,recipient_member_id,sender_agent_id, sender_member_id,payload_kind,payload_json,created_at ) VALUES ('agent-member',?1,?2,'agent-peer','member-peer','plain',?3,'now')", @@ -951,14 +952,14 @@ fn assistant_persistence_accepts_only_exact_same_turn_terminal_provenance() { ) .expect("promote Turn to running"); conn.execute( - "UPDATE agent_org_runtime_tasks + "UPDATE agent_org_execution_tasks SET status='completed',updated_at='completed-at' WHERE org_run_id=?1 AND id='task-a'", [RUN_ID], ) .expect("complete Task"); conn.execute( - "INSERT INTO agent_org_runtime_task_events ( + "INSERT INTO agent_org_execution_task_events ( id,org_run_id,task_id,event_type,previous_owner,next_owner, previous_status,next_status,actor_member_id,actor_kind, source_turn_intent_id,created_at @@ -980,7 +981,7 @@ fn assistant_persistence_accepts_only_exact_same_turn_terminal_provenance() { .expect("same completing Turn may persist its final assistant iteration"); conn.execute( - "INSERT INTO agent_org_runtime_task_events ( + "INSERT INTO agent_org_execution_task_events ( id,org_run_id,task_id,event_type,previous_owner,next_owner, previous_status,next_status,actor_member_id,actor_kind, source_turn_intent_id,created_at @@ -999,13 +1000,13 @@ fn assistant_persistence_accepts_only_exact_same_turn_terminal_provenance() { "{stale_terminal}" ); conn.execute( - "DELETE FROM agent_org_runtime_task_events WHERE id='event-later-system'", + "DELETE FROM agent_org_execution_task_events WHERE id='event-later-system'", [], ) .expect("remove later mutation for the remaining provenance cases"); conn.execute( - "UPDATE agent_org_runtime_task_events + "UPDATE agent_org_execution_task_events SET source_turn_intent_id='turn-other' WHERE id='event-completed'", [], @@ -1017,7 +1018,7 @@ fn assistant_persistence_accepts_only_exact_same_turn_terminal_provenance() { assert!(other_turn.contains("terminal provenance"), "{other_turn}"); conn.execute( - "UPDATE agent_org_runtime_task_events + "UPDATE agent_org_execution_task_events SET source_turn_intent_id=?1,actor_kind='system' WHERE id='event-completed'", [turn_id], @@ -1032,7 +1033,7 @@ fn assistant_persistence_accepts_only_exact_same_turn_terminal_provenance() { ); conn.execute( - "UPDATE agent_org_runtime_task_events + "UPDATE agent_org_execution_task_events SET actor_kind='owner_execution' WHERE id='event-completed'", [], @@ -1065,14 +1066,14 @@ fn assistant_persistence_allows_exact_owner_failure_and_cancelled_turn_end() { ) .expect("promote Turn to running"); conn.execute( - "UPDATE agent_org_runtime_tasks + "UPDATE agent_org_execution_tasks SET status='failed',updated_at='failed-at' WHERE org_run_id=?1 AND id='task-a'", [RUN_ID], ) .expect("fail Task"); conn.execute( - "INSERT INTO agent_org_runtime_task_events ( + "INSERT INTO agent_org_execution_task_events ( id,org_run_id,task_id,event_type,previous_owner,next_owner, previous_status,next_status,actor_member_id,actor_kind, source_turn_intent_id,created_at @@ -1087,7 +1088,7 @@ fn assistant_persistence_allows_exact_owner_failure_and_cancelled_turn_end() { .expect("owner may explain a failure committed by this exact Turn"); conn.execute( - "UPDATE agent_org_runtime_tasks + "UPDATE agent_org_execution_tasks SET status='cancelled',updated_at='cancelled-at' WHERE org_run_id=?1 AND id='task-a'", [RUN_ID], @@ -1103,7 +1104,7 @@ fn assistant_persistence_allows_exact_owner_failure_and_cancelled_turn_end() { .expect("the already-running exact Turn may persist its transcript and end naturally"); conn.execute( - "UPDATE agent_org_runtime_tasks + "UPDATE agent_org_execution_tasks SET updated_at='reassigned-at',owner='member-reassigned' WHERE org_run_id=?1 AND id='task-a'", [RUN_ID], @@ -1130,7 +1131,7 @@ fn assistant_persistence_rejects_generation_and_materialization_drift() { .expect("current in-progress Task may persist assistant output"); conn.execute( - "UPDATE agent_org_runtime_runs SET activation_generation=2 WHERE id=?1", + "UPDATE agent_org_execution_runs SET activation_generation=2 WHERE id=?1", [RUN_ID], ) .expect("advance activation generation"); @@ -1142,7 +1143,7 @@ fn assistant_persistence_rejects_generation_and_materialization_drift() { "{generation}" ); conn.execute( - "UPDATE agent_org_runtime_runs SET activation_generation=1 WHERE id=?1", + "UPDATE agent_org_execution_runs SET activation_generation=1 WHERE id=?1", [RUN_ID], ) .expect("restore activation generation"); @@ -1150,7 +1151,7 @@ fn assistant_persistence_rejects_generation_and_materialization_drift() { conn.execute_batch( "INSERT INTO agent_sessions VALUES ('session-member-new', 'agent-member', 'member-a'); - INSERT INTO agent_org_runtime_member_materializations + INSERT INTO agent_org_execution_member_materializations (org_run_id, member_id, agent_id, generation, session_id, status) VALUES ('run-a', 'member-a', 'agent-member', 2, 'session-member-new', 'succeeded');", @@ -1180,13 +1181,13 @@ fn assistant_terminal_provenance_query_is_task_index_bounded() { assert!( details .iter() - .any(|detail| detail.contains("idx_agent_org_runtime_task_events_task")), + .any(|detail| detail.contains("idx_agent_org_execution_task_events_task")), "task event lookup must use the exact run/task index: {details:?}" ); assert!( details .iter() - .all(|detail| !detail.contains("SCAN agent_org_runtime_task_events")), + .all(|detail| !detail.contains("SCAN agent_org_execution_task_events")), "task event lookup must not scan the full history table: {details:?}" ); } @@ -1204,12 +1205,12 @@ fn durable_pause_continuation_excludes_parallel_ordinary_wake_until_terminal() { ) .expect("finish original Turn before persisted continuation"); conn.execute( - "UPDATE agent_org_runtime_runs SET activation_generation=3 WHERE id=?1", + "UPDATE agent_org_execution_runs SET activation_generation=3 WHERE id=?1", [RUN_ID], ) .expect("advance run to Resume generation"); conn.execute( - "UPDATE agent_org_runtime_member_materializations + "UPDATE agent_org_execution_member_materializations SET generation=3 WHERE org_run_id=?1 AND member_id=?2", params![RUN_ID, MEMBER_ID], ) @@ -1235,7 +1236,7 @@ fn durable_pause_continuation_excludes_parallel_ordinary_wake_until_terminal() { .expect("persist Resume continuation before dispatcher starts"); assert_eq!(continuation_context.member_dispatch_sequence, Some(2)); conn.execute_batch( - "INSERT INTO agent_org_runtime_pause_episodes ( + "INSERT INTO agent_org_execution_pause_episodes ( episode_id,org_run_id,pause_request_id,pause_generation,status, resume_request_id,resume_generation,teardown_owner_id, created_at,updated_at,resumed_at @@ -1243,7 +1244,7 @@ fn durable_pause_continuation_excludes_parallel_ordinary_wake_until_terminal() { 'episode-a','run-a','pause-request-a',2,'consumed', 'resume-request-a',3,'teardown-a','now','now','now' ); - INSERT INTO agent_org_runtime_pause_handoffs ( + INSERT INTO agent_org_execution_pause_handoffs ( handoff_id,episode_id,org_run_id,session_id,original_turn_intent_id, turn_kind,participant_id,task_id,original_owner_member_id, original_activation_generation,original_intent_status,drain_status, @@ -1309,8 +1310,8 @@ fn durable_pause_continuation_excludes_parallel_ordinary_wake_until_terminal() { fn failed_or_cancelled_blockers_never_unlock_a_task_wake() { let mut conn = connection(); conn.execute_batch( - "UPDATE agent_org_runtime_tasks SET status='cancelled' WHERE id='task-a'; - INSERT INTO agent_org_runtime_tasks + "UPDATE agent_org_execution_tasks SET status='cancelled' WHERE id='task-a'; + INSERT INTO agent_org_execution_tasks (org_run_id,id,owner,status,execution_mode,blocked_by_json) VALUES ('run-a','blocker','member-a','failed','build','[]'), @@ -1335,7 +1336,7 @@ fn failed_or_cancelled_blockers_never_unlock_a_task_wake() { assert!(matches!(error, WakeAdmission::NoReadyWork)); conn.execute( - "UPDATE agent_org_runtime_tasks SET status='completed' + "UPDATE agent_org_execution_tasks SET status='completed' WHERE org_run_id=?1 AND id='blocker'", [RUN_ID], ) @@ -1443,7 +1444,7 @@ fn every_member_kind_and_source_shares_one_fifo_and_replay_does_not_bump_it() { assert_eq!(replay.member_dispatch_sequence, Some(1)); let next_sequence: i64 = conn .query_row( - "SELECT next_sequence FROM agent_org_runtime_member_dispatch_allocators + "SELECT next_sequence FROM agent_org_execution_member_dispatch_allocators WHERE org_run_id=?1 AND member_id=?2", params![RUN_ID, MEMBER_ID], |row| row.get(0), @@ -1469,7 +1470,7 @@ fn every_member_kind_and_source_shares_one_fifo_and_replay_does_not_bump_it() { fn user_directed_actor_version_is_independent_from_formal_activation_generation() { let mut conn = connection(); conn.execute( - "UPDATE agent_org_runtime_runs SET activation_generation=2 WHERE id=?1", + "UPDATE agent_org_execution_runs SET activation_generation=2 WHERE id=?1", [RUN_ID], ) .unwrap(); @@ -1499,7 +1500,7 @@ fn canonical_check_and_exhaustive_decode_fail_closed() { ) .unwrap(); let invalid = conn.execute( - "INSERT INTO agent_org_runtime_turn_contexts ( + "INSERT INTO agent_org_execution_turn_contexts ( session_id, turn_intent_id, org_run_id, participant_id, turn_kind, dispatch_member_id, member_dispatch_sequence, source_kind, source_id, activation_generation, created_at @@ -1522,7 +1523,7 @@ fn canonical_check_and_exhaustive_decode_fail_closed() { conn.execute_batch("PRAGMA ignore_check_constraints=ON;") .expect("simulate corrupted stored discriminant"); conn.execute( - "INSERT INTO agent_org_runtime_turn_contexts ( + "INSERT INTO agent_org_execution_turn_contexts ( session_id, turn_intent_id, org_run_id, participant_id, turn_kind, source_kind, source_id, activation_generation, created_at ) VALUES (?1, 'turn-unknown-kind', ?2, 'coordinator', 'future_kind', @@ -1545,7 +1546,7 @@ fn transaction_failure_rolls_back_allocator_base_and_context() { "CREATE TRIGGER fail_admission BEFORE INSERT ON session_turn_intents BEGIN SELECT RAISE(ABORT, 'base fault'); END;" } else { - "CREATE TRIGGER fail_admission BEFORE INSERT ON agent_org_runtime_turn_contexts + "CREATE TRIGGER fail_admission BEFORE INSERT ON agent_org_execution_turn_contexts BEGIN SELECT RAISE(ABORT, 'context fault'); END;" }; conn.execute_batch(trigger).expect("install fault trigger"); @@ -1557,9 +1558,9 @@ fn transaction_failure_rolls_back_allocator_base_and_context() { assert!(error.contains("fault"), "{error}"); transaction.rollback().expect("rollback failed admission"); assert_eq!(row_count(&conn, "session_turn_intents"), 0); - assert_eq!(row_count(&conn, "agent_org_runtime_turn_contexts"), 0); + assert_eq!(row_count(&conn, "agent_org_execution_turn_contexts"), 0); assert_eq!( - row_count(&conn, "agent_org_runtime_member_dispatch_allocators"), + row_count(&conn, "agent_org_execution_member_dispatch_allocators"), 0 ); } @@ -1585,8 +1586,11 @@ fn task_execution_without_exact_authority_source_rolls_back_admission() { "{error}" ); assert_eq!(row_count(&conn, "session_turn_intents"), 0); - assert_eq!(row_count(&conn, "agent_org_runtime_turn_contexts"), 0); - assert_eq!(row_count(&conn, "agent_org_task_execution_leases"), 0); + assert_eq!(row_count(&conn, "agent_org_execution_turn_contexts"), 0); + assert_eq!( + row_count(&conn, "agent_org_execution_task_execution_leases"), + 0 + ); } #[test] @@ -1638,8 +1642,11 @@ fn continuation_receipt_is_one_time_even_after_prior_turn_ends() { error.contains(super::super::agent_org_finality::TASK_EXECUTION_ALREADY_ACTIVE), "{error}" ); - assert_eq!(row_count(&conn, "agent_org_runtime_turn_contexts"), 1); - assert_eq!(row_count(&conn, "agent_org_task_execution_leases"), 1); + assert_eq!(row_count(&conn, "agent_org_execution_turn_contexts"), 1); + assert_eq!( + row_count(&conn, "agent_org_execution_task_execution_leases"), + 1 + ); } #[test] @@ -1750,7 +1757,7 @@ fn fifty_concurrent_task_wakes_admit_exactly_one_live_execution() { let conn = Connection::open(path).expect("inspect shared database"); let live: i64 = conn .query_row( - "SELECT COUNT(*) FROM agent_org_task_execution_leases + "SELECT COUNT(*) FROM agent_org_execution_task_execution_leases WHERE org_run_id=?1 AND work_episode_id='episode-a' AND task_id='task-a' AND activation_generation=1 AND state='active'", [RUN_ID], @@ -1772,7 +1779,7 @@ fn recovery_preserves_only_typed_canonical_initial_and_keeps_running_unknown() { ); accept_in_transaction(&mut conn, &initial).unwrap(); conn.execute( - "INSERT INTO agent_org_runtime_initial_inputs + "INSERT INTO agent_org_execution_initial_inputs (org_run_id, turn_intent_id, message_id, status) VALUES (?1, 'turn-initial', 'message-initial', 'queued')", [RUN_ID], @@ -1808,7 +1815,7 @@ fn recovery_preserves_only_typed_canonical_initial_and_keeps_running_unknown() { assert_eq!(status(&conn, "turn-contextless-terminal"), "completed"); conn.execute( - "UPDATE agent_org_runtime_initial_inputs SET message_id='wrong-message' WHERE org_run_id=?1", + "UPDATE agent_org_execution_initial_inputs SET message_id='wrong-message' WHERE org_run_id=?1", [RUN_ID], ) .unwrap(); @@ -1875,7 +1882,7 @@ fn background_coordinator_wake_preserves_the_durable_fact_trigger() { let persisted: (String, String, i64, String, String) = conn .query_row( "SELECT trigger_kind,trigger_id,trigger_revision,status,doorbell_status - FROM agent_org_runtime_formal_trigger_receipts WHERE receipt_id=?1", + FROM agent_org_execution_formal_trigger_receipts WHERE receipt_id=?1", [&receipt.receipt_id], |row| { Ok(( @@ -1917,15 +1924,15 @@ fn run_delete_cascades_context_and_allocator_without_touching_generic_rows() { [RUN_ID], ) .unwrap(); - assert_eq!(row_count(&conn, "agent_org_runtime_turn_contexts"), 0); + assert_eq!(row_count(&conn, "agent_org_execution_turn_contexts"), 0); assert_eq!( - row_count(&conn, "agent_org_runtime_member_dispatch_allocators"), + row_count(&conn, "agent_org_execution_member_dispatch_allocators"), 1 ); - conn.execute("DELETE FROM agent_org_runtime_runs WHERE id=?1", [RUN_ID]) + conn.execute("DELETE FROM agent_org_execution_runs WHERE id=?1", [RUN_ID]) .unwrap(); assert_eq!( - row_count(&conn, "agent_org_runtime_member_dispatch_allocators"), + row_count(&conn, "agent_org_execution_member_dispatch_allocators"), 0 ); assert_eq!(row_count(&conn, "session_turn_intents"), 1); diff --git a/src-tauri/crates/agent-core/src/core/coordination/agent_org_turn_contexts/wake_admission.rs b/src-tauri/crates/agent-core/src/core/coordination/agent_org_turn_contexts/wake_admission.rs index a3588fa7ed..9bb99c838b 100644 --- a/src-tauri/crates/agent-core/src/core/coordination/agent_org_turn_contexts/wake_admission.rs +++ b/src-tauri/crates/agent-core/src/core/coordination/agent_org_turn_contexts/wake_admission.rs @@ -25,7 +25,7 @@ pub(super) fn assess_wake( ) -> Result>, String> { validate_non_empty(request)?; let (root, snapshot, status): (Option, String, String) = conn.query_row( - "SELECT root_session_id,org_snapshot_json,status FROM agent_org_runtime_runs WHERE id=?1", + "SELECT root_session_id,org_snapshot_json,status FROM agent_org_execution_runs WHERE id=?1", [&request.org_run_id], |row| Ok((row.get(0)?, row.get(1)?, row.get(2)?)), ).map_err(|error| error.to_string())?; let snapshot: AgentOrgLaunchSnapshot = @@ -51,7 +51,7 @@ pub(super) fn assess_wake( return Ok(WakeAdmission::Deferred); } let intervention: bool = conn.query_row( - "SELECT EXISTS(SELECT 1 FROM agent_org_runtime_member_interventions + "SELECT EXISTS(SELECT 1 FROM agent_org_execution_member_interventions WHERE org_run_id=?1 AND member_id=?2 AND status IN ('yield_requested','active','return_requested'))", params![request.org_run_id, member_id], |row| row.get(0), ).map_err(|error| error.to_string())?; @@ -72,7 +72,7 @@ pub(super) fn assess_wake( }; let busy: bool = conn .query_row( - "SELECT EXISTS(SELECT 1 FROM agent_org_task_execution_leases lease + "SELECT EXISTS(SELECT 1 FROM agent_org_execution_task_execution_leases lease JOIN session_turn_intents intent USING(session_id,turn_intent_id) WHERE lease.org_run_id=?1 AND lease.task_id=?2 AND lease.activation_generation=?3 AND lease.state='active' AND intent.status IN ('queued','running','optimistic') @@ -99,16 +99,16 @@ fn coordinator_has_input( request: &AgentOrgTurnAdmission, ) -> Result { conn.query_row( - "SELECT EXISTS(SELECT 1 FROM agent_org_runtime_inbox inbox - LEFT JOIN agent_org_runtime_formal_trigger_receipts receipt ON receipt.inbox_id=inbox.id + "SELECT EXISTS(SELECT 1 FROM agent_org_execution_inbox inbox + LEFT JOIN agent_org_execution_formal_trigger_receipts receipt ON receipt.inbox_id=inbox.id WHERE inbox.org_run_id=?1 AND inbox.recipient_member_id='coordinator' AND inbox.delivery_class='formal_work' AND inbox.read_at IS NULL - AND NOT EXISTS(SELECT 1 FROM agent_org_runtime_inbox_delivery_resolutions resolution WHERE resolution.inbox_id=inbox.id) + AND NOT EXISTS(SELECT 1 FROM agent_org_execution_inbox_delivery_resolutions resolution WHERE resolution.inbox_id=inbox.id) AND (receipt.receipt_id IS NULL OR receipt.status IN ('pending','materialized')) - AND NOT EXISTS(SELECT 1 FROM agent_org_runtime_formal_trigger_attempts attempt + AND NOT EXISTS(SELECT 1 FROM agent_org_execution_formal_trigger_attempts attempt WHERE attempt.receipt_id=receipt.receipt_id AND attempt.status IN ('queued','running') AND NOT (attempt.session_id=?2 AND attempt.turn_intent_id=?3))) - OR EXISTS(SELECT 1 FROM agent_org_runtime_final_summary_receipts summary + OR EXISTS(SELECT 1 FROM agent_org_execution_final_summary_receipts summary WHERE summary.org_run_id=?1 AND (summary.status='pending' OR (summary.coordinator_session_id=?2 AND summary.turn_intent_id=?3 AND summary.status IN ('running','persisting'))))", params![request.org_run_id,request.session_id,request.turn_intent_id], |row| row.get(0), @@ -130,7 +130,7 @@ pub(crate) fn revalidate_wake_in_tx( ); let current: bool = conn .query_row( - "SELECT activation_generation=?2 FROM agent_org_runtime_runs WHERE id=?1", + "SELECT activation_generation=?2 FROM agent_org_execution_runs WHERE id=?1", params![context.org_run_id, context.activation_generation], |row| row.get(0), ) diff --git a/src-tauri/crates/agent-core/src/core/coordination/agent_org_turn_contexts/wake_admission_tests.rs b/src-tauri/crates/agent-core/src/core/coordination/agent_org_turn_contexts/wake_admission_tests.rs index 1f6d898131..39c5a8166d 100644 --- a/src-tauri/crates/agent-core/src/core/coordination/agent_org_turn_contexts/wake_admission_tests.rs +++ b/src-tauri/crates/agent-core/src/core/coordination/agent_org_turn_contexts/wake_admission_tests.rs @@ -50,7 +50,7 @@ fn obsolete_assignment_keeps_its_unread_evidence_and_new_work_gets_admitted() { let conn = connection(); let obsolete = insert_task_assignment(&conn, "task-a"); conn.execute( - "UPDATE agent_org_runtime_tasks SET status='completed' WHERE id='task-a'", + "UPDATE agent_org_execution_tasks SET status='completed' WHERE id='task-a'", [], ) .unwrap(); @@ -62,13 +62,13 @@ fn obsolete_assignment_keeps_its_unread_evidence_and_new_work_gets_admitted() { } assert!(conn .query_row( - "SELECT read_at IS NULL FROM agent_org_runtime_inbox WHERE id=?1", + "SELECT read_at IS NULL FROM agent_org_execution_inbox WHERE id=?1", [obsolete], |r| r.get::<_, bool>(0) ) .unwrap()); - conn.execute_batch("INSERT INTO agent_org_runtime_tasks(org_run_id,id,owner,status) VALUES('run-a','task-new','member-a','pending'); - INSERT INTO agent_org_runtime_work_episode_tasks(org_run_id,work_episode_id,task_id,associated_at) VALUES('run-a','episode-a','task-new','now');").unwrap(); + conn.execute_batch("INSERT INTO agent_org_execution_tasks(org_run_id,id,owner,status) VALUES('run-a','task-new','member-a','pending'); + INSERT INTO agent_org_execution_work_episode_tasks(org_run_id,work_episode_id,task_id,associated_at) VALUES('run-a','episode-a','task-new','now');").unwrap(); insert_task_assignment(&conn, "task-new"); let next = wake(&conn, "new-work", MEMBER_ID) .unwrap() @@ -86,9 +86,9 @@ fn queued_wake_cannot_execute_or_inherit_a_replacement_task() { .unwrap() .into_ready() .unwrap(); - conn.execute_batch("UPDATE agent_org_runtime_tasks SET status='cancelled' WHERE id='task-a'; - INSERT INTO agent_org_runtime_tasks(org_run_id,id,owner,status) VALUES('run-a','task-new','member-a','pending'); - INSERT INTO agent_org_runtime_work_episode_tasks(org_run_id,work_episode_id,task_id,associated_at) VALUES('run-a','episode-a','task-new','now');").unwrap(); + conn.execute_batch("UPDATE agent_org_execution_tasks SET status='cancelled' WHERE id='task-a'; + INSERT INTO agent_org_execution_tasks(org_run_id,id,owner,status) VALUES('run-a','task-new','member-a','pending'); + INSERT INTO agent_org_execution_work_episode_tasks(org_run_id,work_episode_id,task_id,associated_at) VALUES('run-a','episode-a','task-new','now');").unwrap(); insert_task_assignment(&conn, "task-new"); assert!(!revalidate_wake_in_tx(&conn, MEMBER_SESSION_ID, "queued-old").unwrap()); assert_eq!( @@ -102,7 +102,7 @@ fn queued_wake_cannot_execute_or_inherit_a_replacement_task() { ); assert_eq!( conn.query_row( - "SELECT COUNT(*) FROM agent_org_task_execution_leases WHERE state='active'", + "SELECT COUNT(*) FROM agent_org_execution_task_execution_leases WHERE state='active'", [], |r| r.get::<_, i64>(0) ) @@ -130,14 +130,14 @@ fn empty_wake_still_rejects_bad_identity_storage_and_payload() { assert!(wake(&conn, "bad-member", "not-a-member").is_err()); let row = insert_task_assignment(&conn, "task-a"); conn.execute( - "UPDATE agent_org_runtime_inbox SET payload_json='broken' WHERE id=?1", + "UPDATE agent_org_execution_inbox SET payload_json='broken' WHERE id=?1", [row], ) .unwrap(); assert!(wake(&conn, "bad-payload", MEMBER_ID).is_err()); - conn.execute("DELETE FROM agent_org_runtime_inbox WHERE id=?1", [row]) + conn.execute("DELETE FROM agent_org_execution_inbox WHERE id=?1", [row]) .unwrap(); - conn.execute("DROP TABLE agent_org_runtime_inbox", []) + conn.execute("DROP TABLE agent_org_execution_inbox", []) .unwrap(); assert!(wake(&conn, "broken-storage", MEMBER_ID).is_err()); assert_eq!(row_count(&conn, "session_turn_intents"), 0); @@ -151,14 +151,14 @@ fn pause_and_old_generation_cannot_start_queued_work() { .unwrap() .into_ready() .unwrap(); - conn.execute("UPDATE agent_org_runtime_runs SET status='paused'", []) + conn.execute("UPDATE agent_org_execution_runs SET status='paused'", []) .unwrap(); assert!(matches!( wake(&conn, "paused-wake", MEMBER_ID).unwrap(), WakeAdmission::Deferred )); assert!(!revalidate_wake_in_tx(&conn, MEMBER_SESSION_ID, "queued-before-pause").unwrap()); - conn.execute("UPDATE agent_org_runtime_runs SET status='running'", []) + conn.execute("UPDATE agent_org_execution_runs SET status='running'", []) .unwrap(); assert!(matches!( wake(&conn, "consumed-assignment", MEMBER_ID).unwrap(), @@ -172,7 +172,7 @@ fn pause_and_old_generation_cannot_start_queued_work() { .into_ready() .unwrap(); conn.execute( - "UPDATE agent_org_runtime_runs SET activation_generation=2", + "UPDATE agent_org_execution_runs SET activation_generation=2", [], ) .unwrap(); @@ -186,20 +186,20 @@ fn coordinator_no_work_gate_preserves_resolved_rows_and_mixed_new_input() { wake(&conn, "empty-root", COORDINATOR_MEMBER_ID).unwrap(), WakeAdmission::NoReadyWork )); - conn.execute_batch("INSERT INTO agent_org_runtime_inbox(org_run_id,recipient_member_id,payload_kind,payload_json) VALUES('run-a','coordinator','plain','{}'); - INSERT INTO agent_org_runtime_inbox_delivery_resolutions(inbox_id) VALUES(last_insert_rowid());").unwrap(); + conn.execute_batch("INSERT INTO agent_org_execution_inbox(org_run_id,recipient_member_id,payload_kind,payload_json) VALUES('run-a','coordinator','plain','{}'); + INSERT INTO agent_org_execution_inbox_delivery_resolutions(inbox_id) VALUES(last_insert_rowid());").unwrap(); assert!(matches!( wake(&conn, "resolved-root", COORDINATOR_MEMBER_ID).unwrap(), WakeAdmission::NoReadyWork )); - conn.execute_batch("INSERT INTO agent_org_runtime_inbox(org_run_id,recipient_member_id,payload_kind,payload_json) VALUES('run-a','coordinator','plain','{}');").unwrap(); + conn.execute_batch("INSERT INTO agent_org_execution_inbox(org_run_id,recipient_member_id,payload_kind,payload_json) VALUES('run-a','coordinator','plain','{}');").unwrap(); wake(&conn, "mixed-root", COORDINATOR_MEMBER_ID) .unwrap() .into_ready() .unwrap(); assert_eq!( conn.query_row( - "SELECT COUNT(*) FROM agent_org_runtime_inbox WHERE recipient_member_id='coordinator' AND read_at IS NULL", + "SELECT COUNT(*) FROM agent_org_execution_inbox WHERE recipient_member_id='coordinator' AND read_at IS NULL", [], |r| r.get::<_, i64>(0) ) @@ -214,7 +214,7 @@ fn consumed_authority_lookup_is_bounded_by_the_unique_receipt_index() { let mut statement = conn .prepare( "EXPLAIN QUERY PLAN SELECT 1 - FROM agent_org_task_execution_leases lease + FROM agent_org_execution_task_execution_leases lease JOIN session_turn_intents intent USING(session_id,turn_intent_id) WHERE lease.continuation_receipt_id='inbox:' || ?1 AND intent.status NOT IN ('queued','running','optimistic')", diff --git a/src-tauri/crates/agent-core/src/core/coordination/agent_org_user_directed_work.rs b/src-tauri/crates/agent-core/src/core/coordination/agent_org_user_directed_work.rs index cea804913f..d58f98cc1e 100644 --- a/src-tauri/crates/agent-core/src/core/coordination/agent_org_user_directed_work.rs +++ b/src-tauri/crates/agent-core/src/core/coordination/agent_org_user_directed_work.rs @@ -182,7 +182,7 @@ pub(crate) struct UserDirectedCausalReply { pub(super) fn create_schema(conn: &Connection) -> rusqlite::Result<()> { conn.execute_batch( - "CREATE TABLE IF NOT EXISTS agent_org_runtime_user_directed_roots ( + "CREATE TABLE IF NOT EXISTS agent_org_execution_user_directed_roots ( org_run_id TEXT NOT NULL, root_authority_turn_id TEXT NOT NULL CHECK(length(trim(root_authority_turn_id)) > 0), policy_version INTEGER NOT NULL CHECK(policy_version >= 1), @@ -191,10 +191,10 @@ pub(super) fn create_schema(conn: &Connection) -> rusqlite::Result<()> { next_delivery_ordinal INTEGER NOT NULL CHECK(next_delivery_ordinal >= 2), created_at TEXT NOT NULL, PRIMARY KEY(org_run_id, root_authority_turn_id), - FOREIGN KEY(org_run_id) REFERENCES agent_org_runtime_runs(id) ON DELETE CASCADE + FOREIGN KEY(org_run_id) REFERENCES agent_org_execution_runs(id) ON DELETE CASCADE ); - CREATE TABLE IF NOT EXISTS agent_org_runtime_user_directed_deliveries ( + CREATE TABLE IF NOT EXISTS agent_org_execution_user_directed_deliveries ( delivery_id INTEGER PRIMARY KEY AUTOINCREMENT, org_run_id TEXT NOT NULL, session_id TEXT NOT NULL CHECK(length(trim(session_id)) > 0), @@ -225,17 +225,17 @@ pub(super) fn create_schema(conn: &Connection) -> rusqlite::Result<()> { UNIQUE(session_id, turn_intent_id), UNIQUE(org_run_id, root_authority_turn_id, delivery_ordinal), FOREIGN KEY(org_run_id, root_authority_turn_id) - REFERENCES agent_org_runtime_user_directed_roots(org_run_id, root_authority_turn_id) + REFERENCES agent_org_execution_user_directed_roots(org_run_id, root_authority_turn_id) ON DELETE CASCADE, FOREIGN KEY(session_id, turn_intent_id) - REFERENCES agent_org_runtime_turn_contexts(session_id, turn_intent_id) + REFERENCES agent_org_execution_turn_contexts(session_id, turn_intent_id) ON DELETE CASCADE, FOREIGN KEY(parent_delivery_id) - REFERENCES agent_org_runtime_user_directed_deliveries(delivery_id) ON DELETE RESTRICT, + REFERENCES agent_org_execution_user_directed_deliveries(delivery_id) ON DELETE RESTRICT, FOREIGN KEY(source_inbox_id) - REFERENCES agent_org_runtime_inbox(id) ON DELETE RESTRICT, + REFERENCES agent_org_execution_inbox(id) ON DELETE RESTRICT, FOREIGN KEY(parent_inbox_id) - REFERENCES agent_org_runtime_inbox(id) ON DELETE RESTRICT, + REFERENCES agent_org_execution_inbox(id) ON DELETE RESTRICT, CHECK( (source_kind='direct_member' AND source_event_id IS NOT NULL @@ -264,18 +264,18 @@ pub(super) fn create_schema(conn: &Connection) -> rusqlite::Result<()> { (status IN ('failed','abandoned','unknown') AND terminal_at IS NOT NULL) ) ); - CREATE UNIQUE INDEX IF NOT EXISTS idx_agent_org_runtime_udw_source_inbox - ON agent_org_runtime_user_directed_deliveries(source_inbox_id) + CREATE UNIQUE INDEX IF NOT EXISTS idx_agent_org_execution_udw_source_inbox + ON agent_org_execution_user_directed_deliveries(source_inbox_id) WHERE source_inbox_id IS NOT NULL; - CREATE INDEX IF NOT EXISTS idx_agent_org_runtime_udw_member_fifo - ON agent_org_runtime_user_directed_deliveries( + CREATE INDEX IF NOT EXISTS idx_agent_org_execution_udw_member_fifo + ON agent_org_execution_user_directed_deliveries( org_run_id, dispatch_member_id, member_dispatch_sequence ) WHERE status IN ('pending','started'); - CREATE INDEX IF NOT EXISTS idx_agent_org_runtime_udw_pending_recovery - ON agent_org_runtime_user_directed_deliveries(delivery_id) + CREATE INDEX IF NOT EXISTS idx_agent_org_execution_udw_pending_recovery + ON agent_org_execution_user_directed_deliveries(delivery_id) WHERE status='pending'; - CREATE TABLE IF NOT EXISTS agent_org_runtime_user_directed_coordinator_bindings ( + CREATE TABLE IF NOT EXISTS agent_org_execution_user_directed_coordinator_bindings ( binding_id INTEGER PRIMARY KEY AUTOINCREMENT, org_run_id TEXT NOT NULL, session_id TEXT NOT NULL CHECK(length(trim(session_id)) > 0), @@ -300,15 +300,15 @@ pub(super) fn create_schema(conn: &Connection) -> rusqlite::Result<()> { UNIQUE(source_inbox_id), UNIQUE(org_run_id,root_authority_turn_id,delivery_ordinal), FOREIGN KEY(org_run_id,root_authority_turn_id) - REFERENCES agent_org_runtime_user_directed_roots(org_run_id,root_authority_turn_id) + REFERENCES agent_org_execution_user_directed_roots(org_run_id,root_authority_turn_id) ON DELETE CASCADE, FOREIGN KEY(session_id,turn_intent_id) - REFERENCES agent_org_runtime_turn_contexts(session_id,turn_intent_id) + REFERENCES agent_org_execution_turn_contexts(session_id,turn_intent_id) ON DELETE CASCADE, FOREIGN KEY(parent_delivery_id) - REFERENCES agent_org_runtime_user_directed_deliveries(delivery_id) ON DELETE RESTRICT, - FOREIGN KEY(parent_inbox_id) REFERENCES agent_org_runtime_inbox(id) ON DELETE RESTRICT, - FOREIGN KEY(source_inbox_id) REFERENCES agent_org_runtime_inbox(id) ON DELETE RESTRICT, + REFERENCES agent_org_execution_user_directed_deliveries(delivery_id) ON DELETE RESTRICT, + FOREIGN KEY(parent_inbox_id) REFERENCES agent_org_execution_inbox(id) ON DELETE RESTRICT, + FOREIGN KEY(source_inbox_id) REFERENCES agent_org_execution_inbox(id) ON DELETE RESTRICT, CHECK(parent_inbox_id IS NULL OR parent_inbox_id<>source_inbox_id), CHECK( (status='pending' AND started_at IS NULL AND terminal_at IS NULL AND failure_reason IS NULL) @@ -320,8 +320,8 @@ pub(super) fn create_schema(conn: &Connection) -> rusqlite::Result<()> { (status IN ('failed','abandoned','unknown') AND terminal_at IS NOT NULL) ) ); - CREATE INDEX IF NOT EXISTS idx_agent_org_runtime_udw_coordinator_pending - ON agent_org_runtime_user_directed_coordinator_bindings(binding_id) + CREATE INDEX IF NOT EXISTS idx_agent_org_execution_udw_coordinator_pending + ON agent_org_execution_user_directed_coordinator_bindings(binding_id) WHERE status='pending';", ) } @@ -378,7 +378,7 @@ pub(crate) fn insert_root_delivery_with_connection( let now = chrono::Utc::now().to_rfc3339(); conn.execute( - "INSERT INTO agent_org_runtime_user_directed_roots ( + "INSERT INTO agent_org_execution_user_directed_roots ( org_run_id,root_authority_turn_id,policy_version,max_deliveries, max_cascade_depth,next_delivery_ordinal,created_at ) VALUES (?1,?2,?3,?4,?5,2,?6) @@ -422,7 +422,7 @@ pub(crate) fn insert_linked_member_delivery_with_connection( let root_limits: Option = conn .query_row( "SELECT max_cascade_depth - FROM agent_org_runtime_user_directed_roots + FROM agent_org_execution_user_directed_roots WHERE org_run_id=?1 AND root_authority_turn_id=?2", params![request.org_run_id, &parent.root_authority_turn_id], |row| row.get(0), @@ -440,7 +440,7 @@ pub(crate) fn insert_linked_member_delivery_with_connection( let pending: i64 = conn .query_row( "SELECT COUNT(*) - FROM agent_org_runtime_user_directed_deliveries + FROM agent_org_execution_user_directed_deliveries WHERE org_run_id=?1 AND dispatch_member_id=?2 AND status IN ('pending','started')", params![request.org_run_id, request.recipient_member_id], @@ -471,7 +471,7 @@ pub(crate) fn insert_linked_member_delivery_with_connection( })?; let delivery_ordinal: Option = conn .query_row( - "UPDATE agent_org_runtime_user_directed_roots + "UPDATE agent_org_execution_user_directed_roots SET next_delivery_ordinal=next_delivery_ordinal+1 WHERE org_run_id=?1 AND root_authority_turn_id=?2 AND next_delivery_ordinal<=max_deliveries+1 @@ -535,7 +535,7 @@ pub(crate) fn insert_linked_coordinator_delivery_with_connection( let max_depth: Option = conn .query_row( "SELECT max_cascade_depth - FROM agent_org_runtime_user_directed_roots + FROM agent_org_execution_user_directed_roots WHERE org_run_id=?1 AND root_authority_turn_id=?2", params![request.org_run_id, &parent.root_authority_turn_id], |row| row.get(0), @@ -552,7 +552,7 @@ pub(crate) fn insert_linked_coordinator_delivery_with_connection( } let delivery_ordinal: Option = conn .query_row( - "UPDATE agent_org_runtime_user_directed_roots + "UPDATE agent_org_execution_user_directed_roots SET next_delivery_ordinal=next_delivery_ordinal+1 WHERE org_run_id=?1 AND root_authority_turn_id=?2 AND next_delivery_ordinal<=max_deliveries+1 @@ -593,7 +593,7 @@ pub(crate) fn insert_linked_coordinator_delivery_with_connection( let digest = format!("{:x}", Sha256::digest(encoded)); let now = chrono::Utc::now().to_rfc3339(); conn.execute( - "INSERT INTO agent_org_runtime_user_directed_coordinator_bindings ( + "INSERT INTO agent_org_execution_user_directed_coordinator_bindings ( org_run_id,session_id,turn_intent_id,root_authority_turn_id, parent_delivery_id,parent_inbox_id,source_inbox_id,depth,delivery_ordinal,request_digest, dispatch_content,display_content,status,created_at @@ -631,7 +631,7 @@ fn get_coordinator_binding_with_connection( conn.query_row( "SELECT org_run_id,session_id,turn_intent_id,root_authority_turn_id, source_inbox_id,depth,delivery_ordinal,status - FROM agent_org_runtime_user_directed_coordinator_bindings + FROM agent_org_execution_user_directed_coordinator_bindings WHERE session_id=?1 AND turn_intent_id=?2", params![session_id, turn_intent_id], |row| { @@ -663,7 +663,7 @@ fn insert_delivery( let images_json = serde_json::to_string(request.images.unwrap_or(&[])).map_err(|error| error.to_string())?; conn.execute( - "INSERT INTO agent_org_runtime_user_directed_deliveries ( + "INSERT INTO agent_org_execution_user_directed_deliveries ( org_run_id,session_id,turn_intent_id,root_authority_turn_id, parent_delivery_id,parent_inbox_id,source_kind,source_event_id,source_inbox_id, dispatch_member_id,member_dispatch_sequence,depth,delivery_ordinal, @@ -704,7 +704,7 @@ pub(crate) fn get_by_turn_with_connection( root_authority_turn_id,parent_delivery_id,parent_inbox_id,source_kind,source_event_id, source_inbox_id,dispatch_member_id,member_dispatch_sequence,depth, delivery_ordinal,request_digest,status - FROM agent_org_runtime_user_directed_deliveries + FROM agent_org_execution_user_directed_deliveries WHERE session_id=?1 AND turn_intent_id=?2", params![session_id, turn_intent_id], row_to_delivery, @@ -745,7 +745,7 @@ pub(crate) fn causal_reply_for_turn( conn.query_row( "SELECT source_inbox_id,parent_inbox_id,root_authority_turn_id, depth,delivery_ordinal - FROM agent_org_runtime_user_directed_coordinator_bindings + FROM agent_org_execution_user_directed_coordinator_bindings WHERE session_id=?1 AND turn_intent_id=?2", params![session_id, turn_intent_id], |row| { @@ -781,13 +781,13 @@ pub(crate) fn mark_turn_started_with_connection( } let changed = conn .execute( - "UPDATE agent_org_runtime_user_directed_coordinator_bindings AS binding + "UPDATE agent_org_execution_user_directed_coordinator_bindings AS binding SET status='started',started_at=?3 WHERE binding.session_id=?1 AND binding.turn_intent_id=?2 AND binding.status='pending' AND NOT EXISTS ( SELECT 1 - FROM agent_org_runtime_user_directed_coordinator_bindings earlier + FROM agent_org_execution_user_directed_coordinator_bindings earlier WHERE earlier.org_run_id=binding.org_run_id AND earlier.binding_id Result<(), String> { let changed = conn .execute( - "UPDATE agent_org_runtime_inbox + "UPDATE agent_org_execution_inbox SET read_at=COALESCE(read_at,?4) WHERE id=?1 AND org_run_id=?2 AND recipient_member_id=?3 AND delivery_class='user_directed'", @@ -961,7 +961,7 @@ pub(crate) fn mark_turn_terminal( let now = chrono::Utc::now().to_rfc3339(); let changed = tx .execute( - "UPDATE agent_org_runtime_user_directed_coordinator_bindings + "UPDATE agent_org_execution_user_directed_coordinator_bindings SET status=?3,started_at=COALESCE(started_at,?4),terminal_at=?4, failure_reason=?5 WHERE session_id=?1 AND turn_intent_id=?2 @@ -1021,7 +1021,7 @@ pub(crate) fn mark_turn_terminal( let now = chrono::Utc::now().to_rfc3339(); let changed = tx .execute( - "UPDATE agent_org_runtime_user_directed_deliveries + "UPDATE agent_org_execution_user_directed_deliveries SET status=?3,started_at=COALESCE(started_at,?4),terminal_at=?4, failure_reason=?5 WHERE session_id=?1 AND turn_intent_id=?2 @@ -1108,7 +1108,7 @@ pub(crate) fn prepare_exact_group_cancellation( let now = chrono::Utc::now().to_rfc3339(); let changed = tx .execute( - "UPDATE agent_org_runtime_user_directed_deliveries + "UPDATE agent_org_execution_user_directed_deliveries SET status='cancelled',started_at=?3,terminal_at=?3, failure_reason='user_stop' WHERE session_id=?1 AND turn_intent_id=?2 AND status='pending'", @@ -1155,7 +1155,7 @@ pub(crate) fn next_pending_after_terminal( let owner: Option<(String, String, Option)> = conn .query_row( "SELECT org_run_id,participant_id,dispatch_member_id - FROM agent_org_runtime_turn_contexts + FROM agent_org_execution_turn_contexts WHERE session_id=?1 AND turn_intent_id=?2", params![session_id, turn_intent_id], |row| Ok((row.get(0)?, row.get(1)?, row.get(2)?)), @@ -1172,14 +1172,14 @@ pub(crate) fn next_pending_after_terminal( delivery.session_id,delivery.turn_intent_id, delivery.dispatch_content,delivery.display_content, delivery.images_json - FROM agent_org_runtime_user_directed_deliveries delivery - JOIN agent_org_runtime_turn_contexts context + FROM agent_org_execution_user_directed_deliveries delivery + JOIN agent_org_execution_turn_contexts context ON context.session_id=delivery.session_id AND context.turn_intent_id=delivery.turn_intent_id JOIN session_turn_intents intent ON intent.session_id=delivery.session_id AND intent.turn_intent_id=delivery.turn_intent_id - JOIN agent_org_runtime_runs run ON run.id=delivery.org_run_id + JOIN agent_org_execution_runs run ON run.id=delivery.org_run_id WHERE delivery.org_run_id=?1 AND delivery.dispatch_member_id=?2 AND delivery.status='pending' @@ -1208,14 +1208,14 @@ pub(crate) fn next_pending_after_terminal( "SELECT binding.org_run_id,'coordinator',binding.session_id, binding.turn_intent_id,binding.dispatch_content, binding.display_content,'[]' - FROM agent_org_runtime_user_directed_coordinator_bindings binding - JOIN agent_org_runtime_turn_contexts context + FROM agent_org_execution_user_directed_coordinator_bindings binding + JOIN agent_org_execution_turn_contexts context ON context.session_id=binding.session_id AND context.turn_intent_id=binding.turn_intent_id JOIN session_turn_intents intent ON intent.session_id=binding.session_id AND intent.turn_intent_id=binding.turn_intent_id - JOIN agent_org_runtime_runs run ON run.id=binding.org_run_id + JOIN agent_org_execution_runs run ON run.id=binding.org_run_id WHERE binding.org_run_id=?1 AND binding.status='pending' AND context.turn_kind='coordinator' AND context.source_kind='member_inbox' @@ -1274,7 +1274,7 @@ pub(crate) fn dispatch_owner_for_turn( let conn = get_connection().map_err(|error| error.to_string())?; conn.query_row( "SELECT org_run_id,dispatch_member_id - FROM agent_org_runtime_turn_contexts + FROM agent_org_execution_turn_contexts WHERE session_id=?1 AND turn_intent_id=?2 AND dispatch_member_id IS NOT NULL", params![session_id, turn_intent_id], @@ -1350,25 +1350,28 @@ mod tests { let conn = Connection::open_in_memory().expect("open database"); conn.execute_batch( "PRAGMA foreign_keys=ON; - CREATE TABLE agent_org_runtime_runs(id TEXT PRIMARY KEY); - CREATE TABLE agent_org_runtime_inbox(id INTEGER PRIMARY KEY); - CREATE TABLE agent_org_runtime_turn_contexts( + CREATE TABLE agent_org_execution_runs(id TEXT PRIMARY KEY); + CREATE TABLE agent_org_execution_inbox(id INTEGER PRIMARY KEY); + CREATE TABLE agent_org_execution_turn_contexts( session_id TEXT NOT NULL, turn_intent_id TEXT NOT NULL, UNIQUE(session_id,turn_intent_id) );", ) .expect("create dependencies"); create_schema(&conn).expect("create UDW schema"); - conn.execute("INSERT INTO agent_org_runtime_runs(id) VALUES ('run')", []) - .expect("insert run"); conn.execute( - "INSERT INTO agent_org_runtime_turn_contexts(session_id,turn_intent_id) + "INSERT INTO agent_org_execution_runs(id) VALUES ('run')", + [], + ) + .expect("insert run"); + conn.execute( + "INSERT INTO agent_org_execution_turn_contexts(session_id,turn_intent_id) VALUES ('session','turn')", [], ) .expect("insert context"); conn.execute( - "INSERT INTO agent_org_runtime_user_directed_roots( + "INSERT INTO agent_org_execution_user_directed_roots( org_run_id,root_authority_turn_id,policy_version,max_deliveries, max_cascade_depth,next_delivery_ordinal,created_at ) VALUES ('run','turn',1,8,2,2,'now')", @@ -1377,7 +1380,7 @@ mod tests { .expect("insert root"); let error = conn .execute( - "INSERT INTO agent_org_runtime_user_directed_deliveries( + "INSERT INTO agent_org_execution_user_directed_deliveries( org_run_id,session_id,turn_intent_id,root_authority_turn_id, source_kind,source_event_id,dispatch_member_id, member_dispatch_sequence,depth,delivery_ordinal,request_digest, diff --git a/src-tauri/crates/agent-core/src/core/coordination/agent_org_user_directed_work/recovery.rs b/src-tauri/crates/agent-core/src/core/coordination/agent_org_user_directed_work/recovery.rs index 945d4453b7..ef8242a7df 100644 --- a/src-tauri/crates/agent-core/src/core/coordination/agent_org_user_directed_work/recovery.rs +++ b/src-tauri/crates/agent-core/src/core/coordination/agent_org_user_directed_work/recovery.rs @@ -49,13 +49,13 @@ pub(crate) fn mark_started_unknown_after_restart_after( SELECT 'm:' || printf('%020d',delivery_id) AS recovery_key, 'member' AS recovery_kind,delivery_id AS row_id, org_run_id,session_id,turn_intent_id - FROM agent_org_runtime_user_directed_deliveries + FROM agent_org_execution_user_directed_deliveries WHERE status='started' UNION ALL SELECT 'c:' || printf('%020d',binding_id) AS recovery_key, 'coordinator' AS recovery_kind,binding_id AS row_id, org_run_id,session_id,turn_intent_id - FROM agent_org_runtime_user_directed_coordinator_bindings + FROM agent_org_execution_user_directed_coordinator_bindings WHERE status='started' ) SELECT recovery_key,recovery_kind,row_id,org_run_id, @@ -88,14 +88,14 @@ pub(crate) fn mark_started_unknown_after_restart_after( { let changed = if recovery_kind == "member" { tx.execute( - "UPDATE agent_org_runtime_member_intervention_turns + "UPDATE agent_org_execution_member_intervention_turns SET status='abandoned',terminal_at=?3,failure_reason=?4 WHERE session_id=?1 AND turn_intent_id=?2 AND status='running'", params![&session_id, &turn_intent_id, &now, reason], ) .map_err(|error| error.to_string())?; tx.execute( - "UPDATE agent_org_runtime_user_directed_deliveries + "UPDATE agent_org_execution_user_directed_deliveries SET status='unknown',terminal_at=?2,failure_reason=?3 WHERE delivery_id=?1 AND status='started'", params![row_id, &now, reason], @@ -103,7 +103,7 @@ pub(crate) fn mark_started_unknown_after_restart_after( .map_err(|error| error.to_string())? } else { tx.execute( - "UPDATE agent_org_runtime_user_directed_coordinator_bindings + "UPDATE agent_org_execution_user_directed_coordinator_bindings SET status='unknown',terminal_at=?2,failure_reason=?3 WHERE binding_id=?1 AND status='started'", params![row_id, &now, reason], @@ -113,7 +113,7 @@ pub(crate) fn mark_started_unknown_after_restart_after( if changed == 1 { if recovery_kind == "member" { tx.execute( - "UPDATE agent_org_member_turn_admissions + "UPDATE agent_org_execution_member_turn_admissions SET status='unknown',reason_code=?3,terminal_at=?4,updated_at=?4 WHERE session_id=?1 AND turn_intent_id=?2 AND status='committed'", params![&session_id, &turn_intent_id, reason, &now], @@ -154,15 +154,15 @@ pub(crate) fn recoverable_pending_after( delivery.org_run_id,delivery.dispatch_member_id, delivery.session_id,delivery.turn_intent_id, delivery.dispatch_content,delivery.display_content,delivery.images_json - FROM agent_org_runtime_user_directed_deliveries delivery - JOIN agent_org_runtime_turn_contexts context + FROM agent_org_execution_user_directed_deliveries delivery + JOIN agent_org_execution_turn_contexts context ON context.session_id=delivery.session_id AND context.turn_intent_id=delivery.turn_intent_id JOIN session_turn_intents intent ON intent.session_id=delivery.session_id AND intent.turn_intent_id=delivery.turn_intent_id - JOIN agent_org_runtime_runs run ON run.id=delivery.org_run_id - JOIN agent_org_runtime_inbox inbox ON inbox.id=delivery.source_inbox_id + JOIN agent_org_execution_runs run ON run.id=delivery.org_run_id + JOIN agent_org_execution_inbox inbox ON inbox.id=delivery.source_inbox_id WHERE delivery.status='pending' AND delivery.source_kind IN ('group_mention','member_inbox') AND context.turn_kind='user_directed_work' @@ -174,15 +174,15 @@ pub(crate) fn recoverable_pending_after( binding.org_run_id,'coordinator',binding.session_id, binding.turn_intent_id,binding.dispatch_content, binding.display_content,'[]' - FROM agent_org_runtime_user_directed_coordinator_bindings binding - JOIN agent_org_runtime_turn_contexts context + FROM agent_org_execution_user_directed_coordinator_bindings binding + JOIN agent_org_execution_turn_contexts context ON context.session_id=binding.session_id AND context.turn_intent_id=binding.turn_intent_id JOIN session_turn_intents intent ON intent.session_id=binding.session_id AND intent.turn_intent_id=binding.turn_intent_id - JOIN agent_org_runtime_runs run ON run.id=binding.org_run_id - JOIN agent_org_runtime_inbox inbox ON inbox.id=binding.source_inbox_id + JOIN agent_org_execution_runs run ON run.id=binding.org_run_id + JOIN agent_org_execution_inbox inbox ON inbox.id=binding.source_inbox_id WHERE binding.status='pending' AND context.turn_kind='coordinator' AND context.source_kind='member_inbox' diff --git a/src-tauri/crates/agent-core/src/core/coordination/agent_org_watchdog/budget.rs b/src-tauri/crates/agent-core/src/core/coordination/agent_org_watchdog/budget.rs index b418cbfe77..162c89a521 100644 --- a/src-tauri/crates/agent-core/src/core/coordination/agent_org_watchdog/budget.rs +++ b/src-tauri/crates/agent-core/src/core/coordination/agent_org_watchdog/budget.rs @@ -12,7 +12,7 @@ pub fn init_schema(conn: &Connection) -> rusqlite::Result<()> { pub(crate) fn create_schema(conn: &Connection) -> rusqlite::Result<()> { conn.execute_batch( - "CREATE TABLE IF NOT EXISTS agent_org_runtime_recovery_attempts ( + "CREATE TABLE IF NOT EXISTS agent_org_execution_recovery_attempts ( org_run_id TEXT NOT NULL, action_kind TEXT NOT NULL, target_key TEXT NOT NULL, @@ -23,8 +23,8 @@ pub(crate) fn create_schema(conn: &Connection) -> rusqlite::Result<()> { reservation_token TEXT, PRIMARY KEY (org_run_id, action_kind, target_key) ); - CREATE INDEX IF NOT EXISTS idx_agent_org_runtime_recovery_attempts_run - ON agent_org_runtime_recovery_attempts(org_run_id);", + CREATE INDEX IF NOT EXISTS idx_agent_org_execution_recovery_attempts_run + ON agent_org_execution_recovery_attempts(org_run_id);", ) } @@ -56,7 +56,7 @@ pub(super) fn budget_disposition_with_connection( let row: Option<(String, i64, String)> = conn .query_row( "SELECT reason_fingerprint, attempts, next_allowed_at - FROM agent_org_runtime_recovery_attempts + FROM agent_org_execution_recovery_attempts WHERE org_run_id=?1 AND action_kind=?2 AND target_key=?3", params![run_id, action_kind, target_key], |row| Ok((row.get(0)?, row.get(1)?, row.get(2)?)), @@ -129,7 +129,7 @@ pub(super) fn record_attempt_with_connection( ) -> Result<(), String> { let previous: Option<(String, i64)> = conn .query_row( - "SELECT reason_fingerprint, attempts FROM agent_org_runtime_recovery_attempts + "SELECT reason_fingerprint, attempts FROM agent_org_execution_recovery_attempts WHERE org_run_id=?1 AND action_kind=?2 AND target_key=?3", params![run_id, action_kind, target_key], |row| Ok((row.get(0)?, row.get(1)?)), @@ -147,7 +147,7 @@ pub(super) fn record_attempt_with_connection( let now = Utc::now(); let next = now + ChronoDuration::seconds(RECOVERY_DELAYS_SECS[delay_index]); conn.execute( - "INSERT INTO agent_org_runtime_recovery_attempts + "INSERT INTO agent_org_execution_recovery_attempts (org_run_id, action_kind, target_key, reason_fingerprint, attempts, next_allowed_at, updated_at) VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7) ON CONFLICT(org_run_id, action_kind, target_key) DO UPDATE SET @@ -174,7 +174,7 @@ pub fn clear_rewake_budget(run_id: &str, member_id: &str) -> Result<(), String> with_sessions_writer(|| { let conn = get_connection().map_err(|err| err.to_string())?; conn.execute( - "DELETE FROM agent_org_runtime_recovery_attempts + "DELETE FROM agent_org_execution_recovery_attempts WHERE org_run_id=?1 AND action_kind=?2 AND target_key=?3", params![run_id, MEMBER_REWAKE, member_id], ) @@ -227,7 +227,7 @@ pub(crate) fn task_failure_recovery_already_processed_with_connection( ) -> Result { conn.query_row( "SELECT EXISTS( - SELECT 1 FROM agent_org_runtime_recovery_attempts + SELECT 1 FROM agent_org_execution_recovery_attempts WHERE org_run_id=?1 AND action_kind=?2 AND target_key=?3 )", params![run_id, TASK_FAILURE_RECOVERY_EVENT, fingerprint], @@ -250,7 +250,7 @@ pub(crate) fn reserve_task_failure_recovery_with_connection( ) -> Result { let current_generation: i64 = conn .query_row( - "SELECT activation_generation FROM agent_org_runtime_runs + "SELECT activation_generation FROM agent_org_execution_runs WHERE id=?1 AND status='running'", [run_id], |row| row.get(0), @@ -265,7 +265,7 @@ pub(crate) fn reserve_task_failure_recovery_with_connection( let now = Utc::now().to_rfc3339(); let inserted = conn .execute( - "INSERT INTO agent_org_runtime_recovery_attempts( + "INSERT INTO agent_org_execution_recovery_attempts( org_run_id,action_kind,target_key,reason_fingerprint,attempts, next_allowed_at,updated_at,reservation_token ) VALUES (?1,?2,?3,?3,1,?4,?4,NULL) @@ -279,7 +279,7 @@ pub(crate) fn reserve_task_failure_recovery_with_connection( let previous_attempts: i64 = conn .query_row( - "SELECT attempts FROM agent_org_runtime_recovery_attempts + "SELECT attempts FROM agent_org_execution_recovery_attempts WHERE org_run_id=?1 AND action_kind=?2 AND target_key=?3", params![run_id, TASK_FAILURE_RECOVERY, task_id], |row| row.get(0), @@ -292,7 +292,7 @@ pub(crate) fn reserve_task_failure_recovery_with_connection( let exhausted = task_failure_recovery_attempts_exhausted(attempts); let token = uuid::Uuid::new_v4().to_string(); conn.execute( - "INSERT INTO agent_org_runtime_recovery_attempts( + "INSERT INTO agent_org_execution_recovery_attempts( org_run_id,action_kind,target_key,reason_fingerprint,attempts, next_allowed_at,updated_at,reservation_token ) VALUES (?1,?2,?3,?4,?5,?6,?6,?7) @@ -340,7 +340,7 @@ fn reserve_task_system_operation( .map_err(|error| error.to_string())?; let generation: i64 = tx .query_row( - "SELECT activation_generation FROM agent_org_runtime_runs + "SELECT activation_generation FROM agent_org_execution_runs WHERE id=?1 AND status='running'", params![run_id], |row| row.get(0), @@ -350,7 +350,7 @@ fn reserve_task_system_operation( .ok_or_else(|| format!("agent_org_run_not_mutable: {run_id}"))?; let previous_attempts: i64 = tx .query_row( - "SELECT attempts FROM agent_org_runtime_recovery_attempts + "SELECT attempts FROM agent_org_execution_recovery_attempts WHERE org_run_id=?1 AND action_kind=?2 AND target_key=?3", params![run_id, action_kind, target_key], |row| row.get(0), @@ -368,7 +368,7 @@ fn reserve_task_system_operation( let token = uuid::Uuid::new_v4().to_string(); let now = Utc::now().to_rfc3339(); tx.execute( - "INSERT INTO agent_org_runtime_recovery_attempts( + "INSERT INTO agent_org_execution_recovery_attempts( org_run_id,action_kind,target_key,reason_fingerprint,attempts, next_allowed_at,updated_at,reservation_token ) VALUES (?1,?2,?3,?4,?5,?6,?6,?7) diff --git a/src-tauri/crates/agent-core/src/core/coordination/agent_org_watchdog/reservation.rs b/src-tauri/crates/agent-core/src/core/coordination/agent_org_watchdog/reservation.rs index f0839ad447..029e8356f0 100644 --- a/src-tauri/crates/agent-core/src/core/coordination/agent_org_watchdog/reservation.rs +++ b/src-tauri/crates/agent-core/src/core/coordination/agent_org_watchdog/reservation.rs @@ -65,7 +65,7 @@ pub(crate) fn reserve_member_rewake_dispatch( .query_row( "SELECT reason_fingerprint, attempts, next_allowed_at, updated_at, reservation_token - FROM agent_org_runtime_recovery_attempts + FROM agent_org_execution_recovery_attempts WHERE org_run_id=?1 AND action_kind=?2 AND target_key=?3", params![run_id, MEMBER_REWAKE, member_id], |row| { @@ -84,7 +84,7 @@ pub(crate) fn reserve_member_rewake_dispatch( let token = uuid::Uuid::new_v4().to_string(); let updated = tx .execute( - "UPDATE agent_org_runtime_recovery_attempts + "UPDATE agent_org_execution_recovery_attempts SET reservation_token=?1 WHERE org_run_id=?2 AND action_kind=?3 AND target_key=?4 AND reason_fingerprint=?5", @@ -113,7 +113,7 @@ pub(crate) fn commit_member_rewake_reservation( with_sessions_writer(|| -> Result<(), String> { let conn = get_connection().map_err(|err| err.to_string())?; conn.execute( - "UPDATE agent_org_runtime_recovery_attempts + "UPDATE agent_org_execution_recovery_attempts SET reservation_token=NULL WHERE org_run_id=?1 AND action_kind=?2 AND target_key=?3 AND reservation_token=?4", @@ -141,7 +141,7 @@ pub(crate) fn refund_member_rewake_reservation( let owns_current: bool = tx .query_row( "SELECT EXISTS( - SELECT 1 FROM agent_org_runtime_recovery_attempts + SELECT 1 FROM agent_org_execution_recovery_attempts WHERE org_run_id=?1 AND action_kind=?2 AND target_key=?3 AND reservation_token=?4 )", @@ -168,7 +168,7 @@ pub(crate) fn refund_member_rewake_reservation( .filter(|p| p.reservation_token.is_none()) { tx.execute( - "UPDATE agent_org_runtime_recovery_attempts + "UPDATE agent_org_execution_recovery_attempts SET reason_fingerprint=?1, attempts=?2, next_allowed_at=?3, updated_at=?4, reservation_token=?5 WHERE org_run_id=?6 AND action_kind=?7 AND target_key=?8 @@ -188,7 +188,7 @@ pub(crate) fn refund_member_rewake_reservation( .map_err(|err| err.to_string())?; } else { tx.execute( - "DELETE FROM agent_org_runtime_recovery_attempts + "DELETE FROM agent_org_execution_recovery_attempts WHERE org_run_id=?1 AND action_kind=?2 AND target_key=?3 AND reservation_token=?4", params![ diff --git a/src-tauri/crates/agent-core/src/core/coordination/agent_org_watchdog/tests/doorbell_repair_tests.rs b/src-tauri/crates/agent-core/src/core/coordination/agent_org_watchdog/tests/doorbell_repair_tests.rs index acff527e7e..fd3938078d 100644 --- a/src-tauri/crates/agent-core/src/core/coordination/agent_org_watchdog/tests/doorbell_repair_tests.rs +++ b/src-tauri/crates/agent-core/src/core/coordination/agent_org_watchdog/tests/doorbell_repair_tests.rs @@ -48,10 +48,10 @@ fn five_ticks_repair_only_the_original_receipt_once() { let state: (String, String, i64, i64) = conn .query_row( "SELECT receipt.status,receipt.doorbell_status, - (SELECT COUNT(*) FROM agent_org_runtime_inbox), + (SELECT COUNT(*) FROM agent_org_execution_inbox), progress.work_revision - FROM agent_org_runtime_formal_trigger_receipts receipt - JOIN agent_org_runtime_run_progress progress + FROM agent_org_execution_formal_trigger_receipts receipt + JOIN agent_org_execution_run_progress progress ON progress.org_run_id=receipt.org_run_id WHERE receipt.receipt_id=?1", [&receipt_id], @@ -91,16 +91,16 @@ fn ready_assigned_task_gets_one_replacement_doorbell_without_owner_or_task_mutat let state: (String, String, i64, i64, i64) = conn .query_row( "SELECT task.status,task.owner, - (SELECT COUNT(*) FROM agent_org_runtime_tasks + (SELECT COUNT(*) FROM agent_org_execution_tasks WHERE org_run_id=task.org_run_id), - (SELECT COUNT(*) FROM agent_org_runtime_inbox + (SELECT COUNT(*) FROM agent_org_execution_inbox WHERE org_run_id=task.org_run_id AND recipient_member_id='worker' AND payload_kind='task_assigned'), - (SELECT COUNT(*) FROM agent_org_runtime_recovery_attempts + (SELECT COUNT(*) FROM agent_org_execution_recovery_attempts WHERE org_run_id=task.org_run_id AND action_kind='task_assignment_doorbell_repair_event') - FROM agent_org_runtime_tasks task + FROM agent_org_execution_tasks task WHERE task.org_run_id=?1 AND task.id='assigned-with-lost-doorbell'", [&fixture.run_id], |row| { @@ -141,8 +141,8 @@ fn paused_idle_and_archived_teams_never_receive_assignment_repairs() { let side_effects: (i64, i64) = conn .query_row( "SELECT - (SELECT COUNT(*) FROM agent_org_runtime_inbox WHERE org_run_id=?1), - (SELECT COUNT(*) FROM agent_org_runtime_recovery_attempts WHERE org_run_id=?1)", + (SELECT COUNT(*) FROM agent_org_execution_inbox WHERE org_run_id=?1), + (SELECT COUNT(*) FROM agent_org_execution_recovery_attempts WHERE org_run_id=?1)", [&fixture.run_id], |row| Ok((row.get(0)?, row.get(1)?)), ) @@ -166,7 +166,7 @@ fn unaccepted_wake_keeps_confirmation_missing_for_next_tick() { let doorbell: String = conn .query_row( "SELECT doorbell_status - FROM agent_org_runtime_formal_trigger_receipts + FROM agent_org_execution_formal_trigger_receipts WHERE receipt_id=?1", [&receipt_id], |row| row.get(0), @@ -184,14 +184,14 @@ fn missing_doorbell_scan_uses_the_partial_index() { let mut stmt = conn .prepare( "EXPLAIN QUERY PLAN - SELECT receipt_id FROM agent_org_runtime_formal_trigger_receipts receipt + SELECT receipt_id FROM agent_org_execution_formal_trigger_receipts receipt WHERE receipt.status='pending' AND receipt.doorbell_status='missing' AND EXISTS ( - SELECT 1 FROM agent_org_runtime_runs run + SELECT 1 FROM agent_org_execution_runs run WHERE run.id=receipt.org_run_id AND run.status='running' ) AND NOT EXISTS ( - SELECT 1 FROM agent_org_runtime_formal_trigger_attempts attempt + SELECT 1 FROM agent_org_execution_formal_trigger_attempts attempt WHERE attempt.receipt_id=receipt.receipt_id AND attempt.status IN ('queued','running') ) @@ -204,9 +204,9 @@ fn missing_doorbell_scan_uses_the_partial_index() { .unwrap() }; assert!( - details - .iter() - .any(|detail| detail.contains("idx_agent_org_formal_trigger_missing_doorbell")), + details.iter().any( + |detail| detail.contains("idx_agent_org_execution_formal_trigger_missing_doorbell") + ), "query plan did not use the missing-doorbell index: {details:?}" ); } diff --git a/src-tauri/crates/agent-core/src/core/coordination/agent_org_watchdog/tests/fixture.rs b/src-tauri/crates/agent-core/src/core/coordination/agent_org_watchdog/tests/fixture.rs index 69736edd14..5c82254548 100644 --- a/src-tauri/crates/agent-core/src/core/coordination/agent_org_watchdog/tests/fixture.rs +++ b/src-tauri/crates/agent-core/src/core/coordination/agent_org_watchdog/tests/fixture.rs @@ -102,7 +102,7 @@ impl WatchdogFixture { let conn = get_connection().expect("watchdog fixture database"); let now = chrono::Utc::now().to_rfc3339(); conn.execute( - "INSERT INTO agent_org_runtime_member_materializations( + "INSERT INTO agent_org_execution_member_materializations( org_run_id,member_id,agent_id,generation,session_id, authority_class,status,created_at,updated_at ) VALUES (?1,'worker','worker-agent',1,'watchdog-worker-session', @@ -130,7 +130,7 @@ impl WatchdogFixture { pub(super) fn set_run_status(&self, status: AgentOrgRunStatus) { let conn = get_connection().expect("watchdog fixture database"); conn.execute( - "UPDATE agent_org_runtime_runs + "UPDATE agent_org_execution_runs SET status=?2, archived_at=CASE WHEN ?2='archived' THEN ?3 ELSE NULL END, archive_receipt_id=CASE WHEN ?2='archived' THEN 'watchdog-archive-receipt' ELSE NULL END diff --git a/src-tauri/crates/agent-core/src/core/coordination/agent_org_work_episodes.rs b/src-tauri/crates/agent-core/src/core/coordination/agent_org_work_episodes.rs index e045407432..39ea79f523 100644 --- a/src-tauri/crates/agent-core/src/core/coordination/agent_org_work_episodes.rs +++ b/src-tauri/crates/agent-core/src/core/coordination/agent_org_work_episodes.rs @@ -22,7 +22,7 @@ pub(crate) struct AgentOrgWorkEpisode { pub(crate) fn create_schema(conn: &Connection) -> rusqlite::Result<()> { conn.execute_batch( - "CREATE TABLE IF NOT EXISTS agent_org_runtime_work_episodes ( + "CREATE TABLE IF NOT EXISTS agent_org_execution_work_episodes ( id TEXT PRIMARY KEY, org_run_id TEXT NOT NULL, episode_sequence INTEGER NOT NULL CHECK(episode_sequence >= 1), @@ -39,7 +39,7 @@ pub(crate) fn create_schema(conn: &Connection) -> rusqlite::Result<()> { created_at TEXT NOT NULL, closed_at TEXT, UNIQUE(org_run_id, episode_sequence), - FOREIGN KEY (org_run_id) REFERENCES agent_org_runtime_runs(id) ON DELETE CASCADE, + FOREIGN KEY (org_run_id) REFERENCES agent_org_execution_runs(id) ON DELETE CASCADE, CHECK( (status='active' AND closing_activation_generation IS NULL AND closing_work_revision IS NULL AND outcome IS NULL @@ -50,24 +50,24 @@ pub(crate) fn create_schema(conn: &Connection) -> rusqlite::Result<()> { AND certificate_id IS NOT NULL AND closed_at IS NOT NULL) ) ); - CREATE UNIQUE INDEX IF NOT EXISTS idx_agent_org_runtime_work_episodes_active - ON agent_org_runtime_work_episodes(org_run_id) WHERE status='active'; - CREATE INDEX IF NOT EXISTS idx_agent_org_runtime_work_episodes_current - ON agent_org_runtime_work_episodes(org_run_id, episode_sequence DESC); - CREATE TABLE IF NOT EXISTS agent_org_runtime_work_episode_tasks ( + CREATE UNIQUE INDEX IF NOT EXISTS idx_agent_org_execution_work_episodes_active + ON agent_org_execution_work_episodes(org_run_id) WHERE status='active'; + CREATE INDEX IF NOT EXISTS idx_agent_org_execution_work_episodes_current + ON agent_org_execution_work_episodes(org_run_id, episode_sequence DESC); + CREATE TABLE IF NOT EXISTS agent_org_execution_work_episode_tasks ( org_run_id TEXT NOT NULL, work_episode_id TEXT NOT NULL, task_id TEXT NOT NULL, associated_at TEXT NOT NULL, PRIMARY KEY (org_run_id, task_id), FOREIGN KEY (work_episode_id) - REFERENCES agent_org_runtime_work_episodes(id) ON DELETE CASCADE, - FOREIGN KEY (org_run_id) REFERENCES agent_org_runtime_runs(id) ON DELETE CASCADE, + REFERENCES agent_org_execution_work_episodes(id) ON DELETE CASCADE, + FOREIGN KEY (org_run_id) REFERENCES agent_org_execution_runs(id) ON DELETE CASCADE, FOREIGN KEY (org_run_id, task_id) - REFERENCES agent_org_runtime_tasks(org_run_id, id) ON DELETE CASCADE + REFERENCES agent_org_execution_tasks(org_run_id, id) ON DELETE CASCADE ); - CREATE INDEX IF NOT EXISTS idx_agent_org_runtime_work_episode_tasks_episode - ON agent_org_runtime_work_episode_tasks(org_run_id, work_episode_id, task_id);", + CREATE INDEX IF NOT EXISTS idx_agent_org_execution_work_episode_tasks_episode + ON agent_org_execution_work_episode_tasks(org_run_id, work_episode_id, task_id);", ) } @@ -89,7 +89,7 @@ pub(crate) fn active_with_connection( conn.query_row( "SELECT id,episode_sequence,opening_activation_generation, closing_activation_generation,certificate_id,opened_by_turn_intent_id - FROM agent_org_runtime_work_episodes + FROM agent_org_execution_work_episodes WHERE org_run_id=?1 AND status='active'", [org_run_id], decode_episode, @@ -105,7 +105,7 @@ pub(crate) fn current_with_connection( conn.query_row( "SELECT id,episode_sequence,opening_activation_generation, closing_activation_generation,certificate_id,opened_by_turn_intent_id - FROM agent_org_runtime_work_episodes + FROM agent_org_execution_work_episodes WHERE org_run_id=?1 ORDER BY episode_sequence DESC LIMIT 1", [org_run_id], @@ -147,14 +147,14 @@ pub(crate) fn ensure_active_in_tx( return Err("agent_org_work_episode_identity_invalid".to_string()); } conn.execute( - "INSERT INTO agent_org_runtime_run_progress(org_run_id,updated_at) + "INSERT INTO agent_org_execution_run_progress(org_run_id,updated_at) VALUES (?1,?2) ON CONFLICT(org_run_id) DO NOTHING", params![org_run_id, chrono::Utc::now().to_rfc3339()], ) .map_err(|error| error.to_string())?; let work_revision: i64 = conn .query_row( - "SELECT work_revision FROM agent_org_runtime_run_progress WHERE org_run_id=?1", + "SELECT work_revision FROM agent_org_execution_run_progress WHERE org_run_id=?1", [org_run_id], |row| row.get(0), ) @@ -162,7 +162,7 @@ pub(crate) fn ensure_active_in_tx( let id = format!("work-episode-{}", uuid::Uuid::new_v4()); let now = chrono::Utc::now().to_rfc3339(); conn.execute( - "INSERT INTO agent_org_runtime_work_episodes ( + "INSERT INTO agent_org_execution_work_episodes ( id,org_run_id,episode_sequence,status,opening_activation_generation, opening_work_revision,opened_by_turn_intent_id,created_at ) VALUES (?1,?2,?3,'active',?4,?5,?6,?7)", @@ -222,10 +222,10 @@ fn is_new_user_root_turn( "SELECT EXISTS( SELECT 1 FROM session_turn_intents intent - JOIN agent_org_runtime_turn_contexts context + JOIN agent_org_execution_turn_contexts context ON context.session_id=intent.session_id AND context.turn_intent_id=intent.turn_intent_id - JOIN agent_org_runtime_runs run ON run.id=context.org_run_id + JOIN agent_org_execution_runs run ON run.id=context.org_run_id WHERE context.org_run_id=?1 AND context.turn_intent_id=?2 AND context.turn_kind='coordinator' AND intent.session_id=run.root_session_id @@ -259,7 +259,7 @@ pub(crate) fn associate_task_in_tx( opened_by_turn_intent_id, )?; conn.execute( - "INSERT INTO agent_org_runtime_work_episode_tasks ( + "INSERT INTO agent_org_execution_work_episode_tasks ( org_run_id,work_episode_id,task_id,associated_at ) VALUES (?1,?2,?3,?4)", params![ @@ -284,8 +284,8 @@ pub(crate) fn associate_replacement_task_in_tx( let source_episode = conn .query_row( "SELECT episode.id,episode.status - FROM agent_org_runtime_work_episode_tasks association - JOIN agent_org_runtime_work_episodes episode + FROM agent_org_execution_work_episode_tasks association + JOIN agent_org_execution_work_episodes episode ON episode.org_run_id=association.org_run_id AND episode.id=association.work_episode_id WHERE association.org_run_id=?1 AND association.task_id=?2 @@ -310,7 +310,7 @@ pub(crate) fn associate_replacement_task_in_tx( return Err("agent_org_work_episode_replacement_source_invalid".to_string()); }; conn.execute( - "INSERT INTO agent_org_runtime_work_episode_tasks ( + "INSERT INTO agent_org_execution_work_episode_tasks ( org_run_id,work_episode_id,task_id,associated_at ) VALUES (?1,?2,?3,?4)", params![ @@ -331,7 +331,7 @@ pub(crate) fn task_ids_with_connection( ) -> Result, String> { let mut statement = conn .prepare( - "SELECT task_id FROM agent_org_runtime_work_episode_tasks + "SELECT task_id FROM agent_org_execution_work_episode_tasks WHERE org_run_id=?1 AND work_episode_id=?2 ORDER BY task_id", ) .map_err(|error| error.to_string())?; @@ -348,9 +348,9 @@ pub(crate) fn unassociated_task_count_with_connection( org_run_id: &str, ) -> Result { conn.query_row( - "SELECT COUNT(*) FROM agent_org_runtime_tasks task + "SELECT COUNT(*) FROM agent_org_execution_tasks task WHERE task.org_run_id=?1 AND NOT EXISTS( - SELECT 1 FROM agent_org_runtime_work_episode_tasks episode_task + SELECT 1 FROM agent_org_execution_work_episode_tasks episode_task WHERE episode_task.org_run_id=task.org_run_id AND episode_task.task_id=task.id )", @@ -376,7 +376,7 @@ pub(crate) fn close_active_in_tx( ) -> Result<(), String> { let changed = conn .execute( - "UPDATE agent_org_runtime_work_episodes + "UPDATE agent_org_execution_work_episodes SET status='certified',closing_activation_generation=?1, closing_work_revision=?2,outcome=?3,certificate_id=?4,closed_at=?5 WHERE id=?6 AND org_run_id=?7 AND status='active'", diff --git a/src-tauri/crates/agent-core/src/core/coordination/agent_org_work_episodes/tests.rs b/src-tauri/crates/agent-core/src/core/coordination/agent_org_work_episodes/tests.rs index bece6c7e66..8cb7d415bf 100644 --- a/src-tauri/crates/agent-core/src/core/coordination/agent_org_work_episodes/tests.rs +++ b/src-tauri/crates/agent-core/src/core/coordination/agent_org_work_episodes/tests.rs @@ -24,7 +24,7 @@ fn fixture() -> Connection { create_schema(&conn).unwrap(); crate::coordination::agent_org_tasks::create_schema(&conn).unwrap(); conn.execute_batch( - "INSERT INTO agent_org_runtime_runs( + "INSERT INTO agent_org_execution_runs( id,org_id,coordinator_agent_id,root_session_id,entry_mode,status, activation_generation,created_at,updated_at ) VALUES ('run','org','coordinator','root','standalone_session','running',1, @@ -43,7 +43,7 @@ fn insert_root_turn(conn: &Connection, turn_id: &str, source: &str, generation: ) .unwrap(); conn.execute( - "INSERT INTO agent_org_runtime_turn_contexts( + "INSERT INTO agent_org_execution_turn_contexts( session_id,turn_intent_id,org_run_id,participant_id,turn_kind, source_kind,source_id,activation_generation,created_at ) VALUES ('root',?1,'run','coordinator','coordinator', @@ -55,7 +55,7 @@ fn insert_root_turn(conn: &Connection, turn_id: &str, source: &str, generation: fn insert_task(conn: &Connection, task_id: &str, generation: i64, turn_id: &str) { conn.execute( - "INSERT INTO agent_org_runtime_tasks( + "INSERT INTO agent_org_execution_tasks( id,org_run_id,activation_generation,subject,status,execution_mode, created_by_participant_id,source_turn_intent_id,created_at,updated_at ) VALUES (?1,'run',?2,?1,'pending','build','coordinator',?3,?4,?4)", @@ -74,7 +74,7 @@ fn pause_resume_keeps_one_episode_and_next_mission_opens_another() { // Pause/Resume advances authorization but must not split the mission. conn.execute( - "UPDATE agent_org_runtime_runs SET activation_generation=3 WHERE id='run'", + "UPDATE agent_org_execution_runs SET activation_generation=3 WHERE id='run'", [], ) .unwrap(); @@ -101,7 +101,7 @@ fn pause_resume_keeps_one_episode_and_next_mission_opens_another() { ) .unwrap(); conn.execute( - "UPDATE agent_org_runtime_runs SET activation_generation=4 WHERE id='run'", + "UPDATE agent_org_execution_runs SET activation_generation=4 WHERE id='run'", [], ) .unwrap(); @@ -200,7 +200,7 @@ fn terminal_replacement_after_certification_opens_the_next_episode() { .unwrap(); conn.execute( - "UPDATE agent_org_runtime_runs SET activation_generation=2 WHERE id='run'", + "UPDATE agent_org_execution_runs SET activation_generation=2 WHERE id='run'", [], ) .unwrap(); diff --git a/src-tauri/crates/agent-core/src/core/coordination/fixtures/background_history_agent_org.sql b/src-tauri/crates/agent-core/src/core/coordination/fixtures/background_history_agent_org.sql new file mode 100644 index 0000000000..361c64ab06 --- /dev/null +++ b/src-tauri/crates/agent-core/src/core/coordination/fixtures/background_history_agent_org.sql @@ -0,0 +1,1405 @@ +-- Frozen SQLite DDL validated against the production fingerprint at +-- 6968a34d529c5e4c627e91b647bdd38b17139075 and 22767a2a4f3185b127bf6d5669302cffcbe6dce4. +-- Runtime fingerprint: d96f244c1ddb4293c82109cf8dc4ca0a41179f4aa464a22b81c69ffe65f9313c +-- Includes six companion tables. Test-only upgrade input; contains no user data. + +CREATE TABLE agent_org_coordinator_completion_rechecks ( + org_run_id TEXT NOT NULL, + source_session_id TEXT NOT NULL, + source_turn_intent_id TEXT NOT NULL, + activation_generation INTEGER NOT NULL, + work_revision INTEGER NOT NULL, + status TEXT NOT NULL CHECK(status IN ('pending','materialized','resolved')), + inbox_id INTEGER, + created_at TEXT NOT NULL, + updated_at TEXT NOT NULL, + PRIMARY KEY(org_run_id,source_session_id,source_turn_intent_id), + FOREIGN KEY(inbox_id) REFERENCES agent_org_runtime_inbox(id) ON DELETE SET NULL + ); + +CREATE TABLE agent_org_member_turn_admissions ( + session_id TEXT NOT NULL, + turn_intent_id TEXT NOT NULL, + org_run_id TEXT NOT NULL, + member_id TEXT NOT NULL CHECK(length(trim(member_id)) > 0), + reservation_id TEXT NOT NULL CHECK(length(trim(reservation_id)) > 0), + runtime_lease_id TEXT NOT NULL CHECK(length(trim(runtime_lease_id)) > 0), + status TEXT NOT NULL CHECK(status IN ( + 'prepared','committed','rejected','unknown' + )), + reason_code TEXT, + prepared_at TEXT NOT NULL, + committed_at TEXT, + terminal_at TEXT, + updated_at TEXT NOT NULL, + PRIMARY KEY(session_id, turn_intent_id), + UNIQUE(reservation_id), + FOREIGN KEY(session_id, turn_intent_id) + REFERENCES session_turn_intents(session_id, turn_intent_id) + ON DELETE CASCADE, + FOREIGN KEY(org_run_id) + REFERENCES agent_org_runtime_runs(id) ON DELETE CASCADE, + CHECK( + (status='prepared' AND committed_at IS NULL AND terminal_at IS NULL) + OR (status='committed' AND committed_at IS NOT NULL AND terminal_at IS NULL) + OR (status IN ('rejected','unknown') AND terminal_at IS NOT NULL) + ) + ); + +CREATE TABLE agent_org_runtime_archive_episodes ( + archive_receipt_id TEXT PRIMARY KEY CHECK(length(trim(archive_receipt_id)) > 0), + org_run_id TEXT NOT NULL UNIQUE, + archive_request_id TEXT NOT NULL CHECK(length(trim(archive_request_id)) > 0), + archive_generation INTEGER NOT NULL CHECK(archive_generation >= 2), + teardown_status TEXT NOT NULL CHECK(teardown_status IN ( + 'pending','quiesced','retained_runtime' + )), + teardown_attempt_count INTEGER NOT NULL DEFAULT 0 + CHECK(teardown_attempt_count BETWEEN 0 AND 3), + retained_runtime_count INTEGER NOT NULL DEFAULT 0 + CHECK(retained_runtime_count >= 0), + task_cancel_count INTEGER NOT NULL DEFAULT 0 CHECK(task_cancel_count >= 0), + turn_cancel_count INTEGER NOT NULL DEFAULT 0 CHECK(turn_cancel_count >= 0), + inbox_cancel_count INTEGER NOT NULL DEFAULT 0 CHECK(inbox_cancel_count >= 0), + approval_cancel_count INTEGER NOT NULL DEFAULT 0 CHECK(approval_cancel_count >= 0), + intervention_cancel_count INTEGER NOT NULL DEFAULT 0 CHECK(intervention_cancel_count >= 0), + pause_continuation_cancel_count INTEGER NOT NULL DEFAULT 0 + CHECK(pause_continuation_cancel_count >= 0), + deadline_at TEXT NOT NULL, + last_error TEXT, + archived_at TEXT NOT NULL, + updated_at TEXT NOT NULL, + quiesced_at TEXT, + UNIQUE(org_run_id, archive_request_id), + FOREIGN KEY(org_run_id) REFERENCES agent_org_runtime_runs(id) ON DELETE CASCADE, + CHECK( + (teardown_status='quiesced' AND quiesced_at IS NOT NULL + AND retained_runtime_count=0) + OR + (teardown_status<>'quiesced' AND quiesced_at IS NULL) + ) + ); + +CREATE TABLE agent_org_runtime_archive_teardowns ( + teardown_id TEXT PRIMARY KEY CHECK(length(trim(teardown_id)) > 0), + archive_receipt_id TEXT NOT NULL, + org_run_id TEXT NOT NULL, + session_id TEXT NOT NULL, + member_id TEXT, + captured_parent_session_id TEXT, + teardown_status TEXT NOT NULL CHECK(teardown_status IN ( + 'pending','quiesced','retained_runtime' + )), + attempt_count INTEGER NOT NULL DEFAULT 0 CHECK(attempt_count BETWEEN 0 AND 3), + runtime_lease_id TEXT, + dialog_turn_generation TEXT, + last_error TEXT, + released_at TEXT, + created_at TEXT NOT NULL, + updated_at TEXT NOT NULL, + UNIQUE(archive_receipt_id, session_id), + FOREIGN KEY(archive_receipt_id) + REFERENCES agent_org_runtime_archive_episodes(archive_receipt_id) ON DELETE CASCADE, + FOREIGN KEY(org_run_id) REFERENCES agent_org_runtime_runs(id) ON DELETE CASCADE, + CHECK( + (teardown_status='quiesced' AND released_at IS NOT NULL) + OR + (teardown_status<>'quiesced' AND released_at IS NULL) + ), + CHECK( + (runtime_lease_id IS NULL AND dialog_turn_generation IS NULL) + OR runtime_lease_id IS NOT NULL + ) + ); + +CREATE TABLE agent_org_runtime_final_summary_receipts ( + receipt_id TEXT PRIMARY KEY, + org_run_id TEXT NOT NULL, + activation_generation INTEGER NOT NULL CHECK(activation_generation >= 1), + certificate_id TEXT NOT NULL, + evidence_digest TEXT NOT NULL CHECK(length(evidence_digest)=64), + attempt INTEGER NOT NULL CHECK(attempt >= 1), + status TEXT NOT NULL CHECK(status IN ( + 'pending','running','persisting','persisted','failed' + )), + coordinator_session_id TEXT NOT NULL CHECK(trim(coordinator_session_id) <> ''), + turn_intent_id TEXT, + retry_request_id TEXT, + started_at TEXT, + terminal_at TEXT, + event_id TEXT, + typed_error TEXT, + created_at TEXT NOT NULL, + updated_at TEXT NOT NULL, + UNIQUE(certificate_id,attempt), + UNIQUE(certificate_id,retry_request_id), + FOREIGN KEY(org_run_id) REFERENCES agent_org_runtime_runs(id) ON DELETE CASCADE, + FOREIGN KEY(certificate_id) + REFERENCES agent_org_runtime_run_completion_certificates(id) + ON DELETE CASCADE, + CHECK((status='pending' AND turn_intent_id IS NULL AND started_at IS NULL) + OR (status IN ('running','persisting','persisted','failed') + AND turn_intent_id IS NOT NULL AND started_at IS NOT NULL)), + CHECK((status IN ('persisted','failed'))=(terminal_at IS NOT NULL)), + CHECK((status='persisted')=(event_id IS NOT NULL)), + CHECK((status='failed')=(typed_error IS NOT NULL)) + ); + +CREATE TABLE agent_org_runtime_formal_trigger_attempts ( + receipt_id TEXT NOT NULL, + attempt INTEGER NOT NULL CHECK(attempt >= 1), + session_id TEXT NOT NULL, + turn_intent_id TEXT NOT NULL, + status TEXT NOT NULL CHECK(status IN ('queued','running','failed','resolved')), + materialized_input_id TEXT NOT NULL, + materialized_event_id TEXT, + typed_error TEXT, + queued_at TEXT NOT NULL, + started_at TEXT, + terminal_at TEXT, + updated_at TEXT NOT NULL, + PRIMARY KEY(receipt_id,attempt), + FOREIGN KEY(receipt_id) + REFERENCES agent_org_runtime_formal_trigger_receipts(receipt_id) + ON DELETE CASCADE + ); + +CREATE TABLE agent_org_runtime_formal_trigger_receipts ( + receipt_id TEXT PRIMARY KEY, + org_run_id TEXT NOT NULL, + trigger_kind TEXT NOT NULL, + trigger_id TEXT NOT NULL, + trigger_revision INTEGER NOT NULL CHECK(trigger_revision >= 1), + source_kind TEXT NOT NULL, + target_member_id TEXT NOT NULL CHECK(target_member_id='coordinator'), + inbox_id INTEGER, + task_id TEXT, + owner_member_id TEXT, + source_turn_intent_id TEXT, + task_output_digest TEXT CHECK( + task_output_digest IS NULL OR length(task_output_digest)=64 + ), + plan_revision_id TEXT, + status TEXT NOT NULL CHECK(status IN ('pending','materialized','resolved')), + doorbell_status TEXT NOT NULL CHECK(doorbell_status IN ('missing','delivered','suppressed')), + doorbell_delivered_at TEXT, + current_attempt INTEGER NOT NULL DEFAULT 0 CHECK(current_attempt >= 0), + materialized_input_id TEXT, + materialized_event_id TEXT, + resolved_at TEXT, + created_at TEXT NOT NULL, + updated_at TEXT NOT NULL, + UNIQUE(org_run_id,trigger_kind,trigger_id,trigger_revision), + UNIQUE(inbox_id), + FOREIGN KEY(org_run_id) REFERENCES agent_org_runtime_runs(id) ON DELETE CASCADE, + FOREIGN KEY(inbox_id) REFERENCES agent_org_runtime_inbox(id) ON DELETE CASCADE + ); + +CREATE TABLE agent_org_runtime_inbox ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + delivery_class TEXT NOT NULL DEFAULT 'formal_work' + CHECK(delivery_class IN ('formal_work','user_directed')), + recipient_agent_id TEXT NOT NULL, + recipient_member_id TEXT, + sender_agent_id TEXT NOT NULL, + sender_member_id TEXT, + org_run_id TEXT, + payload_kind TEXT NOT NULL, + payload_json TEXT NOT NULL, + request_id TEXT, + created_at TEXT NOT NULL, + read_at TEXT, + causation_inbox_id INTEGER, + display_text TEXT, + client_message_id TEXT + ,source_turn_intent_id TEXT + ); + +CREATE TABLE agent_org_runtime_inbox_delivery_resolutions ( + inbox_id INTEGER PRIMARY KEY, + org_run_id TEXT NOT NULL, + resolution_kind TEXT NOT NULL + CHECK(resolution_kind IN ('cancelled', 'superseded', 'system_reconciled')), + resolved_by_member_id TEXT NOT NULL, + reason TEXT NOT NULL, + replacement_inbox_id INTEGER, + replacement_task_id TEXT, + created_at TEXT NOT NULL, + CHECK( + (resolution_kind IN ('cancelled','system_reconciled') + AND replacement_inbox_id IS NULL + AND replacement_task_id IS NULL) + OR + (resolution_kind='superseded' + AND ((replacement_inbox_id IS NOT NULL) + <> (replacement_task_id IS NOT NULL))) + ) + ); + +CREATE TABLE agent_org_runtime_inbox_materializations ( + inbox_id INTEGER PRIMARY KEY, + session_id TEXT NOT NULL, + transcript_message_id TEXT NOT NULL, + transcript_intent_id TEXT NOT NULL, + materialized_at TEXT NOT NULL + ); + +CREATE TABLE agent_org_runtime_inbox_task_bindings ( + inbox_id INTEGER PRIMARY KEY, + org_run_id TEXT NOT NULL, + task_id TEXT NOT NULL, + recipient_member_id TEXT NOT NULL, + binding_kind TEXT NOT NULL CHECK(binding_kind='coordinator_task_message'), + source_turn_intent_id TEXT NOT NULL, + created_at TEXT NOT NULL, + FOREIGN KEY(inbox_id) + REFERENCES agent_org_runtime_inbox(id) ON DELETE CASCADE, + FOREIGN KEY(org_run_id,task_id) + REFERENCES agent_org_runtime_tasks(org_run_id,id) ON DELETE CASCADE + ); + +CREATE TABLE agent_org_runtime_initial_inputs ( + org_run_id TEXT PRIMARY KEY, + turn_intent_id TEXT NOT NULL, + message_id TEXT NOT NULL, + content TEXT NOT NULL, + payload_json TEXT NOT NULL, + status TEXT NOT NULL CHECK(status IN ( + 'pending_persistence', 'queued', 'dispatched' + )), + created_at TEXT NOT NULL, + updated_at TEXT NOT NULL, + UNIQUE(turn_intent_id), + UNIQUE(message_id), + FOREIGN KEY(org_run_id) REFERENCES agent_org_runtime_runs(id) ON DELETE CASCADE + ); + +CREATE TABLE agent_org_runtime_member_dispatch_allocators ( + org_run_id TEXT NOT NULL, + member_id TEXT NOT NULL CHECK(length(trim(member_id)) > 0), + next_sequence INTEGER NOT NULL CHECK(next_sequence >= 1), + PRIMARY KEY(org_run_id, member_id), + FOREIGN KEY(org_run_id) REFERENCES agent_org_runtime_runs(id) ON DELETE CASCADE + ); + +CREATE TABLE agent_org_runtime_member_intervention_turns ( + intervention_receipt_id TEXT NOT NULL, + session_id TEXT NOT NULL, + turn_intent_id TEXT NOT NULL, + source_event_id TEXT NOT NULL, + dispatch_content TEXT NOT NULL CHECK(length(trim(dispatch_content)) > 0), + display_content TEXT NOT NULL CHECK(length(trim(display_content)) > 0), + member_dispatch_sequence INTEGER NOT NULL CHECK(member_dispatch_sequence >= 1), + chain_position INTEGER NOT NULL CHECK(chain_position >= 1), + status TEXT NOT NULL CHECK(status IN ('queued','running','completed','failed','cancelled','abandoned')), + enqueued_at TEXT NOT NULL, + started_at TEXT, + terminal_at TEXT, + failure_reason TEXT, + PRIMARY KEY(intervention_receipt_id, turn_intent_id), + UNIQUE(intervention_receipt_id, chain_position), + UNIQUE(source_event_id), + FOREIGN KEY(intervention_receipt_id) + REFERENCES agent_org_runtime_member_interventions(intervention_receipt_id) + ON DELETE CASCADE, + FOREIGN KEY(session_id, turn_intent_id) + REFERENCES session_turn_intents(session_id, turn_intent_id) + ON DELETE CASCADE + ); + +CREATE TABLE agent_org_runtime_member_interventions ( + intervention_receipt_id TEXT PRIMARY KEY, + org_run_id TEXT NOT NULL, + member_id TEXT NOT NULL CHECK(length(trim(member_id)) > 0), + agent_id TEXT NOT NULL CHECK(length(trim(agent_id)) > 0), + session_id TEXT NOT NULL CHECK(length(trim(session_id)) > 0), + status TEXT NOT NULL CHECK(status IN ( + 'yield_requested','active','return_requested','cleared','failed' + )), + source_event_id TEXT NOT NULL CHECK(length(trim(source_event_id)) > 0), + original_task_id TEXT, + original_turn_intent_id TEXT, + original_member_dispatch_sequence INTEGER, + runtime_lease_id TEXT, + dialog_turn_generation TEXT, + entered_at TEXT NOT NULL, + last_user_activity_at TEXT NOT NULL, + yield_requested_at TEXT, + yield_released_at TEXT, + yield_timed_out_at TEXT, + return_request_id TEXT, + return_outcome TEXT CHECK(return_outcome IS NULL OR return_outcome IN ( + 'restored_task','cleared_paused','cleared_idle','no_longer_needed' + )), + continuation_turn_intent_id TEXT, + cleared_revision INTEGER, + cleared_at TEXT, + failure_reason TEXT, + updated_at TEXT NOT NULL, + FOREIGN KEY(org_run_id) REFERENCES agent_org_runtime_runs(id) ON DELETE CASCADE, + CHECK((runtime_lease_id IS NULL) = (dialog_turn_generation IS NULL)), + CHECK((original_task_id IS NULL) = (original_turn_intent_id IS NULL)), + CHECK((cleared_at IS NULL) = (status NOT IN ('cleared','failed'))) + ); + +CREATE TABLE agent_org_runtime_member_materializations ( + org_run_id TEXT NOT NULL, + member_id TEXT NOT NULL, + agent_id TEXT NOT NULL, + generation INTEGER NOT NULL CHECK(generation >= 1), + session_id TEXT NOT NULL, + authority_class TEXT NOT NULL CHECK(authority_class IN ( + 'starting', 'formal', 'user_directed' + )), + status TEXT NOT NULL CHECK(status IN ( + 'pending', 'succeeded', 'failed' + )), + error_code TEXT, + error_json TEXT, + created_at TEXT NOT NULL, + updated_at TEXT NOT NULL, + PRIMARY KEY(org_run_id, member_id, generation), + UNIQUE(org_run_id, session_id), + FOREIGN KEY(org_run_id) REFERENCES agent_org_runtime_runs(id) ON DELETE CASCADE + ); + +CREATE TABLE agent_org_runtime_pause_episodes ( + episode_id TEXT PRIMARY KEY CHECK(length(trim(episode_id)) > 0), + org_run_id TEXT NOT NULL, + pause_request_id TEXT NOT NULL CHECK(length(trim(pause_request_id)) > 0), + pause_generation INTEGER NOT NULL CHECK(pause_generation >= 2), + status TEXT NOT NULL CHECK(status IN ('active','consumed')), + resume_request_id TEXT, + resume_generation INTEGER, + teardown_owner_id TEXT NOT NULL CHECK(length(trim(teardown_owner_id)) > 0), + created_at TEXT NOT NULL, + updated_at TEXT NOT NULL, + resumed_at TEXT, + UNIQUE(org_run_id, pause_request_id), + UNIQUE(resume_request_id), + FOREIGN KEY(org_run_id) REFERENCES agent_org_runtime_runs(id) ON DELETE CASCADE, + CHECK( + (status='active' AND resume_request_id IS NULL + AND resume_generation IS NULL AND resumed_at IS NULL) + OR + (status='consumed' AND resume_request_id IS NOT NULL + AND resume_generation IS NOT NULL AND resume_generation > pause_generation + AND resumed_at IS NOT NULL) + ) + ); + +CREATE TABLE agent_org_runtime_pause_handoffs ( + handoff_id TEXT PRIMARY KEY CHECK(length(trim(handoff_id)) > 0), + episode_id TEXT NOT NULL, + org_run_id TEXT NOT NULL, + session_id TEXT NOT NULL, + original_turn_intent_id TEXT NOT NULL, + turn_kind TEXT NOT NULL CHECK(turn_kind IN ('coordinator','task_execution')), + participant_id TEXT NOT NULL, + task_id TEXT, + original_owner_member_id TEXT, + original_activation_generation INTEGER NOT NULL CHECK(original_activation_generation >= 1), + original_intent_status TEXT NOT NULL CHECK(original_intent_status IN ('queued','running')), + drain_status TEXT NOT NULL CHECK(drain_status IN ( + 'waiting','released','runtime_absent','timed_out' + )), + runtime_lease_id TEXT, + dialog_turn_generation TEXT, + yield_requested_at TEXT, + released_at TEXT, + drain_timeout_at TEXT, + drain_error TEXT, + continuation_turn_intent_id TEXT, + continuation_status TEXT CHECK(continuation_status IN ('queued','dispatched','skipped')), + skip_reason TEXT, + created_at TEXT NOT NULL, + updated_at TEXT NOT NULL, + UNIQUE(episode_id, session_id, original_turn_intent_id), + UNIQUE(continuation_turn_intent_id), + FOREIGN KEY(episode_id) REFERENCES agent_org_runtime_pause_episodes(episode_id) ON DELETE CASCADE, + FOREIGN KEY(org_run_id) REFERENCES agent_org_runtime_runs(id) ON DELETE CASCADE, + FOREIGN KEY(session_id, original_turn_intent_id) + REFERENCES agent_org_runtime_turn_contexts(session_id, turn_intent_id) + ON DELETE CASCADE, + CHECK( + (turn_kind='coordinator' AND task_id IS NULL AND original_owner_member_id IS NULL) + OR + (turn_kind='task_execution' AND task_id IS NOT NULL + AND original_owner_member_id=participant_id) + ), + CHECK( + (runtime_lease_id IS NULL AND dialog_turn_generation IS NULL) + OR + (runtime_lease_id IS NOT NULL AND dialog_turn_generation IS NOT NULL) + ), + CHECK( + (continuation_status IS NULL AND continuation_turn_intent_id IS NULL AND skip_reason IS NULL) + OR + (continuation_status IN ('queued','dispatched') + AND continuation_turn_intent_id IS NOT NULL AND skip_reason IS NULL) + OR + (continuation_status='skipped' AND skip_reason IS NOT NULL) + ) + ); + +CREATE TABLE agent_org_runtime_plan_decisions ( + approval_id TEXT PRIMARY KEY, + plan_revision_id TEXT NOT NULL UNIQUE, + request_id TEXT NOT NULL UNIQUE, + policy TEXT NOT NULL CHECK(policy IN ('coordinator','user','automatic')), + status TEXT NOT NULL CHECK(status IN ( + 'pending','approved','changes_requested','superseded','cancelled' + )), + decision_by TEXT CHECK(decision_by IS NULL OR decision_by IN ( + 'user','coordinator','automatic' + )), + feedback TEXT, + created_at TEXT NOT NULL, + resolved_at TEXT, + FOREIGN KEY(plan_revision_id) + REFERENCES agent_org_runtime_plan_revisions(plan_revision_id) + ON DELETE CASCADE, + CHECK( + (status='pending' AND decision_by IS NULL AND resolved_at IS NULL) + OR + (status!='pending' AND decision_by IS NOT NULL AND resolved_at IS NOT NULL) + ) + ); + +CREATE TABLE agent_org_runtime_plan_revisions ( + plan_revision_id TEXT PRIMARY KEY, + org_run_id TEXT NOT NULL, + source_task_id TEXT NOT NULL, + source_member_id TEXT NOT NULL, + source_session_id TEXT NOT NULL, + source_turn_intent_id TEXT NOT NULL, + root_session_id TEXT NOT NULL, + revision_number INTEGER NOT NULL CHECK(revision_number >= 1), + previous_plan_revision_id TEXT, + plan_title TEXT NOT NULL, + plan_path TEXT NOT NULL, + plan_content TEXT NOT NULL, + content_digest TEXT NOT NULL CHECK(length(content_digest)=64), + created_at TEXT NOT NULL, + UNIQUE(org_run_id, source_task_id, revision_number), + FOREIGN KEY(org_run_id) REFERENCES agent_org_runtime_runs(id) ON DELETE CASCADE, + FOREIGN KEY(previous_plan_revision_id) + REFERENCES agent_org_runtime_plan_revisions(plan_revision_id) + ); + +CREATE TABLE agent_org_runtime_recovery_attempts ( + org_run_id TEXT NOT NULL, + action_kind TEXT NOT NULL, + target_key TEXT NOT NULL, + reason_fingerprint TEXT NOT NULL, + attempts INTEGER NOT NULL DEFAULT 0, + next_allowed_at TEXT NOT NULL, + updated_at TEXT NOT NULL, + reservation_token TEXT, + PRIMARY KEY (org_run_id, action_kind, target_key) + ); + +CREATE TABLE agent_org_runtime_run_completion_certificates ( + id TEXT PRIMARY KEY, + org_run_id TEXT NOT NULL, + activation_generation INTEGER NOT NULL CHECK(activation_generation >= 1), + work_revision INTEGER NOT NULL CHECK(work_revision >= 0), + request_id TEXT NOT NULL CHECK(trim(request_id) <> ''), + request_digest TEXT NOT NULL CHECK(length(request_digest)=64), + outcome TEXT NOT NULL CHECK(outcome IN ('delivered','cancelled','failed')), + summary TEXT NOT NULL CHECK(trim(summary) <> ''), + coordinator_session_id TEXT NOT NULL CHECK(trim(coordinator_session_id) <> ''), + coordinator_turn_intent_id TEXT NOT NULL CHECK(trim(coordinator_turn_intent_id) <> ''), + evidence_task_ids_json TEXT NOT NULL CHECK(json_valid(evidence_task_ids_json)=1 AND json_type(evidence_task_ids_json)='array'), + closure_task_ids_json TEXT NOT NULL CHECK(json_valid(closure_task_ids_json)=1 AND json_type(closure_task_ids_json)='array'), + task_output_refs_json TEXT NOT NULL CHECK(json_valid(task_output_refs_json)=1 AND json_type(task_output_refs_json)='array'), + resolution_links_json TEXT NOT NULL CHECK(json_valid(resolution_links_json)=1 AND json_type(resolution_links_json)='array'), + validator_version INTEGER NOT NULL CHECK(validator_version=1), + created_at TEXT NOT NULL, + UNIQUE(org_run_id, request_id), + FOREIGN KEY (org_run_id) REFERENCES agent_org_runtime_runs(id) ON DELETE CASCADE + ); + +CREATE TABLE agent_org_runtime_run_progress ( + org_run_id TEXT PRIMARY KEY, + work_revision INTEGER NOT NULL DEFAULT 0 CHECK(work_revision >= 0), + coordinator_presented_work_revision INTEGER, + coordinator_observed_work_revision INTEGER, + completion_requested INTEGER NOT NULL DEFAULT 0, + completion_requested_at TEXT, + completion_requested_work_revision INTEGER, + completion_summary TEXT, + completion_candidate_json TEXT CHECK(completion_candidate_json IS NULL OR json_valid(completion_candidate_json)=1), + updated_at TEXT NOT NULL, + FOREIGN KEY(org_run_id) REFERENCES agent_org_runtime_runs(id) ON DELETE CASCADE + ); + +CREATE TABLE agent_org_runtime_runs ( + id TEXT PRIMARY KEY, + org_id TEXT NOT NULL, + coordinator_agent_id TEXT NOT NULL, + root_session_id TEXT, + org_snapshot_json TEXT, + entry_mode TEXT NOT NULL, + status TEXT NOT NULL CHECK(status IN ( + 'starting', 'running', 'paused', 'idle', 'failed', 'archived' + )), + activation_generation INTEGER NOT NULL DEFAULT 1 + CHECK(activation_generation >= 1), + has_initial_work INTEGER NOT NULL DEFAULT 0 + CHECK(has_initial_work IN (0, 1)), + work_item_id TEXT, + project_slug TEXT, + routine_fire_id TEXT, + summary TEXT, + last_error TEXT, + failure_json TEXT, + last_activity_outcome TEXT CHECK(last_activity_outcome IN ( + 'completed', 'failed', 'cancelled' + )), + created_at TEXT NOT NULL, + updated_at TEXT NOT NULL, + idled_at TEXT, + archived_at TEXT, + archive_receipt_id TEXT UNIQUE, + CHECK( + (status='archived' AND archived_at IS NOT NULL AND archive_receipt_id IS NOT NULL) + OR + (status<>'archived' AND archived_at IS NULL AND archive_receipt_id IS NULL) + ) + ); + +CREATE TABLE agent_org_runtime_task_annotations ( + id TEXT PRIMARY KEY, + org_run_id TEXT NOT NULL, + task_id TEXT NOT NULL, + kind TEXT NOT NULL CHECK(kind IN ('progress','evidence','audit_note')), + body TEXT NOT NULL CHECK(trim(body) <> ''), + actor_kind TEXT NOT NULL CHECK(actor_kind IN ('graph_writer','owner_execution','system')), + actor_participant_id TEXT NOT NULL CHECK(trim(actor_participant_id) <> ''), + source_turn_intent_id TEXT, + created_at TEXT NOT NULL, + FOREIGN KEY (org_run_id, task_id) + REFERENCES agent_org_runtime_tasks(org_run_id, id) ON DELETE CASCADE + ); + +CREATE TABLE agent_org_runtime_task_events ( + id TEXT PRIMARY KEY, + org_run_id TEXT NOT NULL, + task_id TEXT NOT NULL, + event_type TEXT NOT NULL, + previous_owner TEXT, + next_owner TEXT, + previous_status TEXT, + next_status TEXT, + actor_member_id TEXT, + actor_kind TEXT NOT NULL CHECK(actor_kind IN ('graph_writer','owner_execution','system')), + source_turn_intent_id TEXT, + created_at TEXT NOT NULL + ); + +CREATE TABLE agent_org_runtime_task_execution_handoffs ( + id TEXT PRIMARY KEY, + org_run_id TEXT NOT NULL, + activation_generation INTEGER NOT NULL CHECK(activation_generation >= 1), + request_id TEXT NOT NULL CHECK(trim(request_id) <> ''), + request_digest TEXT NOT NULL CHECK(length(request_digest)=64), + old_task_id TEXT NOT NULL, + old_owner_member_id TEXT NOT NULL CHECK(trim(old_owner_member_id) <> ''), + old_session_id TEXT, + old_turn_intent_id TEXT, + runtime_lease_id TEXT, + dialog_turn_generation TEXT, + replacement_task_id TEXT, + state TEXT NOT NULL CHECK(state IN ('requested','yielding','released','timeout','unknown','failed')), + slo_missed INTEGER NOT NULL DEFAULT 0 CHECK(slo_missed IN (0,1)), + external_effect_unknown INTEGER NOT NULL DEFAULT 0 CHECK(external_effect_unknown IN (0,1)), + local_effect_count INTEGER NOT NULL DEFAULT 0 CHECK(local_effect_count >= 0), + resolution_request_id TEXT, + resolution_session_id TEXT, + requested_resolution TEXT CHECK(requested_resolution IN ('continue_replacement','keep_stopped','abandon_episode')), + resolution_attempt INTEGER NOT NULL DEFAULT 0 CHECK(resolution_attempt >= 0), + resolution_requested_at TEXT, + resolution TEXT CHECK(resolution IN ('continue_replacement','keep_stopped','abandon_episode')), + requested_at TEXT NOT NULL, + released_at TEXT, + resolved_at TEXT, + updated_at TEXT NOT NULL, + UNIQUE(org_run_id, activation_generation, request_id), + UNIQUE(org_run_id, activation_generation, resolution_request_id), + UNIQUE(org_run_id, activation_generation, old_task_id, old_turn_intent_id), + FOREIGN KEY (org_run_id, old_task_id) + REFERENCES agent_org_runtime_tasks(org_run_id, id), + FOREIGN KEY (org_run_id, replacement_task_id) + REFERENCES agent_org_runtime_tasks(org_run_id, id), + CHECK((old_session_id IS NULL) = (old_turn_intent_id IS NULL)), + CHECK((runtime_lease_id IS NULL) = (dialog_turn_generation IS NULL)), + CHECK(runtime_lease_id IS NULL OR old_session_id IS NOT NULL), + CHECK(state <> 'released' OR released_at IS NOT NULL), + CHECK( + (requested_resolution IS NULL AND resolution_request_id IS NULL + AND resolution_session_id IS NULL AND resolution_attempt=0 + AND resolution_requested_at IS NULL) + OR + (requested_resolution IS NOT NULL AND resolution_request_id IS NOT NULL + AND resolution_session_id IS NOT NULL AND resolution_attempt>=1 + AND resolution_requested_at IS NOT NULL) + ), + CHECK(resolution IS NULL OR ( + resolved_at IS NOT NULL AND resolution=requested_resolution + )) + ); + +CREATE TABLE agent_org_runtime_tasks ( + id TEXT NOT NULL, + org_run_id TEXT NOT NULL, + activation_generation INTEGER NOT NULL CHECK(activation_generation >= 1), + subject TEXT NOT NULL, + description TEXT NOT NULL DEFAULT '', + active_form TEXT, + owner TEXT, + status TEXT NOT NULL CHECK(status IN ('pending','in_progress','completed','failed','cancelled')), + execution_mode TEXT NOT NULL CHECK(execution_mode IN ('build','plan')), + blocked_by_json TEXT NOT NULL DEFAULT '[]', + metadata_json TEXT, + output_json TEXT, + failure_reason_json TEXT, + cancel_reason_json TEXT, + external_effect_unknown INTEGER NOT NULL DEFAULT 0 + CHECK(external_effect_unknown IN (0,1)), + created_by_participant_id TEXT NOT NULL CHECK(trim(created_by_participant_id) <> ''), + source_turn_intent_id TEXT NOT NULL CHECK(trim(source_turn_intent_id) <> ''), + originating_message_id TEXT, + replaces_task_id TEXT, + created_at TEXT NOT NULL, + updated_at TEXT NOT NULL, + PRIMARY KEY (org_run_id, id), + FOREIGN KEY (org_run_id, replaces_task_id) + REFERENCES agent_org_runtime_tasks(org_run_id, id), + CHECK(owner IS NULL OR (trim(owner) <> '' AND owner <> 'coordinator')), + CHECK(replaces_task_id IS NULL OR replaces_task_id <> id), + CHECK(json_valid(blocked_by_json)=1 AND json_type(blocked_by_json)='array'), + CHECK(metadata_json IS NULL OR ( + json_valid(metadata_json)=1 AND json_type(metadata_json)='object' + AND json_type(metadata_json,'$.output') IS NULL + AND json_type(metadata_json,'$.execution_mode') IS NULL + )), + CHECK(output_json IS NULL OR (json_valid(output_json)=1 AND json_type(output_json)='object')), + CHECK(failure_reason_json IS NULL OR (json_valid(failure_reason_json)=1 AND json_type(failure_reason_json)='object')), + CHECK(cancel_reason_json IS NULL OR (json_valid(cancel_reason_json)=1 AND json_type(cancel_reason_json)='object')), + CHECK(status NOT IN ('in_progress','completed','failed') OR owner IS NOT NULL), + CHECK( + (status IN ('pending','in_progress') AND output_json IS NULL AND failure_reason_json IS NULL AND cancel_reason_json IS NULL) + OR (status='completed' AND output_json IS NOT NULL AND failure_reason_json IS NULL AND cancel_reason_json IS NULL) + OR (status='failed' AND output_json IS NULL AND failure_reason_json IS NOT NULL AND cancel_reason_json IS NULL) + OR (status='cancelled' AND output_json IS NULL AND failure_reason_json IS NULL AND cancel_reason_json IS NOT NULL) + ) + ); + +CREATE TABLE agent_org_runtime_tool_call_receipts ( + org_run_id TEXT NOT NULL, + session_id TEXT NOT NULL, + turn_intent_id TEXT NOT NULL, + call_id TEXT NOT NULL, + tool_name TEXT NOT NULL, + operation TEXT NOT NULL, + canonical_digest TEXT NOT NULL, + result_text TEXT, + error_kind TEXT, + error_text TEXT, + created_at TEXT NOT NULL, + PRIMARY KEY (org_run_id, session_id, turn_intent_id, call_id), + FOREIGN KEY (org_run_id) + REFERENCES agent_org_runtime_runs(id) ON DELETE CASCADE, + CHECK (trim(org_run_id) <> '' AND org_run_id = trim(org_run_id)), + CHECK (trim(session_id) <> '' AND session_id = trim(session_id)), + CHECK (trim(turn_intent_id) <> '' AND turn_intent_id = trim(turn_intent_id)), + CHECK (trim(call_id) <> '' AND call_id = trim(call_id)), + CHECK (trim(tool_name) <> '' AND length(CAST(tool_name AS BLOB)) <= 128), + CHECK (trim(operation) <> '' AND length(CAST(operation AS BLOB)) <= 128), + CHECK (length(canonical_digest) = 64 AND canonical_digest NOT GLOB '*[^0-9a-f]*'), + CHECK ( + (result_text IS NOT NULL AND error_kind IS NULL AND error_text IS NULL) + OR + (result_text IS NULL AND error_kind IN ('invalid_params','execution_failed','permission_denied','timeout') AND error_text IS NOT NULL) + ), + CHECK (result_text IS NULL OR length(CAST(result_text AS BLOB)) <= 524288), + CHECK (error_text IS NULL OR length(CAST(error_text AS BLOB)) <= 65536), + CHECK (length(created_at) <= 64 AND length(CAST(created_at AS BLOB)) <= 256) + ); + +CREATE TABLE agent_org_runtime_turn_contexts ( + context_id INTEGER PRIMARY KEY AUTOINCREMENT, + session_id TEXT NOT NULL CHECK(length(trim(session_id)) > 0), + turn_intent_id TEXT NOT NULL CHECK(length(trim(turn_intent_id)) > 0), + org_run_id TEXT NOT NULL, + participant_id TEXT NOT NULL CHECK(length(trim(participant_id)) > 0), + turn_kind TEXT NOT NULL, + task_id TEXT, + owner_member_id TEXT, + dispatch_member_id TEXT, + member_dispatch_sequence INTEGER, + source_kind TEXT NOT NULL, + source_id TEXT NOT NULL CHECK(length(trim(source_id)) > 0), + root_authority_turn_id TEXT, + actor_version INTEGER, + activation_generation INTEGER, + coordinator_work_revision INTEGER, + coordinator_presented_outputs_json TEXT NOT NULL DEFAULT '[]' + CHECK(json_valid(coordinator_presented_outputs_json)=1 + AND json_type(coordinator_presented_outputs_json)='array'), + coordinator_observed_task_ids_json TEXT NOT NULL DEFAULT '[]' + CHECK(json_valid(coordinator_observed_task_ids_json)=1 + AND json_type(coordinator_observed_task_ids_json)='array' + AND json_array_length(coordinator_observed_task_ids_json) <= 32), + terminal_reason TEXT, + created_at TEXT NOT NULL, + UNIQUE(session_id, turn_intent_id), + FOREIGN KEY(session_id, turn_intent_id) + REFERENCES session_turn_intents(session_id, turn_intent_id) + ON DELETE CASCADE, + FOREIGN KEY(org_run_id) + REFERENCES agent_org_runtime_runs(id) ON DELETE CASCADE, + CHECK( + (turn_kind='coordinator' + AND participant_id='coordinator' + AND task_id IS NULL AND owner_member_id IS NULL + AND dispatch_member_id IS NULL AND member_dispatch_sequence IS NULL + AND ( + (source_kind IN ('root_turn','group_root') + AND (source_kind<>'root_turn' OR source_id=turn_intent_id) + AND root_authority_turn_id IS NULL AND actor_version IS NULL + AND activation_generation IS NOT NULL AND activation_generation >= 1 + AND (coordinator_work_revision IS NULL OR coordinator_work_revision >= 0) + AND (terminal_reason IS NULL OR terminal_reason='waiting_for_org_event')) + OR + (source_kind='member_inbox' + AND root_authority_turn_id IS NOT NULL + AND length(trim(root_authority_turn_id)) > 0 + AND actor_version IS NOT NULL AND actor_version >= 1 + AND activation_generation IS NULL + AND coordinator_work_revision IS NULL + AND coordinator_observed_task_ids_json='[]' AND terminal_reason IS NULL) + )) + OR + (turn_kind='task_execution' + AND task_id IS NOT NULL AND length(trim(task_id)) > 0 + AND owner_member_id=participant_id + AND dispatch_member_id=participant_id + AND member_dispatch_sequence IS NOT NULL AND member_dispatch_sequence >= 1 + AND source_kind='task' AND source_id=task_id + AND root_authority_turn_id IS NULL AND actor_version IS NULL + AND activation_generation IS NOT NULL AND activation_generation >= 1 + AND coordinator_work_revision IS NULL + AND coordinator_observed_task_ids_json='[]' AND terminal_reason IS NULL) + OR + (turn_kind='user_directed_work' + AND task_id IS NULL AND owner_member_id IS NULL + AND dispatch_member_id=participant_id + AND member_dispatch_sequence IS NOT NULL AND member_dispatch_sequence >= 1 + AND actor_version IS NOT NULL AND actor_version >= 1 + AND activation_generation IS NULL + AND coordinator_work_revision IS NULL + AND coordinator_observed_task_ids_json='[]' AND terminal_reason IS NULL + AND ( + (source_kind='direct_member' + AND root_authority_turn_id=turn_intent_id) + OR + (source_kind='group_mention' + AND root_authority_turn_id=turn_intent_id) + OR + (source_kind='member_inbox' + AND root_authority_turn_id IS NOT NULL + AND length(trim(root_authority_turn_id)) > 0) + )) + ) + ); + +CREATE TABLE agent_org_runtime_user_directed_coordinator_bindings ( + binding_id INTEGER PRIMARY KEY AUTOINCREMENT, + org_run_id TEXT NOT NULL, + session_id TEXT NOT NULL CHECK(length(trim(session_id)) > 0), + turn_intent_id TEXT NOT NULL CHECK(length(trim(turn_intent_id)) > 0), + root_authority_turn_id TEXT NOT NULL CHECK(length(trim(root_authority_turn_id)) > 0), + parent_delivery_id INTEGER NOT NULL, + parent_inbox_id INTEGER, + source_inbox_id INTEGER NOT NULL, + depth INTEGER NOT NULL CHECK(depth >= 1), + delivery_ordinal INTEGER NOT NULL CHECK(delivery_ordinal >= 2), + request_digest TEXT NOT NULL + CHECK(length(request_digest)=64 AND request_digest NOT GLOB '*[^0-9a-f]*'), + dispatch_content TEXT NOT NULL CHECK(length(trim(dispatch_content)) > 0), + display_content TEXT NOT NULL CHECK(length(trim(display_content)) > 0), + status TEXT NOT NULL + CHECK(status IN ('pending','started','completed','failed','cancelled','abandoned','unknown')), + created_at TEXT NOT NULL, + started_at TEXT, + terminal_at TEXT, + failure_reason TEXT, + UNIQUE(session_id,turn_intent_id), + UNIQUE(source_inbox_id), + UNIQUE(org_run_id,root_authority_turn_id,delivery_ordinal), + FOREIGN KEY(org_run_id,root_authority_turn_id) + REFERENCES agent_org_runtime_user_directed_roots(org_run_id,root_authority_turn_id) + ON DELETE CASCADE, + FOREIGN KEY(session_id,turn_intent_id) + REFERENCES agent_org_runtime_turn_contexts(session_id,turn_intent_id) + ON DELETE CASCADE, + FOREIGN KEY(parent_delivery_id) + REFERENCES agent_org_runtime_user_directed_deliveries(delivery_id) ON DELETE RESTRICT, + FOREIGN KEY(parent_inbox_id) REFERENCES agent_org_runtime_inbox(id) ON DELETE RESTRICT, + FOREIGN KEY(source_inbox_id) REFERENCES agent_org_runtime_inbox(id) ON DELETE RESTRICT, + CHECK(parent_inbox_id IS NULL OR parent_inbox_id<>source_inbox_id), + CHECK( + (status='pending' AND started_at IS NULL AND terminal_at IS NULL AND failure_reason IS NULL) + OR + (status='started' AND started_at IS NOT NULL AND terminal_at IS NULL AND failure_reason IS NULL) + OR + (status IN ('completed','cancelled') AND started_at IS NOT NULL AND terminal_at IS NOT NULL) + OR + (status IN ('failed','abandoned','unknown') AND terminal_at IS NOT NULL) + ) + ); + +CREATE TABLE agent_org_runtime_user_directed_deliveries ( + delivery_id INTEGER PRIMARY KEY AUTOINCREMENT, + org_run_id TEXT NOT NULL, + session_id TEXT NOT NULL CHECK(length(trim(session_id)) > 0), + turn_intent_id TEXT NOT NULL CHECK(length(trim(turn_intent_id)) > 0), + root_authority_turn_id TEXT NOT NULL CHECK(length(trim(root_authority_turn_id)) > 0), + parent_delivery_id INTEGER, + parent_inbox_id INTEGER, + source_kind TEXT NOT NULL + CHECK(source_kind IN ('direct_member','group_mention','member_inbox')), + source_event_id TEXT, + source_inbox_id INTEGER, + dispatch_member_id TEXT NOT NULL CHECK(length(trim(dispatch_member_id)) > 0), + member_dispatch_sequence INTEGER NOT NULL CHECK(member_dispatch_sequence >= 1), + depth INTEGER NOT NULL CHECK(depth >= 0), + delivery_ordinal INTEGER NOT NULL CHECK(delivery_ordinal >= 1), + request_digest TEXT NOT NULL + CHECK(length(request_digest)=64 AND request_digest NOT GLOB '*[^0-9a-f]*'), + dispatch_content TEXT NOT NULL CHECK(length(trim(dispatch_content)) > 0), + display_content TEXT NOT NULL CHECK(length(trim(display_content)) > 0), + images_json TEXT NOT NULL DEFAULT '[]' + CHECK(json_valid(images_json)=1 AND json_type(images_json)='array'), + status TEXT NOT NULL + CHECK(status IN ('pending','started','completed','failed','cancelled','abandoned','unknown')), + created_at TEXT NOT NULL, + started_at TEXT, + terminal_at TEXT, + failure_reason TEXT, + UNIQUE(session_id, turn_intent_id), + UNIQUE(org_run_id, root_authority_turn_id, delivery_ordinal), + FOREIGN KEY(org_run_id, root_authority_turn_id) + REFERENCES agent_org_runtime_user_directed_roots(org_run_id, root_authority_turn_id) + ON DELETE CASCADE, + FOREIGN KEY(session_id, turn_intent_id) + REFERENCES agent_org_runtime_turn_contexts(session_id, turn_intent_id) + ON DELETE CASCADE, + FOREIGN KEY(parent_delivery_id) + REFERENCES agent_org_runtime_user_directed_deliveries(delivery_id) ON DELETE RESTRICT, + FOREIGN KEY(source_inbox_id) + REFERENCES agent_org_runtime_inbox(id) ON DELETE RESTRICT, + FOREIGN KEY(parent_inbox_id) + REFERENCES agent_org_runtime_inbox(id) ON DELETE RESTRICT, + CHECK( + (source_kind='direct_member' + AND source_event_id IS NOT NULL + AND source_inbox_id IS NULL AND parent_delivery_id IS NULL + AND parent_inbox_id IS NULL + AND depth=0 AND root_authority_turn_id=turn_intent_id) + OR + (source_kind='group_mention' + AND source_event_id IS NULL + AND source_inbox_id IS NOT NULL AND parent_delivery_id IS NULL + AND parent_inbox_id IS NULL + AND depth=0 AND root_authority_turn_id=turn_intent_id) + OR + (source_kind='member_inbox' + AND source_event_id IS NULL + AND source_inbox_id IS NOT NULL AND parent_delivery_id IS NOT NULL + AND depth>=1) + ), + CHECK( + (status='pending' AND started_at IS NULL AND terminal_at IS NULL AND failure_reason IS NULL) + OR + (status='started' AND started_at IS NOT NULL AND terminal_at IS NULL AND failure_reason IS NULL) + OR + (status IN ('completed','cancelled') AND started_at IS NOT NULL AND terminal_at IS NOT NULL) + OR + (status IN ('failed','abandoned','unknown') AND terminal_at IS NOT NULL) + ) + ); + +CREATE TABLE agent_org_runtime_user_directed_roots ( + org_run_id TEXT NOT NULL, + root_authority_turn_id TEXT NOT NULL CHECK(length(trim(root_authority_turn_id)) > 0), + policy_version INTEGER NOT NULL CHECK(policy_version >= 1), + max_deliveries INTEGER NOT NULL CHECK(max_deliveries >= 1), + max_cascade_depth INTEGER NOT NULL CHECK(max_cascade_depth >= 0), + next_delivery_ordinal INTEGER NOT NULL CHECK(next_delivery_ordinal >= 2), + created_at TEXT NOT NULL, + PRIMARY KEY(org_run_id, root_authority_turn_id), + FOREIGN KEY(org_run_id) REFERENCES agent_org_runtime_runs(id) ON DELETE CASCADE + ); + +CREATE TABLE agent_org_runtime_work_episode_tasks ( + org_run_id TEXT NOT NULL, + work_episode_id TEXT NOT NULL, + task_id TEXT NOT NULL, + associated_at TEXT NOT NULL, + PRIMARY KEY (org_run_id, task_id), + FOREIGN KEY (work_episode_id) + REFERENCES agent_org_runtime_work_episodes(id) ON DELETE CASCADE, + FOREIGN KEY (org_run_id) REFERENCES agent_org_runtime_runs(id) ON DELETE CASCADE, + FOREIGN KEY (org_run_id, task_id) + REFERENCES agent_org_runtime_tasks(org_run_id, id) ON DELETE CASCADE + ); + +CREATE TABLE agent_org_runtime_work_episodes ( + id TEXT PRIMARY KEY, + org_run_id TEXT NOT NULL, + episode_sequence INTEGER NOT NULL CHECK(episode_sequence >= 1), + status TEXT NOT NULL CHECK(status IN ('active','certified')), + opening_activation_generation INTEGER NOT NULL + CHECK(opening_activation_generation >= 1), + closing_activation_generation INTEGER + CHECK(closing_activation_generation IS NULL OR closing_activation_generation >= 1), + opening_work_revision INTEGER NOT NULL CHECK(opening_work_revision >= 0), + closing_work_revision INTEGER CHECK(closing_work_revision IS NULL OR closing_work_revision >= 0), + outcome TEXT CHECK(outcome IN ('delivered','cancelled','failed')), + certificate_id TEXT UNIQUE, + opened_by_turn_intent_id TEXT NOT NULL CHECK(trim(opened_by_turn_intent_id) <> ''), + created_at TEXT NOT NULL, + closed_at TEXT, + UNIQUE(org_run_id, episode_sequence), + FOREIGN KEY (org_run_id) REFERENCES agent_org_runtime_runs(id) ON DELETE CASCADE, + CHECK( + (status='active' AND closing_activation_generation IS NULL + AND closing_work_revision IS NULL AND outcome IS NULL + AND certificate_id IS NULL AND closed_at IS NULL) + OR + (status='certified' AND closing_activation_generation IS NOT NULL + AND closing_work_revision IS NOT NULL AND outcome IS NOT NULL + AND certificate_id IS NOT NULL AND closed_at IS NOT NULL) + ) + ); + +CREATE TABLE agent_org_scope_removal_receipts ( + receipt_id TEXT PRIMARY KEY, + org_run_id TEXT NOT NULL, + work_episode_id TEXT NOT NULL, + target_task_id TEXT NOT NULL, + root_user_event_id TEXT NOT NULL, + request_id TEXT NOT NULL, + request_digest TEXT NOT NULL, + actor_session_id TEXT NOT NULL, + actor_kind TEXT NOT NULL CHECK(actor_kind='run_view_user'), + status TEXT NOT NULL CHECK(status IN ('recorded','revoked')), + created_at TEXT NOT NULL, + revoked_at TEXT, + UNIQUE(org_run_id, request_id), + UNIQUE(root_user_event_id), + FOREIGN KEY(org_run_id, target_task_id) + REFERENCES agent_org_runtime_tasks(org_run_id, id) ON DELETE CASCADE, + FOREIGN KEY(work_episode_id) + REFERENCES agent_org_runtime_work_episodes(id) ON DELETE CASCADE + ); + +CREATE TABLE agent_org_scope_resolution_receipts ( + resolution_id TEXT PRIMARY KEY, + root_receipt_id TEXT NOT NULL, + org_run_id TEXT NOT NULL, + work_episode_id TEXT NOT NULL, + task_id TEXT NOT NULL, + resolution_kind TEXT NOT NULL CHECK(resolution_kind IN ( + 'dependency_cancelled','dependency_replaced','dependency_detached' + )), + replacement_task_id TEXT, + source_turn_intent_id TEXT, + created_at TEXT NOT NULL, + UNIQUE(root_receipt_id,task_id,resolution_kind), + FOREIGN KEY(root_receipt_id) + REFERENCES agent_org_scope_removal_receipts(receipt_id) ON DELETE CASCADE, + FOREIGN KEY(org_run_id,task_id) + REFERENCES agent_org_runtime_tasks(org_run_id,id) ON DELETE CASCADE, + FOREIGN KEY(work_episode_id) + REFERENCES agent_org_runtime_work_episodes(id) ON DELETE CASCADE, + CHECK( + (resolution_kind='dependency_replaced' AND replacement_task_id IS NOT NULL) + OR (resolution_kind<>'dependency_replaced' AND replacement_task_id IS NULL) + ) + ); + +CREATE TABLE agent_org_task_execution_leases ( + lease_id TEXT PRIMARY KEY, + org_run_id TEXT NOT NULL, + work_episode_id TEXT NOT NULL, + task_id TEXT NOT NULL, + activation_generation INTEGER NOT NULL CHECK(activation_generation >= 1), + execution_epoch INTEGER NOT NULL CHECK(execution_epoch >= 1), + owner_member_id TEXT NOT NULL, + session_id TEXT NOT NULL, + turn_intent_id TEXT NOT NULL, + source_kind TEXT NOT NULL CHECK(source_kind IN ( + 'assignment','plan_revision','coordinator_message', + 'pause_resume','intervention_return','legacy_repair' + )), + continuation_receipt_id TEXT NOT NULL, + source_inbox_id INTEGER, + prior_lease_id TEXT, + state TEXT NOT NULL CHECK(state IN ('active','released','frozen','conflict')), + terminal_reason_code TEXT, + created_at TEXT NOT NULL, + terminal_at TEXT, + UNIQUE(session_id, turn_intent_id), + UNIQUE(org_run_id, work_episode_id, task_id, activation_generation, execution_epoch), + UNIQUE(continuation_receipt_id), + FOREIGN KEY(org_run_id, task_id) + REFERENCES agent_org_runtime_tasks(org_run_id, id) ON DELETE CASCADE, + FOREIGN KEY(work_episode_id) + REFERENCES agent_org_runtime_work_episodes(id) ON DELETE CASCADE, + FOREIGN KEY(source_inbox_id) + REFERENCES agent_org_runtime_inbox(id) ON DELETE SET NULL, + FOREIGN KEY(prior_lease_id) + REFERENCES agent_org_task_execution_leases(lease_id) + ); + +CREATE TABLE agent_org_task_execution_reconciliations ( + context_id INTEGER PRIMARY KEY, + org_run_id TEXT NOT NULL, + task_id TEXT NOT NULL, + activation_generation INTEGER NOT NULL, + session_id TEXT NOT NULL, + turn_intent_id TEXT NOT NULL, + disposition TEXT NOT NULL CHECK(disposition='conflict_rejected'), + reason_code TEXT NOT NULL CHECK(reason_code='duplicate_execution_rejected'), + reconciled_at TEXT NOT NULL, + UNIQUE(session_id,turn_intent_id), + FOREIGN KEY(context_id) + REFERENCES agent_org_runtime_turn_contexts(context_id) ON DELETE CASCADE + ); + +CREATE UNIQUE INDEX idx_agent_org_completion_recheck_inbox + ON agent_org_coordinator_completion_rechecks(inbox_id) + WHERE inbox_id IS NOT NULL; + +CREATE INDEX idx_agent_org_completion_recheck_pending + ON agent_org_coordinator_completion_rechecks(org_run_id,status,work_revision); + +CREATE UNIQUE INDEX idx_agent_org_final_summary_one_active + ON agent_org_runtime_final_summary_receipts(certificate_id) + WHERE status IN ('pending','running','persisting'); + +CREATE INDEX idx_agent_org_final_summary_public_timeline + ON agent_org_runtime_final_summary_receipts(org_run_id,terminal_at,receipt_id) + WHERE status IN ('persisted','failed'); + +CREATE INDEX idx_agent_org_final_summary_run_current + ON agent_org_runtime_final_summary_receipts( + org_run_id,activation_generation,attempt DESC + ); + +CREATE UNIQUE INDEX idx_agent_org_final_summary_turn + ON agent_org_runtime_final_summary_receipts( + coordinator_session_id,turn_intent_id + ) WHERE turn_intent_id IS NOT NULL; + +CREATE INDEX idx_agent_org_formal_trigger_attempt_turn + ON agent_org_runtime_formal_trigger_attempts( + session_id,turn_intent_id,status,receipt_id + ); + +CREATE INDEX idx_agent_org_formal_trigger_missing_doorbell + ON agent_org_runtime_formal_trigger_receipts( + doorbell_status,status,org_run_id,created_at + ) WHERE status='pending' AND doorbell_status='missing'; + +CREATE UNIQUE INDEX idx_agent_org_formal_trigger_one_active_attempt + ON agent_org_runtime_formal_trigger_attempts(receipt_id) + WHERE status IN ('queued','running'); + +CREATE INDEX idx_agent_org_formal_trigger_pending + ON agent_org_runtime_formal_trigger_receipts( + org_run_id,status,doorbell_status,created_at,receipt_id + ); + +CREATE INDEX idx_agent_org_formal_trigger_task + ON agent_org_runtime_formal_trigger_receipts(org_run_id,task_id,created_at) + WHERE task_id IS NOT NULL; + +CREATE UNIQUE INDEX idx_agent_org_member_intervention_active + ON agent_org_runtime_member_interventions(org_run_id, member_id) + WHERE status IN ('yield_requested','active','return_requested'); + +CREATE UNIQUE INDEX idx_agent_org_member_intervention_continuation + ON agent_org_runtime_member_interventions(session_id, continuation_turn_intent_id) + WHERE continuation_turn_intent_id IS NOT NULL; + +CREATE INDEX idx_agent_org_member_intervention_public_timeline + ON agent_org_runtime_member_interventions( + org_run_id,cleared_at,intervention_receipt_id + ) WHERE status='cleared'; + +CREATE UNIQUE INDEX idx_agent_org_member_intervention_return_request + ON agent_org_runtime_member_interventions(org_run_id, return_request_id) + WHERE return_request_id IS NOT NULL; + +CREATE INDEX idx_agent_org_member_intervention_session + ON agent_org_runtime_member_interventions(session_id, status, updated_at); + +CREATE INDEX idx_agent_org_member_intervention_turn_queue + ON agent_org_runtime_member_intervention_turns( + intervention_receipt_id, status, member_dispatch_sequence + ); + +CREATE INDEX idx_agent_org_member_turn_admission_recovery + ON agent_org_member_turn_admissions(status, updated_at); + +CREATE INDEX idx_agent_org_runtime_archive_pending + ON agent_org_runtime_archive_episodes(teardown_status, deadline_at); + +CREATE INDEX idx_agent_org_runtime_archive_teardown_pending + ON agent_org_runtime_archive_teardowns( + archive_receipt_id, teardown_status, session_id + ); + +CREATE UNIQUE INDEX idx_agent_org_runtime_inbox_causation_recipient_once + ON agent_org_runtime_inbox( + causation_inbox_id, + payload_kind, + recipient_agent_id, + COALESCE(recipient_member_id, '') + ) + WHERE causation_inbox_id IS NOT NULL; + +CREATE INDEX idx_agent_org_runtime_inbox_delivery_resolutions_run + ON agent_org_runtime_inbox_delivery_resolutions(org_run_id, inbox_id); + +CREATE INDEX idx_agent_org_runtime_inbox_materializations_session + ON agent_org_runtime_inbox_materializations(session_id, inbox_id); + +CREATE INDEX idx_agent_org_runtime_inbox_org_run + ON agent_org_runtime_inbox(org_run_id, created_at); + +CREATE INDEX idx_agent_org_runtime_inbox_org_run_id + ON agent_org_runtime_inbox(org_run_id, id); + +CREATE INDEX idx_agent_org_runtime_inbox_recipient_member_unread + ON agent_org_runtime_inbox(recipient_member_id, read_at, created_at); + +CREATE INDEX idx_agent_org_runtime_inbox_recipient_unread + ON agent_org_runtime_inbox(recipient_agent_id, read_at, created_at); + +CREATE INDEX idx_agent_org_runtime_inbox_request_id + ON agent_org_runtime_inbox(request_id); + +CREATE INDEX idx_agent_org_runtime_inbox_run_kind_id + ON agent_org_runtime_inbox(org_run_id, payload_kind, id); + +CREATE INDEX idx_agent_org_runtime_inbox_run_task_assignment_v4 + ON agent_org_runtime_inbox( + org_run_id, + recipient_member_id, + json_extract( + CASE WHEN length(CAST(payload_json AS BLOB))<=262144 + AND json_valid(payload_json) + THEN payload_json ELSE '{}' END, + '$.task_id' + ) + ) + WHERE payload_kind='task_assigned' + AND CASE WHEN length(CAST(payload_json AS BLOB))<=262144 + THEN json_valid(payload_json) ELSE 0 END + AND json_type( + CASE WHEN length(CAST(payload_json AS BLOB))<=262144 + AND json_valid(payload_json) + THEN payload_json ELSE '{}' END, + '$.task_id' + )='text'; + +CREATE INDEX idx_agent_org_runtime_inbox_run_unread_recipient + ON agent_org_runtime_inbox(org_run_id, recipient_member_id, recipient_agent_id, id) + WHERE read_at IS NULL; + +CREATE INDEX idx_agent_org_runtime_inbox_task_bindings_wake + ON agent_org_runtime_inbox_task_bindings( + org_run_id,recipient_member_id,task_id,inbox_id + ); + +CREATE UNIQUE INDEX idx_agent_org_runtime_inbox_user_message_once + ON agent_org_runtime_inbox(org_run_id, sender_agent_id, client_message_id) + WHERE client_message_id IS NOT NULL; + +CREATE INDEX idx_agent_org_runtime_initial_inputs_dispatch + ON agent_org_runtime_initial_inputs(status, org_run_id); + +CREATE INDEX idx_agent_org_runtime_member_materializations_pending + ON agent_org_runtime_member_materializations(status, org_run_id, generation); + +CREATE INDEX idx_agent_org_runtime_pause_capture + ON agent_org_runtime_turn_contexts( + org_run_id, activation_generation, turn_kind, session_id, turn_intent_id + ) + WHERE turn_kind IN ('coordinator','task_execution'); + +CREATE INDEX idx_agent_org_runtime_pause_dispatch + ON agent_org_runtime_pause_handoffs(continuation_status, org_run_id, session_id); + +CREATE INDEX idx_agent_org_runtime_pause_drain + ON agent_org_runtime_pause_handoffs(episode_id, drain_status, session_id); + +CREATE UNIQUE INDEX idx_agent_org_runtime_pause_one_active + ON agent_org_runtime_pause_episodes(org_run_id) + WHERE status='active'; + +CREATE INDEX idx_agent_org_runtime_pause_public_timeline + ON agent_org_runtime_pause_episodes(org_run_id, created_at, episode_id); + +CREATE INDEX idx_agent_org_runtime_pause_request + ON agent_org_runtime_pause_episodes(org_run_id, pause_request_id); + +CREATE INDEX idx_agent_org_runtime_plan_decisions_status + ON agent_org_runtime_plan_decisions(status, created_at, approval_id); + +CREATE INDEX idx_agent_org_runtime_plan_revisions_path + ON agent_org_runtime_plan_revisions(plan_path, created_at DESC); + +CREATE INDEX idx_agent_org_runtime_plan_revisions_run_task + ON agent_org_runtime_plan_revisions( + org_run_id, source_task_id, revision_number DESC + ); + +CREATE INDEX idx_agent_org_runtime_plan_revisions_source_session_turn + ON agent_org_runtime_plan_revisions( + source_session_id, source_turn_intent_id, created_at + ); + +CREATE INDEX idx_agent_org_runtime_recovery_attempts_run + ON agent_org_runtime_recovery_attempts(org_run_id); + +CREATE INDEX idx_agent_org_runtime_resume_public_timeline + ON agent_org_runtime_pause_episodes(org_run_id, resumed_at, episode_id) + WHERE resumed_at IS NOT NULL; + +CREATE INDEX idx_agent_org_runtime_run_completion_certificates_turn + ON agent_org_runtime_run_completion_certificates( + coordinator_session_id,coordinator_turn_intent_id + ); + +CREATE INDEX idx_agent_org_runtime_run_completion_public_timeline + ON agent_org_runtime_run_completion_certificates(org_run_id,created_at,id); + +CREATE INDEX idx_agent_org_runtime_runs_org_updated + ON agent_org_runtime_runs(org_id, updated_at); + +CREATE INDEX idx_agent_org_runtime_runs_root_session + ON agent_org_runtime_runs(root_session_id); + +CREATE INDEX idx_agent_org_runtime_runs_status + ON agent_org_runtime_runs(status); + +CREATE INDEX idx_agent_org_runtime_runs_work_item + ON agent_org_runtime_runs(work_item_id); + +CREATE INDEX idx_agent_org_runtime_task_annotations_page + ON agent_org_runtime_task_annotations(org_run_id, task_id, created_at, id); + +CREATE INDEX idx_agent_org_runtime_task_events_run + ON agent_org_runtime_task_events(org_run_id, created_at, id); + +CREATE INDEX idx_agent_org_runtime_task_events_task + ON agent_org_runtime_task_events(org_run_id, task_id, created_at, id); + +CREATE UNIQUE INDEX idx_agent_org_runtime_task_execution_handoffs_replacement + ON agent_org_runtime_task_execution_handoffs(org_run_id, replacement_task_id) + WHERE replacement_task_id IS NOT NULL; + +CREATE INDEX idx_agent_org_runtime_task_execution_handoffs_run + ON agent_org_runtime_task_execution_handoffs(org_run_id, activation_generation, state, requested_at, id); + +CREATE INDEX idx_agent_org_runtime_tasks_history_page + ON agent_org_runtime_tasks(org_run_id, status, updated_at, id); + +CREATE INDEX idx_agent_org_runtime_tasks_owner + ON agent_org_runtime_tasks(org_run_id, owner, status); + +CREATE INDEX idx_agent_org_runtime_tasks_page + ON agent_org_runtime_tasks(org_run_id, status, created_at, id); + +CREATE INDEX idx_agent_org_runtime_tasks_replacement + ON agent_org_runtime_tasks(org_run_id, replaces_task_id); + +CREATE INDEX idx_agent_org_runtime_turn_contexts_group_root_session + ON agent_org_runtime_turn_contexts(session_id, context_id, source_id) + WHERE source_kind='group_root'; + +CREATE UNIQUE INDEX idx_agent_org_runtime_turn_contexts_member_sequence + ON agent_org_runtime_turn_contexts( + org_run_id, dispatch_member_id, member_dispatch_sequence + ) + WHERE dispatch_member_id IS NOT NULL; + +CREATE INDEX idx_agent_org_runtime_turn_contexts_public_timeline + ON agent_org_runtime_turn_contexts(org_run_id, created_at, context_id) + WHERE source_kind IN ('group_root','group_mention'); + +CREATE INDEX idx_agent_org_runtime_turn_contexts_source + ON agent_org_runtime_turn_contexts( + org_run_id, source_kind, source_id, context_id + ); + +CREATE INDEX idx_agent_org_runtime_udw_coordinator_pending + ON agent_org_runtime_user_directed_coordinator_bindings(binding_id) + WHERE status='pending'; + +CREATE INDEX idx_agent_org_runtime_udw_member_fifo + ON agent_org_runtime_user_directed_deliveries( + org_run_id, dispatch_member_id, member_dispatch_sequence + ) WHERE status IN ('pending','started'); + +CREATE INDEX idx_agent_org_runtime_udw_pending_recovery + ON agent_org_runtime_user_directed_deliveries(delivery_id) + WHERE status='pending'; + +CREATE UNIQUE INDEX idx_agent_org_runtime_udw_source_inbox + ON agent_org_runtime_user_directed_deliveries(source_inbox_id) + WHERE source_inbox_id IS NOT NULL; + +CREATE INDEX idx_agent_org_runtime_work_episode_tasks_episode + ON agent_org_runtime_work_episode_tasks(org_run_id, work_episode_id, task_id); + +CREATE UNIQUE INDEX idx_agent_org_runtime_work_episodes_active + ON agent_org_runtime_work_episodes(org_run_id) WHERE status='active'; + +CREATE INDEX idx_agent_org_runtime_work_episodes_current + ON agent_org_runtime_work_episodes(org_run_id, episode_sequence DESC); + +CREATE INDEX idx_agent_org_scope_removal_episode + ON agent_org_scope_removal_receipts(org_run_id,work_episode_id,target_task_id); + +CREATE INDEX idx_agent_org_scope_resolution_episode + ON agent_org_scope_resolution_receipts(org_run_id,work_episode_id,task_id); + +CREATE UNIQUE INDEX idx_agent_org_task_execution_one_live + ON agent_org_task_execution_leases( + org_run_id,work_episode_id,task_id,activation_generation + ) WHERE state='active'; + +CREATE INDEX idx_agent_org_task_execution_reconciliation_task + ON agent_org_task_execution_reconciliations( + org_run_id,task_id,activation_generation + ); + +CREATE INDEX idx_agent_org_task_execution_task + ON agent_org_task_execution_leases(org_run_id,task_id,execution_epoch DESC); + +CREATE INDEX idx_agent_org_task_execution_turn + ON agent_org_task_execution_leases(session_id,turn_intent_id,state); + +CREATE TRIGGER trg_agent_org_runtime_plan_revisions_immutable + BEFORE UPDATE ON agent_org_runtime_plan_revisions + BEGIN + SELECT RAISE(ABORT, 'agent_org_plan_revision_immutable'); + END; diff --git a/src-tauri/crates/agent-core/src/core/coordination/fixtures/official_v2_0_8_agent_org.sql b/src-tauri/crates/agent-core/src/core/coordination/fixtures/official_v2_0_8_agent_org.sql new file mode 100644 index 0000000000..082e61e94f --- /dev/null +++ b/src-tauri/crates/agent-core/src/core/coordination/fixtures/official_v2_0_8_agent_org.sql @@ -0,0 +1,1399 @@ +-- Exact SQLite DDL from official v2.0.8 (55b14b1937b4cac8d4ff9acc98f7e225aba9e5c9). +-- Runtime fingerprint: ca0b99fc4d60fe4a4d691c405114d7e48009b8b86fdeec78cf1a0f82998cd352 +-- Includes the six separately owned execution companion tables. + +CREATE TABLE agent_org_coordinator_completion_rechecks ( + org_run_id TEXT NOT NULL, + source_session_id TEXT NOT NULL, + source_turn_intent_id TEXT NOT NULL, + activation_generation INTEGER NOT NULL, + work_revision INTEGER NOT NULL, + status TEXT NOT NULL CHECK(status IN ('pending','materialized','resolved')), + inbox_id INTEGER, + created_at TEXT NOT NULL, + updated_at TEXT NOT NULL, + PRIMARY KEY(org_run_id,source_session_id,source_turn_intent_id), + FOREIGN KEY(inbox_id) REFERENCES agent_org_runtime_inbox(id) ON DELETE SET NULL + ); + +CREATE TABLE agent_org_member_turn_admissions ( + session_id TEXT NOT NULL, + turn_intent_id TEXT NOT NULL, + org_run_id TEXT NOT NULL, + member_id TEXT NOT NULL CHECK(length(trim(member_id)) > 0), + reservation_id TEXT NOT NULL CHECK(length(trim(reservation_id)) > 0), + runtime_lease_id TEXT NOT NULL CHECK(length(trim(runtime_lease_id)) > 0), + status TEXT NOT NULL CHECK(status IN ( + 'prepared','committed','rejected','unknown' + )), + reason_code TEXT, + prepared_at TEXT NOT NULL, + committed_at TEXT, + terminal_at TEXT, + updated_at TEXT NOT NULL, + PRIMARY KEY(session_id, turn_intent_id), + UNIQUE(reservation_id), + FOREIGN KEY(session_id, turn_intent_id) + REFERENCES session_turn_intents(session_id, turn_intent_id) + ON DELETE CASCADE, + FOREIGN KEY(org_run_id) + REFERENCES agent_org_runtime_runs(id) ON DELETE CASCADE, + CHECK( + (status='prepared' AND committed_at IS NULL AND terminal_at IS NULL) + OR (status='committed' AND committed_at IS NOT NULL AND terminal_at IS NULL) + OR (status IN ('rejected','unknown') AND terminal_at IS NOT NULL) + ) + ); + +CREATE TABLE agent_org_runtime_archive_episodes ( + archive_receipt_id TEXT PRIMARY KEY CHECK(length(trim(archive_receipt_id)) > 0), + org_run_id TEXT NOT NULL UNIQUE, + archive_request_id TEXT NOT NULL CHECK(length(trim(archive_request_id)) > 0), + archive_generation INTEGER NOT NULL CHECK(archive_generation >= 2), + teardown_status TEXT NOT NULL CHECK(teardown_status IN ( + 'pending','quiesced','retained_runtime' + )), + teardown_attempt_count INTEGER NOT NULL DEFAULT 0 + CHECK(teardown_attempt_count BETWEEN 0 AND 3), + retained_runtime_count INTEGER NOT NULL DEFAULT 0 + CHECK(retained_runtime_count >= 0), + task_cancel_count INTEGER NOT NULL DEFAULT 0 CHECK(task_cancel_count >= 0), + turn_cancel_count INTEGER NOT NULL DEFAULT 0 CHECK(turn_cancel_count >= 0), + inbox_cancel_count INTEGER NOT NULL DEFAULT 0 CHECK(inbox_cancel_count >= 0), + approval_cancel_count INTEGER NOT NULL DEFAULT 0 CHECK(approval_cancel_count >= 0), + intervention_cancel_count INTEGER NOT NULL DEFAULT 0 CHECK(intervention_cancel_count >= 0), + pause_continuation_cancel_count INTEGER NOT NULL DEFAULT 0 + CHECK(pause_continuation_cancel_count >= 0), + deadline_at TEXT NOT NULL, + last_error TEXT, + archived_at TEXT NOT NULL, + updated_at TEXT NOT NULL, + quiesced_at TEXT, + UNIQUE(org_run_id, archive_request_id), + FOREIGN KEY(org_run_id) REFERENCES agent_org_runtime_runs(id) ON DELETE CASCADE, + CHECK( + (teardown_status='quiesced' AND quiesced_at IS NOT NULL + AND retained_runtime_count=0) + OR + (teardown_status<>'quiesced' AND quiesced_at IS NULL) + ) + ); + +CREATE TABLE agent_org_runtime_archive_teardowns ( + teardown_id TEXT PRIMARY KEY CHECK(length(trim(teardown_id)) > 0), + archive_receipt_id TEXT NOT NULL, + org_run_id TEXT NOT NULL, + session_id TEXT NOT NULL, + member_id TEXT, + captured_parent_session_id TEXT, + teardown_status TEXT NOT NULL CHECK(teardown_status IN ( + 'pending','quiesced','retained_runtime' + )), + attempt_count INTEGER NOT NULL DEFAULT 0 CHECK(attempt_count BETWEEN 0 AND 3), + runtime_lease_id TEXT, + dialog_turn_generation TEXT, + last_error TEXT, + released_at TEXT, + created_at TEXT NOT NULL, + updated_at TEXT NOT NULL, + UNIQUE(archive_receipt_id, session_id), + FOREIGN KEY(archive_receipt_id) + REFERENCES agent_org_runtime_archive_episodes(archive_receipt_id) ON DELETE CASCADE, + FOREIGN KEY(org_run_id) REFERENCES agent_org_runtime_runs(id) ON DELETE CASCADE, + CHECK( + (teardown_status='quiesced' AND released_at IS NOT NULL) + OR + (teardown_status<>'quiesced' AND released_at IS NULL) + ), + CHECK( + (runtime_lease_id IS NULL AND dialog_turn_generation IS NULL) + OR runtime_lease_id IS NOT NULL + ) + ); + +CREATE TABLE agent_org_runtime_final_summary_receipts ( + receipt_id TEXT PRIMARY KEY, + org_run_id TEXT NOT NULL, + activation_generation INTEGER NOT NULL CHECK(activation_generation >= 1), + certificate_id TEXT NOT NULL, + evidence_digest TEXT NOT NULL CHECK(length(evidence_digest)=64), + attempt INTEGER NOT NULL CHECK(attempt >= 1), + status TEXT NOT NULL CHECK(status IN ( + 'pending','running','persisting','persisted','failed' + )), + coordinator_session_id TEXT NOT NULL CHECK(trim(coordinator_session_id) <> ''), + turn_intent_id TEXT, + retry_request_id TEXT, + started_at TEXT, + terminal_at TEXT, + event_id TEXT, + typed_error TEXT, + created_at TEXT NOT NULL, + updated_at TEXT NOT NULL, + UNIQUE(certificate_id,attempt), + UNIQUE(certificate_id,retry_request_id), + FOREIGN KEY(org_run_id) REFERENCES agent_org_runtime_runs(id) ON DELETE CASCADE, + FOREIGN KEY(certificate_id) + REFERENCES agent_org_runtime_run_completion_certificates(id) + ON DELETE CASCADE, + CHECK((status='pending' AND turn_intent_id IS NULL AND started_at IS NULL) + OR (status IN ('running','persisting','persisted','failed') + AND turn_intent_id IS NOT NULL AND started_at IS NOT NULL)), + CHECK((status IN ('persisted','failed'))=(terminal_at IS NOT NULL)), + CHECK((status='persisted')=(event_id IS NOT NULL)), + CHECK((status='failed')=(typed_error IS NOT NULL)) + ); + +CREATE TABLE agent_org_runtime_formal_trigger_attempts ( + receipt_id TEXT NOT NULL, + attempt INTEGER NOT NULL CHECK(attempt >= 1), + session_id TEXT NOT NULL, + turn_intent_id TEXT NOT NULL, + status TEXT NOT NULL CHECK(status IN ('queued','running','failed','resolved')), + materialized_input_id TEXT NOT NULL, + materialized_event_id TEXT, + typed_error TEXT, + queued_at TEXT NOT NULL, + started_at TEXT, + terminal_at TEXT, + updated_at TEXT NOT NULL, + PRIMARY KEY(receipt_id,attempt), + FOREIGN KEY(receipt_id) + REFERENCES agent_org_runtime_formal_trigger_receipts(receipt_id) + ON DELETE CASCADE + ); + +CREATE TABLE agent_org_runtime_formal_trigger_receipts ( + receipt_id TEXT PRIMARY KEY, + org_run_id TEXT NOT NULL, + trigger_kind TEXT NOT NULL, + trigger_id TEXT NOT NULL, + trigger_revision INTEGER NOT NULL CHECK(trigger_revision >= 1), + source_kind TEXT NOT NULL, + target_member_id TEXT NOT NULL CHECK(target_member_id='coordinator'), + inbox_id INTEGER, + task_id TEXT, + owner_member_id TEXT, + source_turn_intent_id TEXT, + task_output_digest TEXT CHECK( + task_output_digest IS NULL OR length(task_output_digest)=64 + ), + plan_revision_id TEXT, + status TEXT NOT NULL CHECK(status IN ('pending','materialized','resolved')), + doorbell_status TEXT NOT NULL CHECK(doorbell_status IN ('missing','delivered','suppressed')), + doorbell_delivered_at TEXT, + current_attempt INTEGER NOT NULL DEFAULT 0 CHECK(current_attempt >= 0), + materialized_input_id TEXT, + materialized_event_id TEXT, + resolved_at TEXT, + created_at TEXT NOT NULL, + updated_at TEXT NOT NULL, + UNIQUE(org_run_id,trigger_kind,trigger_id,trigger_revision), + UNIQUE(inbox_id), + FOREIGN KEY(org_run_id) REFERENCES agent_org_runtime_runs(id) ON DELETE CASCADE, + FOREIGN KEY(inbox_id) REFERENCES agent_org_runtime_inbox(id) ON DELETE CASCADE + ); + +CREATE TABLE agent_org_runtime_inbox ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + delivery_class TEXT NOT NULL DEFAULT 'formal_work' + CHECK(delivery_class IN ('formal_work','user_directed')), + recipient_agent_id TEXT NOT NULL, + recipient_member_id TEXT, + sender_agent_id TEXT NOT NULL, + sender_member_id TEXT, + org_run_id TEXT, + payload_kind TEXT NOT NULL, + payload_json TEXT NOT NULL, + request_id TEXT, + created_at TEXT NOT NULL, + read_at TEXT, + causation_inbox_id INTEGER, + display_text TEXT, + client_message_id TEXT + ); + +CREATE TABLE agent_org_runtime_inbox_delivery_resolutions ( + inbox_id INTEGER PRIMARY KEY, + org_run_id TEXT NOT NULL, + resolution_kind TEXT NOT NULL + CHECK(resolution_kind IN ('cancelled', 'superseded')), + resolved_by_member_id TEXT NOT NULL, + reason TEXT NOT NULL, + replacement_inbox_id INTEGER, + replacement_task_id TEXT, + created_at TEXT NOT NULL, + CHECK( + (resolution_kind='cancelled' + AND replacement_inbox_id IS NULL + AND replacement_task_id IS NULL) + OR + (resolution_kind='superseded' + AND ((replacement_inbox_id IS NOT NULL) + <> (replacement_task_id IS NOT NULL))) + ) + ); + +CREATE TABLE agent_org_runtime_inbox_materializations ( + inbox_id INTEGER PRIMARY KEY, + session_id TEXT NOT NULL, + transcript_message_id TEXT NOT NULL, + transcript_intent_id TEXT NOT NULL, + materialized_at TEXT NOT NULL + ); + +CREATE TABLE agent_org_runtime_inbox_task_bindings ( + inbox_id INTEGER PRIMARY KEY, + org_run_id TEXT NOT NULL, + task_id TEXT NOT NULL, + recipient_member_id TEXT NOT NULL, + binding_kind TEXT NOT NULL CHECK(binding_kind='coordinator_task_message'), + source_turn_intent_id TEXT NOT NULL, + created_at TEXT NOT NULL, + FOREIGN KEY(inbox_id) + REFERENCES agent_org_runtime_inbox(id) ON DELETE CASCADE, + FOREIGN KEY(org_run_id,task_id) + REFERENCES agent_org_runtime_tasks(org_run_id,id) ON DELETE CASCADE + ); + +CREATE TABLE agent_org_runtime_initial_inputs ( + org_run_id TEXT PRIMARY KEY, + turn_intent_id TEXT NOT NULL, + message_id TEXT NOT NULL, + content TEXT NOT NULL, + payload_json TEXT NOT NULL, + status TEXT NOT NULL CHECK(status IN ( + 'pending_persistence', 'queued', 'dispatched' + )), + created_at TEXT NOT NULL, + updated_at TEXT NOT NULL, + UNIQUE(turn_intent_id), + UNIQUE(message_id), + FOREIGN KEY(org_run_id) REFERENCES agent_org_runtime_runs(id) ON DELETE CASCADE + ); + +CREATE TABLE agent_org_runtime_member_dispatch_allocators ( + org_run_id TEXT NOT NULL, + member_id TEXT NOT NULL CHECK(length(trim(member_id)) > 0), + next_sequence INTEGER NOT NULL CHECK(next_sequence >= 1), + PRIMARY KEY(org_run_id, member_id), + FOREIGN KEY(org_run_id) REFERENCES agent_org_runtime_runs(id) ON DELETE CASCADE + ); + +CREATE TABLE agent_org_runtime_member_intervention_turns ( + intervention_receipt_id TEXT NOT NULL, + session_id TEXT NOT NULL, + turn_intent_id TEXT NOT NULL, + source_event_id TEXT NOT NULL, + dispatch_content TEXT NOT NULL CHECK(length(trim(dispatch_content)) > 0), + display_content TEXT NOT NULL CHECK(length(trim(display_content)) > 0), + member_dispatch_sequence INTEGER NOT NULL CHECK(member_dispatch_sequence >= 1), + chain_position INTEGER NOT NULL CHECK(chain_position >= 1), + status TEXT NOT NULL CHECK(status IN ('queued','running','completed','failed','cancelled','abandoned')), + enqueued_at TEXT NOT NULL, + started_at TEXT, + terminal_at TEXT, + failure_reason TEXT, + PRIMARY KEY(intervention_receipt_id, turn_intent_id), + UNIQUE(intervention_receipt_id, chain_position), + UNIQUE(source_event_id), + FOREIGN KEY(intervention_receipt_id) + REFERENCES agent_org_runtime_member_interventions(intervention_receipt_id) + ON DELETE CASCADE, + FOREIGN KEY(session_id, turn_intent_id) + REFERENCES session_turn_intents(session_id, turn_intent_id) + ON DELETE CASCADE + ); + +CREATE TABLE agent_org_runtime_member_interventions ( + intervention_receipt_id TEXT PRIMARY KEY, + org_run_id TEXT NOT NULL, + member_id TEXT NOT NULL CHECK(length(trim(member_id)) > 0), + agent_id TEXT NOT NULL CHECK(length(trim(agent_id)) > 0), + session_id TEXT NOT NULL CHECK(length(trim(session_id)) > 0), + status TEXT NOT NULL CHECK(status IN ( + 'yield_requested','active','return_requested','cleared','failed' + )), + source_event_id TEXT NOT NULL CHECK(length(trim(source_event_id)) > 0), + original_task_id TEXT, + original_turn_intent_id TEXT, + original_member_dispatch_sequence INTEGER, + runtime_lease_id TEXT, + dialog_turn_generation TEXT, + entered_at TEXT NOT NULL, + last_user_activity_at TEXT NOT NULL, + yield_requested_at TEXT, + yield_released_at TEXT, + yield_timed_out_at TEXT, + return_request_id TEXT, + return_outcome TEXT CHECK(return_outcome IS NULL OR return_outcome IN ( + 'restored_task','cleared_paused','cleared_idle','no_longer_needed' + )), + continuation_turn_intent_id TEXT, + cleared_revision INTEGER, + cleared_at TEXT, + failure_reason TEXT, + updated_at TEXT NOT NULL, + FOREIGN KEY(org_run_id) REFERENCES agent_org_runtime_runs(id) ON DELETE CASCADE, + CHECK((runtime_lease_id IS NULL) = (dialog_turn_generation IS NULL)), + CHECK((original_task_id IS NULL) = (original_turn_intent_id IS NULL)), + CHECK((cleared_at IS NULL) = (status NOT IN ('cleared','failed'))) + ); + +CREATE TABLE agent_org_runtime_member_materializations ( + org_run_id TEXT NOT NULL, + member_id TEXT NOT NULL, + agent_id TEXT NOT NULL, + generation INTEGER NOT NULL CHECK(generation >= 1), + session_id TEXT NOT NULL, + authority_class TEXT NOT NULL CHECK(authority_class IN ( + 'starting', 'formal', 'user_directed' + )), + status TEXT NOT NULL CHECK(status IN ( + 'pending', 'succeeded', 'failed' + )), + error_code TEXT, + error_json TEXT, + created_at TEXT NOT NULL, + updated_at TEXT NOT NULL, + PRIMARY KEY(org_run_id, member_id, generation), + UNIQUE(org_run_id, session_id), + FOREIGN KEY(org_run_id) REFERENCES agent_org_runtime_runs(id) ON DELETE CASCADE + ); + +CREATE TABLE agent_org_runtime_pause_episodes ( + episode_id TEXT PRIMARY KEY CHECK(length(trim(episode_id)) > 0), + org_run_id TEXT NOT NULL, + pause_request_id TEXT NOT NULL CHECK(length(trim(pause_request_id)) > 0), + pause_generation INTEGER NOT NULL CHECK(pause_generation >= 2), + status TEXT NOT NULL CHECK(status IN ('active','consumed')), + resume_request_id TEXT, + resume_generation INTEGER, + teardown_owner_id TEXT NOT NULL CHECK(length(trim(teardown_owner_id)) > 0), + created_at TEXT NOT NULL, + updated_at TEXT NOT NULL, + resumed_at TEXT, + UNIQUE(org_run_id, pause_request_id), + UNIQUE(resume_request_id), + FOREIGN KEY(org_run_id) REFERENCES agent_org_runtime_runs(id) ON DELETE CASCADE, + CHECK( + (status='active' AND resume_request_id IS NULL + AND resume_generation IS NULL AND resumed_at IS NULL) + OR + (status='consumed' AND resume_request_id IS NOT NULL + AND resume_generation IS NOT NULL AND resume_generation > pause_generation + AND resumed_at IS NOT NULL) + ) + ); + +CREATE TABLE agent_org_runtime_pause_handoffs ( + handoff_id TEXT PRIMARY KEY CHECK(length(trim(handoff_id)) > 0), + episode_id TEXT NOT NULL, + org_run_id TEXT NOT NULL, + session_id TEXT NOT NULL, + original_turn_intent_id TEXT NOT NULL, + turn_kind TEXT NOT NULL CHECK(turn_kind IN ('coordinator','task_execution')), + participant_id TEXT NOT NULL, + task_id TEXT, + original_owner_member_id TEXT, + original_activation_generation INTEGER NOT NULL CHECK(original_activation_generation >= 1), + original_intent_status TEXT NOT NULL CHECK(original_intent_status IN ('queued','running')), + drain_status TEXT NOT NULL CHECK(drain_status IN ( + 'waiting','released','runtime_absent','timed_out' + )), + runtime_lease_id TEXT, + dialog_turn_generation TEXT, + yield_requested_at TEXT, + released_at TEXT, + drain_timeout_at TEXT, + drain_error TEXT, + continuation_turn_intent_id TEXT, + continuation_status TEXT CHECK(continuation_status IN ('queued','dispatched','skipped')), + skip_reason TEXT, + created_at TEXT NOT NULL, + updated_at TEXT NOT NULL, + UNIQUE(episode_id, session_id, original_turn_intent_id), + UNIQUE(continuation_turn_intent_id), + FOREIGN KEY(episode_id) REFERENCES agent_org_runtime_pause_episodes(episode_id) ON DELETE CASCADE, + FOREIGN KEY(org_run_id) REFERENCES agent_org_runtime_runs(id) ON DELETE CASCADE, + FOREIGN KEY(session_id, original_turn_intent_id) + REFERENCES agent_org_runtime_turn_contexts(session_id, turn_intent_id) + ON DELETE CASCADE, + CHECK( + (turn_kind='coordinator' AND task_id IS NULL AND original_owner_member_id IS NULL) + OR + (turn_kind='task_execution' AND task_id IS NOT NULL + AND original_owner_member_id=participant_id) + ), + CHECK( + (runtime_lease_id IS NULL AND dialog_turn_generation IS NULL) + OR + (runtime_lease_id IS NOT NULL AND dialog_turn_generation IS NOT NULL) + ), + CHECK( + (continuation_status IS NULL AND continuation_turn_intent_id IS NULL AND skip_reason IS NULL) + OR + (continuation_status IN ('queued','dispatched') + AND continuation_turn_intent_id IS NOT NULL AND skip_reason IS NULL) + OR + (continuation_status='skipped' AND skip_reason IS NOT NULL) + ) + ); + +CREATE TABLE agent_org_runtime_plan_decisions ( + approval_id TEXT PRIMARY KEY, + plan_revision_id TEXT NOT NULL UNIQUE, + request_id TEXT NOT NULL UNIQUE, + policy TEXT NOT NULL CHECK(policy IN ('coordinator','user','automatic')), + status TEXT NOT NULL CHECK(status IN ( + 'pending','approved','changes_requested','superseded','cancelled' + )), + decision_by TEXT CHECK(decision_by IS NULL OR decision_by IN ( + 'user','coordinator','automatic' + )), + feedback TEXT, + created_at TEXT NOT NULL, + resolved_at TEXT, + FOREIGN KEY(plan_revision_id) + REFERENCES agent_org_runtime_plan_revisions(plan_revision_id) + ON DELETE CASCADE, + CHECK( + (status='pending' AND decision_by IS NULL AND resolved_at IS NULL) + OR + (status!='pending' AND decision_by IS NOT NULL AND resolved_at IS NOT NULL) + ) + ); + +CREATE TABLE agent_org_runtime_plan_revisions ( + plan_revision_id TEXT PRIMARY KEY, + org_run_id TEXT NOT NULL, + source_task_id TEXT NOT NULL, + source_member_id TEXT NOT NULL, + source_session_id TEXT NOT NULL, + source_turn_intent_id TEXT NOT NULL, + root_session_id TEXT NOT NULL, + revision_number INTEGER NOT NULL CHECK(revision_number >= 1), + previous_plan_revision_id TEXT, + plan_title TEXT NOT NULL, + plan_path TEXT NOT NULL, + plan_content TEXT NOT NULL, + content_digest TEXT NOT NULL CHECK(length(content_digest)=64), + created_at TEXT NOT NULL, + UNIQUE(org_run_id, source_task_id, revision_number), + FOREIGN KEY(org_run_id) REFERENCES agent_org_runtime_runs(id) ON DELETE CASCADE, + FOREIGN KEY(previous_plan_revision_id) + REFERENCES agent_org_runtime_plan_revisions(plan_revision_id) + ); + +CREATE TABLE agent_org_runtime_recovery_attempts ( + org_run_id TEXT NOT NULL, + action_kind TEXT NOT NULL, + target_key TEXT NOT NULL, + reason_fingerprint TEXT NOT NULL, + attempts INTEGER NOT NULL DEFAULT 0, + next_allowed_at TEXT NOT NULL, + updated_at TEXT NOT NULL, + reservation_token TEXT, + PRIMARY KEY (org_run_id, action_kind, target_key) + ); + +CREATE TABLE agent_org_runtime_run_completion_certificates ( + id TEXT PRIMARY KEY, + org_run_id TEXT NOT NULL, + activation_generation INTEGER NOT NULL CHECK(activation_generation >= 1), + work_revision INTEGER NOT NULL CHECK(work_revision >= 0), + request_id TEXT NOT NULL CHECK(trim(request_id) <> ''), + request_digest TEXT NOT NULL CHECK(length(request_digest)=64), + outcome TEXT NOT NULL CHECK(outcome IN ('delivered','cancelled','failed')), + summary TEXT NOT NULL CHECK(trim(summary) <> ''), + coordinator_session_id TEXT NOT NULL CHECK(trim(coordinator_session_id) <> ''), + coordinator_turn_intent_id TEXT NOT NULL CHECK(trim(coordinator_turn_intent_id) <> ''), + evidence_task_ids_json TEXT NOT NULL CHECK(json_valid(evidence_task_ids_json)=1 AND json_type(evidence_task_ids_json)='array'), + closure_task_ids_json TEXT NOT NULL CHECK(json_valid(closure_task_ids_json)=1 AND json_type(closure_task_ids_json)='array'), + task_output_refs_json TEXT NOT NULL CHECK(json_valid(task_output_refs_json)=1 AND json_type(task_output_refs_json)='array'), + resolution_links_json TEXT NOT NULL CHECK(json_valid(resolution_links_json)=1 AND json_type(resolution_links_json)='array'), + validator_version INTEGER NOT NULL CHECK(validator_version=1), + created_at TEXT NOT NULL, + UNIQUE(org_run_id, request_id), + FOREIGN KEY (org_run_id) REFERENCES agent_org_runtime_runs(id) ON DELETE CASCADE + ); + +CREATE TABLE agent_org_runtime_run_progress ( + org_run_id TEXT PRIMARY KEY, + work_revision INTEGER NOT NULL DEFAULT 0 CHECK(work_revision >= 0), + coordinator_presented_work_revision INTEGER, + coordinator_observed_work_revision INTEGER, + completion_requested INTEGER NOT NULL DEFAULT 0, + completion_requested_at TEXT, + completion_requested_work_revision INTEGER, + completion_summary TEXT, + updated_at TEXT NOT NULL, + FOREIGN KEY(org_run_id) REFERENCES agent_org_runtime_runs(id) ON DELETE CASCADE + ); + +CREATE TABLE agent_org_runtime_runs ( + id TEXT PRIMARY KEY, + org_id TEXT NOT NULL, + coordinator_agent_id TEXT NOT NULL, + root_session_id TEXT, + org_snapshot_json TEXT, + entry_mode TEXT NOT NULL, + status TEXT NOT NULL CHECK(status IN ( + 'starting', 'running', 'paused', 'idle', 'failed', 'archived' + )), + activation_generation INTEGER NOT NULL DEFAULT 1 + CHECK(activation_generation >= 1), + has_initial_work INTEGER NOT NULL DEFAULT 0 + CHECK(has_initial_work IN (0, 1)), + work_item_id TEXT, + project_slug TEXT, + routine_fire_id TEXT, + summary TEXT, + last_error TEXT, + failure_json TEXT, + last_activity_outcome TEXT CHECK(last_activity_outcome IN ( + 'completed', 'failed', 'cancelled' + )), + created_at TEXT NOT NULL, + updated_at TEXT NOT NULL, + idled_at TEXT, + archived_at TEXT, + archive_receipt_id TEXT UNIQUE, + CHECK( + (status='archived' AND archived_at IS NOT NULL AND archive_receipt_id IS NOT NULL) + OR + (status<>'archived' AND archived_at IS NULL AND archive_receipt_id IS NULL) + ) + ); + +CREATE TABLE agent_org_runtime_task_annotations ( + id TEXT PRIMARY KEY, + org_run_id TEXT NOT NULL, + task_id TEXT NOT NULL, + kind TEXT NOT NULL CHECK(kind IN ('progress','evidence','audit_note')), + body TEXT NOT NULL CHECK(trim(body) <> ''), + actor_kind TEXT NOT NULL CHECK(actor_kind IN ('graph_writer','owner_execution','system')), + actor_participant_id TEXT NOT NULL CHECK(trim(actor_participant_id) <> ''), + source_turn_intent_id TEXT, + created_at TEXT NOT NULL, + FOREIGN KEY (org_run_id, task_id) + REFERENCES agent_org_runtime_tasks(org_run_id, id) ON DELETE CASCADE + ); + +CREATE TABLE agent_org_runtime_task_events ( + id TEXT PRIMARY KEY, + org_run_id TEXT NOT NULL, + task_id TEXT NOT NULL, + event_type TEXT NOT NULL, + previous_owner TEXT, + next_owner TEXT, + previous_status TEXT, + next_status TEXT, + actor_member_id TEXT, + actor_kind TEXT NOT NULL CHECK(actor_kind IN ('graph_writer','owner_execution','system')), + source_turn_intent_id TEXT, + created_at TEXT NOT NULL + ); + +CREATE TABLE agent_org_runtime_task_execution_handoffs ( + id TEXT PRIMARY KEY, + org_run_id TEXT NOT NULL, + activation_generation INTEGER NOT NULL CHECK(activation_generation >= 1), + request_id TEXT NOT NULL CHECK(trim(request_id) <> ''), + request_digest TEXT NOT NULL CHECK(length(request_digest)=64), + old_task_id TEXT NOT NULL, + old_owner_member_id TEXT NOT NULL CHECK(trim(old_owner_member_id) <> ''), + old_session_id TEXT, + old_turn_intent_id TEXT, + runtime_lease_id TEXT, + dialog_turn_generation TEXT, + replacement_task_id TEXT, + state TEXT NOT NULL CHECK(state IN ('requested','yielding','released','timeout','unknown','failed')), + slo_missed INTEGER NOT NULL DEFAULT 0 CHECK(slo_missed IN (0,1)), + external_effect_unknown INTEGER NOT NULL DEFAULT 0 CHECK(external_effect_unknown IN (0,1)), + local_effect_count INTEGER NOT NULL DEFAULT 0 CHECK(local_effect_count >= 0), + resolution_request_id TEXT, + resolution_session_id TEXT, + requested_resolution TEXT CHECK(requested_resolution IN ('continue_replacement','keep_stopped','abandon_episode')), + resolution_attempt INTEGER NOT NULL DEFAULT 0 CHECK(resolution_attempt >= 0), + resolution_requested_at TEXT, + resolution TEXT CHECK(resolution IN ('continue_replacement','keep_stopped','abandon_episode')), + requested_at TEXT NOT NULL, + released_at TEXT, + resolved_at TEXT, + updated_at TEXT NOT NULL, + UNIQUE(org_run_id, activation_generation, request_id), + UNIQUE(org_run_id, activation_generation, resolution_request_id), + UNIQUE(org_run_id, activation_generation, old_task_id, old_turn_intent_id), + FOREIGN KEY (org_run_id, old_task_id) + REFERENCES agent_org_runtime_tasks(org_run_id, id), + FOREIGN KEY (org_run_id, replacement_task_id) + REFERENCES agent_org_runtime_tasks(org_run_id, id), + CHECK((old_session_id IS NULL) = (old_turn_intent_id IS NULL)), + CHECK((runtime_lease_id IS NULL) = (dialog_turn_generation IS NULL)), + CHECK(runtime_lease_id IS NULL OR old_session_id IS NOT NULL), + CHECK(state <> 'released' OR released_at IS NOT NULL), + CHECK( + (requested_resolution IS NULL AND resolution_request_id IS NULL + AND resolution_session_id IS NULL AND resolution_attempt=0 + AND resolution_requested_at IS NULL) + OR + (requested_resolution IS NOT NULL AND resolution_request_id IS NOT NULL + AND resolution_session_id IS NOT NULL AND resolution_attempt>=1 + AND resolution_requested_at IS NOT NULL) + ), + CHECK(resolution IS NULL OR ( + resolved_at IS NOT NULL AND resolution=requested_resolution + )) + ); + +CREATE TABLE agent_org_runtime_tasks ( + id TEXT NOT NULL, + org_run_id TEXT NOT NULL, + activation_generation INTEGER NOT NULL CHECK(activation_generation >= 1), + subject TEXT NOT NULL, + description TEXT NOT NULL DEFAULT '', + active_form TEXT, + owner TEXT, + status TEXT NOT NULL CHECK(status IN ('pending','in_progress','completed','failed','cancelled')), + execution_mode TEXT NOT NULL CHECK(execution_mode IN ('build','plan')), + blocked_by_json TEXT NOT NULL DEFAULT '[]', + metadata_json TEXT, + output_json TEXT, + failure_reason_json TEXT, + cancel_reason_json TEXT, + external_effect_unknown INTEGER NOT NULL DEFAULT 0 + CHECK(external_effect_unknown IN (0,1)), + created_by_participant_id TEXT NOT NULL CHECK(trim(created_by_participant_id) <> ''), + source_turn_intent_id TEXT NOT NULL CHECK(trim(source_turn_intent_id) <> ''), + originating_message_id TEXT, + replaces_task_id TEXT, + created_at TEXT NOT NULL, + updated_at TEXT NOT NULL, + PRIMARY KEY (org_run_id, id), + FOREIGN KEY (org_run_id, replaces_task_id) + REFERENCES agent_org_runtime_tasks(org_run_id, id), + CHECK(owner IS NULL OR (trim(owner) <> '' AND owner <> 'coordinator')), + CHECK(replaces_task_id IS NULL OR replaces_task_id <> id), + CHECK(json_valid(blocked_by_json)=1 AND json_type(blocked_by_json)='array'), + CHECK(metadata_json IS NULL OR ( + json_valid(metadata_json)=1 AND json_type(metadata_json)='object' + AND json_type(metadata_json,'$.output') IS NULL + AND json_type(metadata_json,'$.execution_mode') IS NULL + )), + CHECK(output_json IS NULL OR (json_valid(output_json)=1 AND json_type(output_json)='object')), + CHECK(failure_reason_json IS NULL OR (json_valid(failure_reason_json)=1 AND json_type(failure_reason_json)='object')), + CHECK(cancel_reason_json IS NULL OR (json_valid(cancel_reason_json)=1 AND json_type(cancel_reason_json)='object')), + CHECK(status NOT IN ('in_progress','completed','failed') OR owner IS NOT NULL), + CHECK( + (status IN ('pending','in_progress') AND output_json IS NULL AND failure_reason_json IS NULL AND cancel_reason_json IS NULL) + OR (status='completed' AND output_json IS NOT NULL AND failure_reason_json IS NULL AND cancel_reason_json IS NULL) + OR (status='failed' AND output_json IS NULL AND failure_reason_json IS NOT NULL AND cancel_reason_json IS NULL) + OR (status='cancelled' AND output_json IS NULL AND failure_reason_json IS NULL AND cancel_reason_json IS NOT NULL) + ) + ); + +CREATE TABLE agent_org_runtime_tool_call_receipts ( + org_run_id TEXT NOT NULL, + session_id TEXT NOT NULL, + turn_intent_id TEXT NOT NULL, + call_id TEXT NOT NULL, + tool_name TEXT NOT NULL, + operation TEXT NOT NULL, + canonical_digest TEXT NOT NULL, + result_text TEXT, + error_kind TEXT, + error_text TEXT, + created_at TEXT NOT NULL, + PRIMARY KEY (org_run_id, session_id, turn_intent_id, call_id), + FOREIGN KEY (org_run_id) + REFERENCES agent_org_runtime_runs(id) ON DELETE CASCADE, + CHECK (trim(org_run_id) <> '' AND org_run_id = trim(org_run_id)), + CHECK (trim(session_id) <> '' AND session_id = trim(session_id)), + CHECK (trim(turn_intent_id) <> '' AND turn_intent_id = trim(turn_intent_id)), + CHECK (trim(call_id) <> '' AND call_id = trim(call_id)), + CHECK (trim(tool_name) <> '' AND length(CAST(tool_name AS BLOB)) <= 128), + CHECK (trim(operation) <> '' AND length(CAST(operation AS BLOB)) <= 128), + CHECK (length(canonical_digest) = 64 AND canonical_digest NOT GLOB '*[^0-9a-f]*'), + CHECK ( + (result_text IS NOT NULL AND error_kind IS NULL AND error_text IS NULL) + OR + (result_text IS NULL AND error_kind IN ('invalid_params','execution_failed','permission_denied','timeout') AND error_text IS NOT NULL) + ), + CHECK (result_text IS NULL OR length(CAST(result_text AS BLOB)) <= 524288), + CHECK (error_text IS NULL OR length(CAST(error_text AS BLOB)) <= 65536), + CHECK (length(created_at) <= 64 AND length(CAST(created_at AS BLOB)) <= 256) + ); + +CREATE TABLE agent_org_runtime_turn_contexts ( + context_id INTEGER PRIMARY KEY AUTOINCREMENT, + session_id TEXT NOT NULL CHECK(length(trim(session_id)) > 0), + turn_intent_id TEXT NOT NULL CHECK(length(trim(turn_intent_id)) > 0), + org_run_id TEXT NOT NULL, + participant_id TEXT NOT NULL CHECK(length(trim(participant_id)) > 0), + turn_kind TEXT NOT NULL, + task_id TEXT, + owner_member_id TEXT, + dispatch_member_id TEXT, + member_dispatch_sequence INTEGER, + source_kind TEXT NOT NULL, + source_id TEXT NOT NULL CHECK(length(trim(source_id)) > 0), + root_authority_turn_id TEXT, + actor_version INTEGER, + activation_generation INTEGER, + coordinator_work_revision INTEGER, + coordinator_observed_task_ids_json TEXT NOT NULL DEFAULT '[]' + CHECK(json_valid(coordinator_observed_task_ids_json)=1 + AND json_type(coordinator_observed_task_ids_json)='array' + AND json_array_length(coordinator_observed_task_ids_json) <= 32), + terminal_reason TEXT, + created_at TEXT NOT NULL, + UNIQUE(session_id, turn_intent_id), + FOREIGN KEY(session_id, turn_intent_id) + REFERENCES session_turn_intents(session_id, turn_intent_id) + ON DELETE CASCADE, + FOREIGN KEY(org_run_id) + REFERENCES agent_org_runtime_runs(id) ON DELETE CASCADE, + CHECK( + (turn_kind='coordinator' + AND participant_id='coordinator' + AND task_id IS NULL AND owner_member_id IS NULL + AND dispatch_member_id IS NULL AND member_dispatch_sequence IS NULL + AND ( + (source_kind IN ('root_turn','group_root') + AND (source_kind<>'root_turn' OR source_id=turn_intent_id) + AND root_authority_turn_id IS NULL AND actor_version IS NULL + AND activation_generation IS NOT NULL AND activation_generation >= 1 + AND (coordinator_work_revision IS NULL OR coordinator_work_revision >= 0) + AND (terminal_reason IS NULL OR terminal_reason='waiting_for_org_event')) + OR + (source_kind='member_inbox' + AND root_authority_turn_id IS NOT NULL + AND length(trim(root_authority_turn_id)) > 0 + AND actor_version IS NOT NULL AND actor_version >= 1 + AND activation_generation IS NULL + AND coordinator_work_revision IS NULL + AND coordinator_observed_task_ids_json='[]' AND terminal_reason IS NULL) + )) + OR + (turn_kind='task_execution' + AND task_id IS NOT NULL AND length(trim(task_id)) > 0 + AND owner_member_id=participant_id + AND dispatch_member_id=participant_id + AND member_dispatch_sequence IS NOT NULL AND member_dispatch_sequence >= 1 + AND source_kind='task' AND source_id=task_id + AND root_authority_turn_id IS NULL AND actor_version IS NULL + AND activation_generation IS NOT NULL AND activation_generation >= 1 + AND coordinator_work_revision IS NULL + AND coordinator_observed_task_ids_json='[]' AND terminal_reason IS NULL) + OR + (turn_kind='user_directed_work' + AND task_id IS NULL AND owner_member_id IS NULL + AND dispatch_member_id=participant_id + AND member_dispatch_sequence IS NOT NULL AND member_dispatch_sequence >= 1 + AND actor_version IS NOT NULL AND actor_version >= 1 + AND activation_generation IS NULL + AND coordinator_work_revision IS NULL + AND coordinator_observed_task_ids_json='[]' AND terminal_reason IS NULL + AND ( + (source_kind='direct_member' + AND root_authority_turn_id=turn_intent_id) + OR + (source_kind='group_mention' + AND root_authority_turn_id=turn_intent_id) + OR + (source_kind='member_inbox' + AND root_authority_turn_id IS NOT NULL + AND length(trim(root_authority_turn_id)) > 0) + )) + ) + ); + +CREATE TABLE agent_org_runtime_user_directed_coordinator_bindings ( + binding_id INTEGER PRIMARY KEY AUTOINCREMENT, + org_run_id TEXT NOT NULL, + session_id TEXT NOT NULL CHECK(length(trim(session_id)) > 0), + turn_intent_id TEXT NOT NULL CHECK(length(trim(turn_intent_id)) > 0), + root_authority_turn_id TEXT NOT NULL CHECK(length(trim(root_authority_turn_id)) > 0), + parent_delivery_id INTEGER NOT NULL, + parent_inbox_id INTEGER, + source_inbox_id INTEGER NOT NULL, + depth INTEGER NOT NULL CHECK(depth >= 1), + delivery_ordinal INTEGER NOT NULL CHECK(delivery_ordinal >= 2), + request_digest TEXT NOT NULL + CHECK(length(request_digest)=64 AND request_digest NOT GLOB '*[^0-9a-f]*'), + dispatch_content TEXT NOT NULL CHECK(length(trim(dispatch_content)) > 0), + display_content TEXT NOT NULL CHECK(length(trim(display_content)) > 0), + status TEXT NOT NULL + CHECK(status IN ('pending','started','completed','failed','cancelled','abandoned','unknown')), + created_at TEXT NOT NULL, + started_at TEXT, + terminal_at TEXT, + failure_reason TEXT, + UNIQUE(session_id,turn_intent_id), + UNIQUE(source_inbox_id), + UNIQUE(org_run_id,root_authority_turn_id,delivery_ordinal), + FOREIGN KEY(org_run_id,root_authority_turn_id) + REFERENCES agent_org_runtime_user_directed_roots(org_run_id,root_authority_turn_id) + ON DELETE CASCADE, + FOREIGN KEY(session_id,turn_intent_id) + REFERENCES agent_org_runtime_turn_contexts(session_id,turn_intent_id) + ON DELETE CASCADE, + FOREIGN KEY(parent_delivery_id) + REFERENCES agent_org_runtime_user_directed_deliveries(delivery_id) ON DELETE RESTRICT, + FOREIGN KEY(parent_inbox_id) REFERENCES agent_org_runtime_inbox(id) ON DELETE RESTRICT, + FOREIGN KEY(source_inbox_id) REFERENCES agent_org_runtime_inbox(id) ON DELETE RESTRICT, + CHECK(parent_inbox_id IS NULL OR parent_inbox_id<>source_inbox_id), + CHECK( + (status='pending' AND started_at IS NULL AND terminal_at IS NULL AND failure_reason IS NULL) + OR + (status='started' AND started_at IS NOT NULL AND terminal_at IS NULL AND failure_reason IS NULL) + OR + (status IN ('completed','cancelled') AND started_at IS NOT NULL AND terminal_at IS NOT NULL) + OR + (status IN ('failed','abandoned','unknown') AND terminal_at IS NOT NULL) + ) + ); + +CREATE TABLE agent_org_runtime_user_directed_deliveries ( + delivery_id INTEGER PRIMARY KEY AUTOINCREMENT, + org_run_id TEXT NOT NULL, + session_id TEXT NOT NULL CHECK(length(trim(session_id)) > 0), + turn_intent_id TEXT NOT NULL CHECK(length(trim(turn_intent_id)) > 0), + root_authority_turn_id TEXT NOT NULL CHECK(length(trim(root_authority_turn_id)) > 0), + parent_delivery_id INTEGER, + parent_inbox_id INTEGER, + source_kind TEXT NOT NULL + CHECK(source_kind IN ('direct_member','group_mention','member_inbox')), + source_event_id TEXT, + source_inbox_id INTEGER, + dispatch_member_id TEXT NOT NULL CHECK(length(trim(dispatch_member_id)) > 0), + member_dispatch_sequence INTEGER NOT NULL CHECK(member_dispatch_sequence >= 1), + depth INTEGER NOT NULL CHECK(depth >= 0), + delivery_ordinal INTEGER NOT NULL CHECK(delivery_ordinal >= 1), + request_digest TEXT NOT NULL + CHECK(length(request_digest)=64 AND request_digest NOT GLOB '*[^0-9a-f]*'), + dispatch_content TEXT NOT NULL CHECK(length(trim(dispatch_content)) > 0), + display_content TEXT NOT NULL CHECK(length(trim(display_content)) > 0), + images_json TEXT NOT NULL DEFAULT '[]' + CHECK(json_valid(images_json)=1 AND json_type(images_json)='array'), + status TEXT NOT NULL + CHECK(status IN ('pending','started','completed','failed','cancelled','abandoned','unknown')), + created_at TEXT NOT NULL, + started_at TEXT, + terminal_at TEXT, + failure_reason TEXT, + UNIQUE(session_id, turn_intent_id), + UNIQUE(org_run_id, root_authority_turn_id, delivery_ordinal), + FOREIGN KEY(org_run_id, root_authority_turn_id) + REFERENCES agent_org_runtime_user_directed_roots(org_run_id, root_authority_turn_id) + ON DELETE CASCADE, + FOREIGN KEY(session_id, turn_intent_id) + REFERENCES agent_org_runtime_turn_contexts(session_id, turn_intent_id) + ON DELETE CASCADE, + FOREIGN KEY(parent_delivery_id) + REFERENCES agent_org_runtime_user_directed_deliveries(delivery_id) ON DELETE RESTRICT, + FOREIGN KEY(source_inbox_id) + REFERENCES agent_org_runtime_inbox(id) ON DELETE RESTRICT, + FOREIGN KEY(parent_inbox_id) + REFERENCES agent_org_runtime_inbox(id) ON DELETE RESTRICT, + CHECK( + (source_kind='direct_member' + AND source_event_id IS NOT NULL + AND source_inbox_id IS NULL AND parent_delivery_id IS NULL + AND parent_inbox_id IS NULL + AND depth=0 AND root_authority_turn_id=turn_intent_id) + OR + (source_kind='group_mention' + AND source_event_id IS NULL + AND source_inbox_id IS NOT NULL AND parent_delivery_id IS NULL + AND parent_inbox_id IS NULL + AND depth=0 AND root_authority_turn_id=turn_intent_id) + OR + (source_kind='member_inbox' + AND source_event_id IS NULL + AND source_inbox_id IS NOT NULL AND parent_delivery_id IS NOT NULL + AND depth>=1) + ), + CHECK( + (status='pending' AND started_at IS NULL AND terminal_at IS NULL AND failure_reason IS NULL) + OR + (status='started' AND started_at IS NOT NULL AND terminal_at IS NULL AND failure_reason IS NULL) + OR + (status IN ('completed','cancelled') AND started_at IS NOT NULL AND terminal_at IS NOT NULL) + OR + (status IN ('failed','abandoned','unknown') AND terminal_at IS NOT NULL) + ) + ); + +CREATE TABLE agent_org_runtime_user_directed_roots ( + org_run_id TEXT NOT NULL, + root_authority_turn_id TEXT NOT NULL CHECK(length(trim(root_authority_turn_id)) > 0), + policy_version INTEGER NOT NULL CHECK(policy_version >= 1), + max_deliveries INTEGER NOT NULL CHECK(max_deliveries >= 1), + max_cascade_depth INTEGER NOT NULL CHECK(max_cascade_depth >= 0), + next_delivery_ordinal INTEGER NOT NULL CHECK(next_delivery_ordinal >= 2), + created_at TEXT NOT NULL, + PRIMARY KEY(org_run_id, root_authority_turn_id), + FOREIGN KEY(org_run_id) REFERENCES agent_org_runtime_runs(id) ON DELETE CASCADE + ); + +CREATE TABLE agent_org_runtime_work_episode_tasks ( + org_run_id TEXT NOT NULL, + work_episode_id TEXT NOT NULL, + task_id TEXT NOT NULL, + associated_at TEXT NOT NULL, + PRIMARY KEY (org_run_id, task_id), + FOREIGN KEY (work_episode_id) + REFERENCES agent_org_runtime_work_episodes(id) ON DELETE CASCADE, + FOREIGN KEY (org_run_id) REFERENCES agent_org_runtime_runs(id) ON DELETE CASCADE, + FOREIGN KEY (org_run_id, task_id) + REFERENCES agent_org_runtime_tasks(org_run_id, id) ON DELETE CASCADE + ); + +CREATE TABLE agent_org_runtime_work_episodes ( + id TEXT PRIMARY KEY, + org_run_id TEXT NOT NULL, + episode_sequence INTEGER NOT NULL CHECK(episode_sequence >= 1), + status TEXT NOT NULL CHECK(status IN ('active','certified')), + opening_activation_generation INTEGER NOT NULL + CHECK(opening_activation_generation >= 1), + closing_activation_generation INTEGER + CHECK(closing_activation_generation IS NULL OR closing_activation_generation >= 1), + opening_work_revision INTEGER NOT NULL CHECK(opening_work_revision >= 0), + closing_work_revision INTEGER CHECK(closing_work_revision IS NULL OR closing_work_revision >= 0), + outcome TEXT CHECK(outcome IN ('delivered','cancelled','failed')), + certificate_id TEXT UNIQUE, + opened_by_turn_intent_id TEXT NOT NULL CHECK(trim(opened_by_turn_intent_id) <> ''), + created_at TEXT NOT NULL, + closed_at TEXT, + UNIQUE(org_run_id, episode_sequence), + FOREIGN KEY (org_run_id) REFERENCES agent_org_runtime_runs(id) ON DELETE CASCADE, + CHECK( + (status='active' AND closing_activation_generation IS NULL + AND closing_work_revision IS NULL AND outcome IS NULL + AND certificate_id IS NULL AND closed_at IS NULL) + OR + (status='certified' AND closing_activation_generation IS NOT NULL + AND closing_work_revision IS NOT NULL AND outcome IS NOT NULL + AND certificate_id IS NOT NULL AND closed_at IS NOT NULL) + ) + ); + +CREATE TABLE agent_org_scope_removal_receipts ( + receipt_id TEXT PRIMARY KEY, + org_run_id TEXT NOT NULL, + work_episode_id TEXT NOT NULL, + target_task_id TEXT NOT NULL, + root_user_event_id TEXT NOT NULL, + request_id TEXT NOT NULL, + request_digest TEXT NOT NULL, + actor_session_id TEXT NOT NULL, + actor_kind TEXT NOT NULL CHECK(actor_kind='run_view_user'), + status TEXT NOT NULL CHECK(status IN ('recorded','revoked')), + created_at TEXT NOT NULL, + revoked_at TEXT, + UNIQUE(org_run_id, request_id), + UNIQUE(root_user_event_id), + FOREIGN KEY(org_run_id, target_task_id) + REFERENCES agent_org_runtime_tasks(org_run_id, id) ON DELETE CASCADE, + FOREIGN KEY(work_episode_id) + REFERENCES agent_org_runtime_work_episodes(id) ON DELETE CASCADE + ); + +CREATE TABLE agent_org_scope_resolution_receipts ( + resolution_id TEXT PRIMARY KEY, + root_receipt_id TEXT NOT NULL, + org_run_id TEXT NOT NULL, + work_episode_id TEXT NOT NULL, + task_id TEXT NOT NULL, + resolution_kind TEXT NOT NULL CHECK(resolution_kind IN ( + 'dependency_cancelled','dependency_replaced','dependency_detached' + )), + replacement_task_id TEXT, + source_turn_intent_id TEXT, + created_at TEXT NOT NULL, + UNIQUE(root_receipt_id,task_id,resolution_kind), + FOREIGN KEY(root_receipt_id) + REFERENCES agent_org_scope_removal_receipts(receipt_id) ON DELETE CASCADE, + FOREIGN KEY(org_run_id,task_id) + REFERENCES agent_org_runtime_tasks(org_run_id,id) ON DELETE CASCADE, + FOREIGN KEY(work_episode_id) + REFERENCES agent_org_runtime_work_episodes(id) ON DELETE CASCADE, + CHECK( + (resolution_kind='dependency_replaced' AND replacement_task_id IS NOT NULL) + OR (resolution_kind<>'dependency_replaced' AND replacement_task_id IS NULL) + ) + ); + +CREATE TABLE agent_org_task_execution_leases ( + lease_id TEXT PRIMARY KEY, + org_run_id TEXT NOT NULL, + work_episode_id TEXT NOT NULL, + task_id TEXT NOT NULL, + activation_generation INTEGER NOT NULL CHECK(activation_generation >= 1), + execution_epoch INTEGER NOT NULL CHECK(execution_epoch >= 1), + owner_member_id TEXT NOT NULL, + session_id TEXT NOT NULL, + turn_intent_id TEXT NOT NULL, + source_kind TEXT NOT NULL CHECK(source_kind IN ( + 'assignment','plan_revision','coordinator_message', + 'pause_resume','intervention_return','legacy_repair' + )), + continuation_receipt_id TEXT NOT NULL, + source_inbox_id INTEGER, + prior_lease_id TEXT, + state TEXT NOT NULL CHECK(state IN ('active','released','frozen','conflict')), + terminal_reason_code TEXT, + created_at TEXT NOT NULL, + terminal_at TEXT, + UNIQUE(session_id, turn_intent_id), + UNIQUE(org_run_id, work_episode_id, task_id, activation_generation, execution_epoch), + UNIQUE(continuation_receipt_id), + FOREIGN KEY(org_run_id, task_id) + REFERENCES agent_org_runtime_tasks(org_run_id, id) ON DELETE CASCADE, + FOREIGN KEY(work_episode_id) + REFERENCES agent_org_runtime_work_episodes(id) ON DELETE CASCADE, + FOREIGN KEY(source_inbox_id) + REFERENCES agent_org_runtime_inbox(id) ON DELETE SET NULL, + FOREIGN KEY(prior_lease_id) + REFERENCES agent_org_task_execution_leases(lease_id) + ); + +CREATE TABLE agent_org_task_execution_reconciliations ( + context_id INTEGER PRIMARY KEY, + org_run_id TEXT NOT NULL, + task_id TEXT NOT NULL, + activation_generation INTEGER NOT NULL, + session_id TEXT NOT NULL, + turn_intent_id TEXT NOT NULL, + disposition TEXT NOT NULL CHECK(disposition='conflict_rejected'), + reason_code TEXT NOT NULL CHECK(reason_code='duplicate_execution_rejected'), + reconciled_at TEXT NOT NULL, + UNIQUE(session_id,turn_intent_id), + FOREIGN KEY(context_id) + REFERENCES agent_org_runtime_turn_contexts(context_id) ON DELETE CASCADE + ); + +CREATE UNIQUE INDEX idx_agent_org_completion_recheck_inbox + ON agent_org_coordinator_completion_rechecks(inbox_id) + WHERE inbox_id IS NOT NULL; + +CREATE INDEX idx_agent_org_completion_recheck_pending + ON agent_org_coordinator_completion_rechecks(org_run_id,status,work_revision); + +CREATE UNIQUE INDEX idx_agent_org_final_summary_one_active + ON agent_org_runtime_final_summary_receipts(certificate_id) + WHERE status IN ('pending','running','persisting'); + +CREATE INDEX idx_agent_org_final_summary_public_timeline + ON agent_org_runtime_final_summary_receipts(org_run_id,terminal_at,receipt_id) + WHERE status IN ('persisted','failed'); + +CREATE INDEX idx_agent_org_final_summary_run_current + ON agent_org_runtime_final_summary_receipts( + org_run_id,activation_generation,attempt DESC + ); + +CREATE UNIQUE INDEX idx_agent_org_final_summary_turn + ON agent_org_runtime_final_summary_receipts( + coordinator_session_id,turn_intent_id + ) WHERE turn_intent_id IS NOT NULL; + +CREATE INDEX idx_agent_org_formal_trigger_attempt_turn + ON agent_org_runtime_formal_trigger_attempts( + session_id,turn_intent_id,status,receipt_id + ); + +CREATE INDEX idx_agent_org_formal_trigger_missing_doorbell + ON agent_org_runtime_formal_trigger_receipts( + doorbell_status,status,org_run_id,created_at + ) WHERE status='pending' AND doorbell_status='missing'; + +CREATE UNIQUE INDEX idx_agent_org_formal_trigger_one_active_attempt + ON agent_org_runtime_formal_trigger_attempts(receipt_id) + WHERE status IN ('queued','running'); + +CREATE INDEX idx_agent_org_formal_trigger_pending + ON agent_org_runtime_formal_trigger_receipts( + org_run_id,status,doorbell_status,created_at,receipt_id + ); + +CREATE INDEX idx_agent_org_formal_trigger_task + ON agent_org_runtime_formal_trigger_receipts(org_run_id,task_id,created_at) + WHERE task_id IS NOT NULL; + +CREATE UNIQUE INDEX idx_agent_org_member_intervention_active + ON agent_org_runtime_member_interventions(org_run_id, member_id) + WHERE status IN ('yield_requested','active','return_requested'); + +CREATE UNIQUE INDEX idx_agent_org_member_intervention_continuation + ON agent_org_runtime_member_interventions(session_id, continuation_turn_intent_id) + WHERE continuation_turn_intent_id IS NOT NULL; + +CREATE INDEX idx_agent_org_member_intervention_public_timeline + ON agent_org_runtime_member_interventions( + org_run_id,cleared_at,intervention_receipt_id + ) WHERE status='cleared'; + +CREATE UNIQUE INDEX idx_agent_org_member_intervention_return_request + ON agent_org_runtime_member_interventions(org_run_id, return_request_id) + WHERE return_request_id IS NOT NULL; + +CREATE INDEX idx_agent_org_member_intervention_session + ON agent_org_runtime_member_interventions(session_id, status, updated_at); + +CREATE INDEX idx_agent_org_member_intervention_turn_queue + ON agent_org_runtime_member_intervention_turns( + intervention_receipt_id, status, member_dispatch_sequence + ); + +CREATE INDEX idx_agent_org_member_turn_admission_recovery + ON agent_org_member_turn_admissions(status, updated_at); + +CREATE INDEX idx_agent_org_runtime_archive_pending + ON agent_org_runtime_archive_episodes(teardown_status, deadline_at); + +CREATE INDEX idx_agent_org_runtime_archive_teardown_pending + ON agent_org_runtime_archive_teardowns( + archive_receipt_id, teardown_status, session_id + ); + +CREATE UNIQUE INDEX idx_agent_org_runtime_inbox_causation_recipient_once + ON agent_org_runtime_inbox( + causation_inbox_id, + payload_kind, + recipient_agent_id, + COALESCE(recipient_member_id, '') + ) + WHERE causation_inbox_id IS NOT NULL; + +CREATE INDEX idx_agent_org_runtime_inbox_delivery_resolutions_run + ON agent_org_runtime_inbox_delivery_resolutions(org_run_id, inbox_id); + +CREATE INDEX idx_agent_org_runtime_inbox_materializations_session + ON agent_org_runtime_inbox_materializations(session_id, inbox_id); + +CREATE INDEX idx_agent_org_runtime_inbox_org_run + ON agent_org_runtime_inbox(org_run_id, created_at); + +CREATE INDEX idx_agent_org_runtime_inbox_org_run_id + ON agent_org_runtime_inbox(org_run_id, id); + +CREATE INDEX idx_agent_org_runtime_inbox_recipient_member_unread + ON agent_org_runtime_inbox(recipient_member_id, read_at, created_at); + +CREATE INDEX idx_agent_org_runtime_inbox_recipient_unread + ON agent_org_runtime_inbox(recipient_agent_id, read_at, created_at); + +CREATE INDEX idx_agent_org_runtime_inbox_request_id + ON agent_org_runtime_inbox(request_id); + +CREATE INDEX idx_agent_org_runtime_inbox_run_kind_id + ON agent_org_runtime_inbox(org_run_id, payload_kind, id); + +CREATE INDEX idx_agent_org_runtime_inbox_run_task_assignment_v4 + ON agent_org_runtime_inbox( + org_run_id, + recipient_member_id, + json_extract( + CASE WHEN length(CAST(payload_json AS BLOB))<=262144 + AND json_valid(payload_json) + THEN payload_json ELSE '{}' END, + '$.task_id' + ) + ) + WHERE payload_kind='task_assigned' + AND CASE WHEN length(CAST(payload_json AS BLOB))<=262144 + THEN json_valid(payload_json) ELSE 0 END + AND json_type( + CASE WHEN length(CAST(payload_json AS BLOB))<=262144 + AND json_valid(payload_json) + THEN payload_json ELSE '{}' END, + '$.task_id' + )='text'; + +CREATE INDEX idx_agent_org_runtime_inbox_run_unread_recipient + ON agent_org_runtime_inbox(org_run_id, recipient_member_id, recipient_agent_id, id) + WHERE read_at IS NULL; + +CREATE INDEX idx_agent_org_runtime_inbox_task_bindings_wake + ON agent_org_runtime_inbox_task_bindings( + org_run_id,recipient_member_id,task_id,inbox_id + ); + +CREATE UNIQUE INDEX idx_agent_org_runtime_inbox_user_message_once + ON agent_org_runtime_inbox(org_run_id, sender_agent_id, client_message_id) + WHERE client_message_id IS NOT NULL; + +CREATE INDEX idx_agent_org_runtime_initial_inputs_dispatch + ON agent_org_runtime_initial_inputs(status, org_run_id); + +CREATE INDEX idx_agent_org_runtime_member_materializations_pending + ON agent_org_runtime_member_materializations(status, org_run_id, generation); + +CREATE INDEX idx_agent_org_runtime_pause_capture + ON agent_org_runtime_turn_contexts( + org_run_id, activation_generation, turn_kind, session_id, turn_intent_id + ) + WHERE turn_kind IN ('coordinator','task_execution'); + +CREATE INDEX idx_agent_org_runtime_pause_dispatch + ON agent_org_runtime_pause_handoffs(continuation_status, org_run_id, session_id); + +CREATE INDEX idx_agent_org_runtime_pause_drain + ON agent_org_runtime_pause_handoffs(episode_id, drain_status, session_id); + +CREATE UNIQUE INDEX idx_agent_org_runtime_pause_one_active + ON agent_org_runtime_pause_episodes(org_run_id) + WHERE status='active'; + +CREATE INDEX idx_agent_org_runtime_pause_public_timeline + ON agent_org_runtime_pause_episodes(org_run_id, created_at, episode_id); + +CREATE INDEX idx_agent_org_runtime_pause_request + ON agent_org_runtime_pause_episodes(org_run_id, pause_request_id); + +CREATE INDEX idx_agent_org_runtime_plan_decisions_status + ON agent_org_runtime_plan_decisions(status, created_at, approval_id); + +CREATE INDEX idx_agent_org_runtime_plan_revisions_path + ON agent_org_runtime_plan_revisions(plan_path, created_at DESC); + +CREATE INDEX idx_agent_org_runtime_plan_revisions_run_task + ON agent_org_runtime_plan_revisions( + org_run_id, source_task_id, revision_number DESC + ); + +CREATE INDEX idx_agent_org_runtime_plan_revisions_source_session_turn + ON agent_org_runtime_plan_revisions( + source_session_id, source_turn_intent_id, created_at + ); + +CREATE INDEX idx_agent_org_runtime_recovery_attempts_run + ON agent_org_runtime_recovery_attempts(org_run_id); + +CREATE INDEX idx_agent_org_runtime_resume_public_timeline + ON agent_org_runtime_pause_episodes(org_run_id, resumed_at, episode_id) + WHERE resumed_at IS NOT NULL; + +CREATE INDEX idx_agent_org_runtime_run_completion_certificates_turn + ON agent_org_runtime_run_completion_certificates( + coordinator_session_id,coordinator_turn_intent_id + ); + +CREATE INDEX idx_agent_org_runtime_run_completion_public_timeline + ON agent_org_runtime_run_completion_certificates(org_run_id,created_at,id); + +CREATE INDEX idx_agent_org_runtime_runs_org_updated + ON agent_org_runtime_runs(org_id, updated_at); + +CREATE INDEX idx_agent_org_runtime_runs_root_session + ON agent_org_runtime_runs(root_session_id); + +CREATE INDEX idx_agent_org_runtime_runs_status + ON agent_org_runtime_runs(status); + +CREATE INDEX idx_agent_org_runtime_runs_work_item + ON agent_org_runtime_runs(work_item_id); + +CREATE INDEX idx_agent_org_runtime_task_annotations_page + ON agent_org_runtime_task_annotations(org_run_id, task_id, created_at, id); + +CREATE INDEX idx_agent_org_runtime_task_events_run + ON agent_org_runtime_task_events(org_run_id, created_at, id); + +CREATE INDEX idx_agent_org_runtime_task_events_task + ON agent_org_runtime_task_events(org_run_id, task_id, created_at, id); + +CREATE UNIQUE INDEX idx_agent_org_runtime_task_execution_handoffs_replacement + ON agent_org_runtime_task_execution_handoffs(org_run_id, replacement_task_id) + WHERE replacement_task_id IS NOT NULL; + +CREATE INDEX idx_agent_org_runtime_task_execution_handoffs_run + ON agent_org_runtime_task_execution_handoffs(org_run_id, activation_generation, state, requested_at, id); + +CREATE INDEX idx_agent_org_runtime_tasks_history_page + ON agent_org_runtime_tasks(org_run_id, status, updated_at, id); + +CREATE INDEX idx_agent_org_runtime_tasks_owner + ON agent_org_runtime_tasks(org_run_id, owner, status); + +CREATE INDEX idx_agent_org_runtime_tasks_page + ON agent_org_runtime_tasks(org_run_id, status, created_at, id); + +CREATE INDEX idx_agent_org_runtime_tasks_replacement + ON agent_org_runtime_tasks(org_run_id, replaces_task_id); + +CREATE INDEX idx_agent_org_runtime_turn_contexts_group_root_session + ON agent_org_runtime_turn_contexts(session_id, context_id, source_id) + WHERE source_kind='group_root'; + +CREATE UNIQUE INDEX idx_agent_org_runtime_turn_contexts_member_sequence + ON agent_org_runtime_turn_contexts( + org_run_id, dispatch_member_id, member_dispatch_sequence + ) + WHERE dispatch_member_id IS NOT NULL; + +CREATE INDEX idx_agent_org_runtime_turn_contexts_public_timeline + ON agent_org_runtime_turn_contexts(org_run_id, created_at, context_id) + WHERE source_kind IN ('group_root','group_mention'); + +CREATE INDEX idx_agent_org_runtime_turn_contexts_source + ON agent_org_runtime_turn_contexts( + org_run_id, source_kind, source_id, context_id + ); + +CREATE INDEX idx_agent_org_runtime_udw_coordinator_pending + ON agent_org_runtime_user_directed_coordinator_bindings(binding_id) + WHERE status='pending'; + +CREATE INDEX idx_agent_org_runtime_udw_member_fifo + ON agent_org_runtime_user_directed_deliveries( + org_run_id, dispatch_member_id, member_dispatch_sequence + ) WHERE status IN ('pending','started'); + +CREATE INDEX idx_agent_org_runtime_udw_pending_recovery + ON agent_org_runtime_user_directed_deliveries(delivery_id) + WHERE status='pending'; + +CREATE UNIQUE INDEX idx_agent_org_runtime_udw_source_inbox + ON agent_org_runtime_user_directed_deliveries(source_inbox_id) + WHERE source_inbox_id IS NOT NULL; + +CREATE INDEX idx_agent_org_runtime_work_episode_tasks_episode + ON agent_org_runtime_work_episode_tasks(org_run_id, work_episode_id, task_id); + +CREATE UNIQUE INDEX idx_agent_org_runtime_work_episodes_active + ON agent_org_runtime_work_episodes(org_run_id) WHERE status='active'; + +CREATE INDEX idx_agent_org_runtime_work_episodes_current + ON agent_org_runtime_work_episodes(org_run_id, episode_sequence DESC); + +CREATE INDEX idx_agent_org_scope_removal_episode + ON agent_org_scope_removal_receipts(org_run_id,work_episode_id,target_task_id); + +CREATE INDEX idx_agent_org_scope_resolution_episode + ON agent_org_scope_resolution_receipts(org_run_id,work_episode_id,task_id); + +CREATE UNIQUE INDEX idx_agent_org_task_execution_one_live + ON agent_org_task_execution_leases( + org_run_id,work_episode_id,task_id,activation_generation + ) WHERE state='active'; + +CREATE INDEX idx_agent_org_task_execution_reconciliation_task + ON agent_org_task_execution_reconciliations( + org_run_id,task_id,activation_generation + ); + +CREATE INDEX idx_agent_org_task_execution_task + ON agent_org_task_execution_leases(org_run_id,task_id,execution_epoch DESC); + +CREATE INDEX idx_agent_org_task_execution_turn + ON agent_org_task_execution_leases(session_id,turn_intent_id,state); + +CREATE TRIGGER trg_agent_org_runtime_plan_revisions_immutable + BEFORE UPDATE ON agent_org_runtime_plan_revisions + BEGIN + SELECT RAISE(ABORT, 'agent_org_plan_revision_immutable'); + END; diff --git a/src-tauri/crates/agent-core/src/core/coordination/mod.rs b/src-tauri/crates/agent-core/src/core/coordination/mod.rs index 22cebc2293..89377a0397 100644 --- a/src-tauri/crates/agent-core/src/core/coordination/mod.rs +++ b/src-tauri/crates/agent-core/src/core/coordination/mod.rs @@ -28,6 +28,7 @@ pub mod agent_org_final_summary; pub(crate) mod agent_org_finality; pub mod agent_org_formal_triggers; pub mod agent_org_history; +pub mod agent_org_history_store; pub(crate) mod agent_org_ownership; pub mod agent_org_pause; pub mod agent_org_payload_limits; diff --git a/src-tauri/crates/agent-core/src/core/coordination/schema.rs b/src-tauri/crates/agent-core/src/core/coordination/schema.rs index 5530e97bd4..492f56ae0c 100644 --- a/src-tauri/crates/agent-core/src/core/coordination/schema.rs +++ b/src-tauri/crates/agent-core/src/core/coordination/schema.rs @@ -1,10 +1,4 @@ -//! Atomic ownership of the canonical Agent Org private SQLite namespace. -//! -//! Old releases may recreate the retired names after a downgrade. Every new -//! process therefore retires the exact known legacy set again; there is no -//! one-time marker. Canonical runtime data is treated more conservatively: a -//! partial or structurally unknown runtime namespace fails closed before any -//! legacy object is dropped. +//! Atomic cutover to isolated execution, with a frozen v2.0.8 compatibility area. use std::collections::BTreeMap; @@ -19,207 +13,178 @@ use super::{ agent_org_work_episodes, }; -const RUNTIME_TABLES: [&str; 33] = [ - "agent_org_runtime_runs", - "agent_org_runtime_run_progress", - "agent_org_runtime_work_episodes", - "agent_org_runtime_work_episode_tasks", - "agent_org_runtime_run_completion_certificates", - "agent_org_runtime_final_summary_receipts", - "agent_org_runtime_member_materializations", - "agent_org_runtime_initial_inputs", - "agent_org_runtime_plan_revisions", - "agent_org_runtime_plan_decisions", - "agent_org_runtime_recovery_attempts", - "agent_org_runtime_tasks", - "agent_org_runtime_task_events", - "agent_org_runtime_task_annotations", - "agent_org_runtime_task_execution_handoffs", - "agent_org_runtime_inbox", - "agent_org_runtime_inbox_materializations", - "agent_org_runtime_inbox_delivery_resolutions", - "agent_org_runtime_inbox_task_bindings", - "agent_org_runtime_formal_trigger_receipts", - "agent_org_runtime_formal_trigger_attempts", - "agent_org_runtime_member_interventions", - "agent_org_runtime_member_intervention_turns", - "agent_org_runtime_member_dispatch_allocators", - "agent_org_runtime_turn_contexts", - "agent_org_runtime_user_directed_roots", - "agent_org_runtime_user_directed_deliveries", - "agent_org_runtime_user_directed_coordinator_bindings", - "agent_org_runtime_pause_episodes", - "agent_org_runtime_pause_handoffs", - "agent_org_runtime_archive_episodes", - "agent_org_runtime_archive_teardowns", - "agent_org_runtime_tool_call_receipts", +const RUNTIME_TABLES: [&str; 39] = [ + "agent_org_execution_archive_episodes", + "agent_org_execution_archive_teardowns", + "agent_org_execution_coordinator_completion_rechecks", + "agent_org_execution_final_summary_receipts", + "agent_org_execution_formal_trigger_attempts", + "agent_org_execution_formal_trigger_receipts", + "agent_org_execution_inbox", + "agent_org_execution_inbox_delivery_resolutions", + "agent_org_execution_inbox_materializations", + "agent_org_execution_inbox_task_bindings", + "agent_org_execution_initial_inputs", + "agent_org_execution_member_dispatch_allocators", + "agent_org_execution_member_intervention_turns", + "agent_org_execution_member_interventions", + "agent_org_execution_member_materializations", + "agent_org_execution_member_turn_admissions", + "agent_org_execution_pause_episodes", + "agent_org_execution_pause_handoffs", + "agent_org_execution_plan_decisions", + "agent_org_execution_plan_revisions", + "agent_org_execution_recovery_attempts", + "agent_org_execution_run_completion_certificates", + "agent_org_execution_run_progress", + "agent_org_execution_runs", + "agent_org_execution_scope_removal_receipts", + "agent_org_execution_scope_resolution_receipts", + "agent_org_execution_task_annotations", + "agent_org_execution_task_events", + "agent_org_execution_task_execution_handoffs", + "agent_org_execution_task_execution_leases", + "agent_org_execution_task_execution_reconciliations", + "agent_org_execution_tasks", + "agent_org_execution_tool_call_receipts", + "agent_org_execution_turn_contexts", + "agent_org_execution_user_directed_coordinator_bindings", + "agent_org_execution_user_directed_deliveries", + "agent_org_execution_user_directed_roots", + "agent_org_execution_work_episode_tasks", + "agent_org_execution_work_episodes", ]; -const RUNTIME_INDEXES: [&str; 70] = [ - "idx_agent_org_final_summary_one_active", - "idx_agent_org_final_summary_public_timeline", - "idx_agent_org_final_summary_run_current", - "idx_agent_org_final_summary_turn", - "idx_agent_org_formal_trigger_attempt_turn", - "idx_agent_org_formal_trigger_missing_doorbell", - "idx_agent_org_formal_trigger_one_active_attempt", - "idx_agent_org_formal_trigger_pending", - "idx_agent_org_formal_trigger_task", - "idx_agent_org_member_intervention_active", - "idx_agent_org_member_intervention_continuation", - "idx_agent_org_member_intervention_public_timeline", - "idx_agent_org_member_intervention_return_request", - "idx_agent_org_member_intervention_session", - "idx_agent_org_member_intervention_turn_queue", - "idx_agent_org_runtime_archive_pending", - "idx_agent_org_runtime_archive_teardown_pending", - "idx_agent_org_runtime_inbox_causation_recipient_once", - "idx_agent_org_runtime_inbox_delivery_resolutions_run", - "idx_agent_org_runtime_inbox_materializations_session", - "idx_agent_org_runtime_inbox_org_run", - "idx_agent_org_runtime_inbox_org_run_id", - "idx_agent_org_runtime_inbox_recipient_member_unread", - "idx_agent_org_runtime_inbox_recipient_unread", - "idx_agent_org_runtime_inbox_request_id", - "idx_agent_org_runtime_inbox_run_kind_id", - "idx_agent_org_runtime_inbox_run_task_assignment_v4", - "idx_agent_org_runtime_inbox_run_unread_recipient", - "idx_agent_org_runtime_inbox_task_bindings_wake", - "idx_agent_org_runtime_inbox_user_message_once", - "idx_agent_org_runtime_initial_inputs_dispatch", - "idx_agent_org_runtime_member_materializations_pending", - "idx_agent_org_runtime_pause_capture", - "idx_agent_org_runtime_pause_dispatch", - "idx_agent_org_runtime_pause_drain", - "idx_agent_org_runtime_pause_one_active", - "idx_agent_org_runtime_pause_public_timeline", - "idx_agent_org_runtime_pause_request", - "idx_agent_org_runtime_plan_decisions_status", - "idx_agent_org_runtime_plan_revisions_path", - "idx_agent_org_runtime_plan_revisions_run_task", - "idx_agent_org_runtime_plan_revisions_source_session_turn", - "idx_agent_org_runtime_recovery_attempts_run", - "idx_agent_org_runtime_resume_public_timeline", - "idx_agent_org_runtime_run_completion_certificates_turn", - "idx_agent_org_runtime_run_completion_public_timeline", - "idx_agent_org_runtime_runs_org_updated", - "idx_agent_org_runtime_runs_root_session", - "idx_agent_org_runtime_runs_status", - "idx_agent_org_runtime_runs_work_item", - "idx_agent_org_runtime_task_annotations_page", - "idx_agent_org_runtime_task_events_run", - "idx_agent_org_runtime_task_events_task", - "idx_agent_org_runtime_task_execution_handoffs_replacement", - "idx_agent_org_runtime_task_execution_handoffs_run", - "idx_agent_org_runtime_tasks_history_page", - "idx_agent_org_runtime_tasks_owner", - "idx_agent_org_runtime_tasks_page", - "idx_agent_org_runtime_tasks_replacement", - "idx_agent_org_runtime_turn_contexts_group_root_session", - "idx_agent_org_runtime_turn_contexts_member_sequence", - "idx_agent_org_runtime_turn_contexts_public_timeline", - "idx_agent_org_runtime_turn_contexts_source", - "idx_agent_org_runtime_udw_coordinator_pending", - "idx_agent_org_runtime_udw_member_fifo", - "idx_agent_org_runtime_udw_pending_recovery", - "idx_agent_org_runtime_udw_source_inbox", - "idx_agent_org_runtime_work_episode_tasks_episode", - "idx_agent_org_runtime_work_episodes_active", - "idx_agent_org_runtime_work_episodes_current", +const RUNTIME_INDEXES: [&str; 79] = [ + "idx_agent_org_execution_archive_pending", + "idx_agent_org_execution_archive_teardown_pending", + "idx_agent_org_execution_completion_recheck_inbox", + "idx_agent_org_execution_completion_recheck_pending", + "idx_agent_org_execution_final_summary_one_active", + "idx_agent_org_execution_final_summary_public_timeline", + "idx_agent_org_execution_final_summary_run_current", + "idx_agent_org_execution_final_summary_turn", + "idx_agent_org_execution_formal_trigger_attempt_turn", + "idx_agent_org_execution_formal_trigger_missing_doorbell", + "idx_agent_org_execution_formal_trigger_one_active_attempt", + "idx_agent_org_execution_formal_trigger_pending", + "idx_agent_org_execution_formal_trigger_task", + "idx_agent_org_execution_inbox_causation_recipient_once", + "idx_agent_org_execution_inbox_delivery_resolutions_run", + "idx_agent_org_execution_inbox_materializations_session", + "idx_agent_org_execution_inbox_org_run", + "idx_agent_org_execution_inbox_org_run_id", + "idx_agent_org_execution_inbox_recipient_member_unread", + "idx_agent_org_execution_inbox_recipient_unread", + "idx_agent_org_execution_inbox_request_id", + "idx_agent_org_execution_inbox_run_kind_id", + "idx_agent_org_execution_inbox_run_task_assignment_v4", + "idx_agent_org_execution_inbox_run_unread_recipient", + "idx_agent_org_execution_inbox_task_bindings_wake", + "idx_agent_org_execution_inbox_user_message_once", + "idx_agent_org_execution_initial_inputs_dispatch", + "idx_agent_org_execution_member_intervention_active", + "idx_agent_org_execution_member_intervention_continuation", + "idx_agent_org_execution_member_intervention_public_timeline", + "idx_agent_org_execution_member_intervention_return_request", + "idx_agent_org_execution_member_intervention_session", + "idx_agent_org_execution_member_intervention_turn_queue", + "idx_agent_org_execution_member_materializations_pending", + "idx_agent_org_execution_member_turn_admission_recovery", + "idx_agent_org_execution_pause_capture", + "idx_agent_org_execution_pause_dispatch", + "idx_agent_org_execution_pause_drain", + "idx_agent_org_execution_pause_one_active", + "idx_agent_org_execution_pause_public_timeline", + "idx_agent_org_execution_pause_request", + "idx_agent_org_execution_plan_decisions_status", + "idx_agent_org_execution_plan_revisions_path", + "idx_agent_org_execution_plan_revisions_run_task", + "idx_agent_org_execution_plan_revisions_source_session_turn", + "idx_agent_org_execution_recovery_attempts_run", + "idx_agent_org_execution_resume_public_timeline", + "idx_agent_org_execution_run_completion_certificates_turn", + "idx_agent_org_execution_run_completion_public_timeline", + "idx_agent_org_execution_runs_org_updated", + "idx_agent_org_execution_runs_root_session", + "idx_agent_org_execution_runs_status", + "idx_agent_org_execution_runs_work_item", + "idx_agent_org_execution_scope_removal_episode", + "idx_agent_org_execution_scope_resolution_episode", + "idx_agent_org_execution_task_annotations_page", + "idx_agent_org_execution_task_events_run", + "idx_agent_org_execution_task_events_task", + "idx_agent_org_execution_task_execution_handoffs_replacement", + "idx_agent_org_execution_task_execution_handoffs_run", + "idx_agent_org_execution_task_execution_one_live", + "idx_agent_org_execution_task_execution_reconciliation_task", + "idx_agent_org_execution_task_execution_task", + "idx_agent_org_execution_task_execution_turn", + "idx_agent_org_execution_tasks_history_page", + "idx_agent_org_execution_tasks_owner", + "idx_agent_org_execution_tasks_page", + "idx_agent_org_execution_tasks_replacement", + "idx_agent_org_execution_turn_contexts_group_root_session", + "idx_agent_org_execution_turn_contexts_member_sequence", + "idx_agent_org_execution_turn_contexts_public_timeline", + "idx_agent_org_execution_turn_contexts_source", + "idx_agent_org_execution_udw_coordinator_pending", + "idx_agent_org_execution_udw_member_fifo", + "idx_agent_org_execution_udw_pending_recovery", + "idx_agent_org_execution_udw_source_inbox", + "idx_agent_org_execution_work_episode_tasks_episode", + "idx_agent_org_execution_work_episodes_active", + "idx_agent_org_execution_work_episodes_current", ]; -const RUNTIME_TRIGGERS: [&str; 1] = ["trg_agent_org_runtime_plan_revisions_immutable"]; +const RUNTIME_TRIGGERS: [&str; 1] = ["trg_agent_org_execution_plan_revisions_immutable"]; const RUNTIME_MANIFEST_SHA256: &str = - "d96f244c1ddb4293c82109cf8dc4ca0a41179f4aa464a22b81c69ffe65f9313c"; - -/// Exact private Agent Org tables created by official v1.3.0 and v1.2.6. -const LEGACY_TABLES: [&str; 11] = [ - "agent_org_runs", - "agent_org_run_progress", - "agent_org_plan_approvals", - "agent_org_recovery_attempts", - "agent_org_tasks", - "agent_org_task_events", - "agent_org_task_run_schema_migrations", - "agent_inbox", - "agent_inbox_materializations", - "agent_inbox_delivery_resolutions", - "agent_member_interventions", -]; + "547907b63c1a2c3a7d27a57fbe3642efb4349acc4090581910b0ee915e58c5eb"; const RUNTIME_OBJECTS_QUERY: &str = "SELECT type, name, tbl_name, sql FROM sqlite_master WHERE sql IS NOT NULL AND type IN ('table', 'index', 'trigger') - AND (name LIKE 'agent_org_runtime_%' OR tbl_name LIKE 'agent_org_runtime_%') + AND (name LIKE 'agent_org_execution_%' OR tbl_name LIKE 'agent_org_execution_%') ORDER BY type, name"; -const DROP_LEGACY_SCHEMA: &str = "DROP TABLE IF EXISTS agent_inbox_materializations; - DROP TABLE IF EXISTS agent_inbox_delivery_resolutions; - DROP TABLE IF EXISTS agent_inbox; - DROP TABLE IF EXISTS agent_org_task_events; - DROP TABLE IF EXISTS agent_org_task_run_schema_migrations; - DROP TABLE IF EXISTS agent_org_tasks; - DROP TABLE IF EXISTS agent_org_plan_approvals; - DROP TABLE IF EXISTS agent_org_recovery_attempts; - DROP TABLE IF EXISTS agent_member_interventions; - DROP TABLE IF EXISTS agent_org_run_progress; - DROP TABLE IF EXISTS agent_org_runs;"; - type SchemaManifest = BTreeMap<(String, String), (String, String)>; pub(super) fn initialize(conn: &Connection) -> SqliteResult<()> { + // Private tables contain cycles. Disable FK actions on this connection only + // while atomically copying and retiring them; otherwise DROP could cascade + // into data before its raw archive is written. Always restore caller policy. + if !conn.is_autocommit() { + return Err(schema_error( + "Agent Org initialization requires its own transaction".into(), + )); + } + let foreign_keys: bool = conn.pragma_query_value(None, "foreign_keys", |row| row.get(0))?; + conn.pragma_update(None, "foreign_keys", false)?; + let result = initialize_transaction(conn); + let restore = conn.pragma_update(None, "foreign_keys", foreign_keys); + result.and(restore) +} + +fn initialize_transaction(conn: &Connection) -> SqliteResult<()> { let expected = expected_manifest()?; let tx = database::db::begin_immediate(conn)?; - let runtime_table_count = count_known_tables(&tx, &RUNTIME_TABLES)?; - - let fresh = match runtime_table_count { - 0 => true, - count if count == RUNTIME_TABLES.len() => { - verify_manifest(&tx, &expected)?; - false - } - count => { - return Err(schema_error(format!( - "partial Agent Org runtime schema: found {count} of {} canonical tables; only an empty namespace or the complete current manifest is accepted", - RUNTIME_TABLES.len(), - ))) - } - }; - - let legacy_table_count = count_known_tables(&tx, &LEGACY_TABLES)?; - let legacy_object_count = count_legacy_objects(&tx)?; - tx.execute_batch(DROP_LEGACY_SCHEMA)?; - + let actual = read_manifest(&tx)?; + let ready = super::agent_org_history_store::cutover_complete(&tx)?; + let fresh = actual.is_empty() && !ready; + if !fresh { + // A completion marker with missing tables is corruption, including a + // completely missing execution area. Never silently reset live teams. + verify_manifest(&tx, &expected)?; + } + super::agent_org_history_store::prepare_cutover(&tx, fresh)?; if fresh { create_runtime_schema(&tx)?; } verify_manifest(&tx, &expected)?; - // The manifest includes completion candidates, presentation evidence and - // system dispositions. Only fresh/current databases are supported; an - // earlier manifest is rejected above, never migrated or rewritten here. - // Existing finality companions retain their separate additive owner. - super::agent_org_finality::create_schema(&tx)?; - agent_member_interventions::create_runtime_admission_schema(&tx)?; agent_inbox::repair_dangling_materializations(&tx)?; - let unknown_objects = unknown_agent_org_objects(&tx)?; + super::agent_org_history_store::finish_cutover(&tx)?; tx.commit()?; - - if !unknown_objects.is_empty() { - tracing::warn!( - event = "agent_org_unknown_schema_objects_preserved", - objects = ?unknown_objects, - "preserved schema objects outside the exact legacy retirement registry" - ); - } - tracing::info!( - event = "agent_org_runtime_namespace_initialized", - legacy_table_count, - legacy_object_count, - fresh, - idempotent = !fresh, - "initialized isolated Agent Org runtime schema" - ); Ok(()) } @@ -239,7 +204,9 @@ fn create_runtime_schema(conn: &Connection) -> SqliteResult<()> { agent_org_user_directed_work::create_schema(conn)?; agent_org_pause::create_schema(conn)?; agent_org_archive::create_schema(conn)?; - agent_org_tool_receipts::create_schema(conn) + agent_org_tool_receipts::create_schema(conn)?; + super::agent_org_finality::create_schema(conn)?; + agent_member_interventions::create_runtime_admission_schema(conn) } fn expected_manifest() -> SqliteResult { @@ -344,663 +311,10 @@ fn read_manifest(conn: &Connection) -> SqliteResult { rows.collect() } -fn count_known_tables(conn: &Connection, names: &[&str]) -> SqliteResult { - let mut statement = conn.prepare("SELECT name FROM sqlite_master WHERE type='table'")?; - let rows = statement.query_map([], |row| row.get::<_, String>(0))?; - let mut count = 0; - for row in rows { - if names.contains(&row?.as_str()) { - count += 1; - } - } - Ok(count) -} - -fn count_legacy_objects(conn: &Connection) -> SqliteResult { - let mut statement = conn.prepare( - "SELECT name, tbl_name FROM sqlite_master - WHERE type IN ('table', 'index', 'trigger')", - )?; - let rows = statement.query_map([], |row| { - Ok((row.get::<_, String>(0)?, row.get::<_, String>(1)?)) - })?; - let mut count = 0; - for row in rows { - let (name, table_name) = row?; - if LEGACY_TABLES.contains(&name.as_str()) || LEGACY_TABLES.contains(&table_name.as_str()) { - count += 1; - } - } - Ok(count) -} - -fn unknown_agent_org_objects(conn: &Connection) -> SqliteResult> { - let mut statement = conn.prepare( - "SELECT name FROM sqlite_master - WHERE type IN ('table', 'index', 'trigger') - AND (name LIKE 'agent_org_%' OR name LIKE 'agent_inbox%' OR name LIKE 'agent_member_%') - ORDER BY name", - )?; - let rows = statement.query_map([], |row| row.get::<_, String>(0))?; - let mut unknown = Vec::new(); - for row in rows { - let name = row?; - let known_runtime = name.starts_with("sqlite_autoindex_agent_org_runtime_") - || read_known_runtime_object(conn, &name)?; - if !known_runtime && !LEGACY_TABLES.contains(&name.as_str()) { - unknown.push(name); - } - } - Ok(unknown) -} - -fn read_known_runtime_object(conn: &Connection, name: &str) -> SqliteResult { - conn.query_row( - "SELECT EXISTS( - SELECT 1 FROM sqlite_master - WHERE name=?1 - AND (name LIKE 'agent_org_runtime_%' OR tbl_name LIKE 'agent_org_runtime_%') - )", - [name], - |row| row.get(0), - ) -} - fn schema_error(message: String) -> SqliteError { SqliteError::SqliteFailure(ffi::Error::new(ffi::SQLITE_SCHEMA), Some(message)) } #[cfg(test)] -mod tests { - use std::sync::{Arc, Barrier}; - use std::time::{Duration, Instant}; - - use super::*; - - fn connection() -> Connection { - let conn = Connection::open_in_memory().expect("in-memory SQLite"); - conn.execute_batch("PRAGMA foreign_keys=ON;") - .expect("enable foreign keys"); - conn - } - - fn object_exists(conn: &Connection, object_type: &str, name: &str) -> bool { - conn.query_row( - "SELECT EXISTS( - SELECT 1 FROM sqlite_master WHERE type=?1 AND name=?2 - )", - rusqlite::params![object_type, name], - |row| row.get(0), - ) - .expect("inspect schema object") - } - - fn row_count(conn: &Connection, table: &str) -> i64 { - conn.query_row(&format!("SELECT COUNT(*) FROM {table}"), [], |row| { - row.get(0) - }) - .unwrap_or_else(|error| panic!("count {table}: {error}")) - } - - fn create_official_v1_3_0_fixture(conn: &Connection) { - conn.execute_batch(include_str!("fixtures/official_v1_3_0_agent_org.sql")) - .expect("create exact official v1.3.0 Agent Org fixture"); - } - - fn seed_shared_sentinels(conn: &Connection) { - crate::persistence::session_snapshots::ensure_tables_with(conn) - .expect("create production Session/message schema"); - conn.execute_batch( - "CREATE TABLE code_sessions ( - id TEXT PRIMARY KEY, session_id TEXT UNIQUE, payload BLOB, org_member_id TEXT - ); - CREATE TABLE session_turn_intents (id TEXT PRIMARY KEY, payload BLOB, org_run_id TEXT); - CREATE TABLE projects (id TEXT PRIMARY KEY, payload BLOB); - CREATE TABLE work_items (id TEXT PRIMARY KEY, payload BLOB); - CREATE TABLE routines (id TEXT PRIMARY KEY, payload BLOB); - CREATE TABLE usage_events (id TEXT PRIMARY KEY, payload BLOB); - INSERT INTO agent_sessions ( - session_id,name,status,user_input,created_at,updated_at - ) VALUES ( - 'ordinary-session','Ordinary SDE','idle','ordinary sentinel', - '2026-08-01T00:00:00Z','2026-08-01T00:00:00Z' - ); - INSERT INTO agent_messages ( - id,session_id,role,content,sequence,created_at - ) VALUES ( - 'ordinary-message','ordinary-session','assistant', - 'ordinary message sentinel',1,'2026-08-01T00:00:00Z' - ); - INSERT INTO code_sessions VALUES ('cli', 'cli-session', x'060708', 'member-b'); - INSERT INTO session_turn_intents VALUES ('intent', x'090A0B', 'run-a'); - INSERT INTO projects VALUES ('project', x'0C0D0E'); - INSERT INTO work_items VALUES ('work-item', x'0F1011'); - INSERT INTO routines VALUES ('routine', x'121314'); - INSERT INTO usage_events VALUES ('usage', x'151617');", - ) - .expect("shared sentinels"); - } - - fn shared_sentinel_fingerprint(conn: &Connection) -> Vec<(String, String)> { - [ - ( - "agent_sessions", - "SELECT session_id || '|' || name || '|' || status || '|' || user_input - FROM agent_sessions WHERE session_id='ordinary-session'", - ), - ( - "agent_messages", - "SELECT id || '|' || session_id || '|' || role || '|' || content || '|' || sequence - FROM agent_messages WHERE id='ordinary-message'", - ), - ("code_sessions", "SELECT hex(payload) FROM code_sessions"), - ( - "session_turn_intents", - "SELECT hex(payload) FROM session_turn_intents", - ), - ("projects", "SELECT hex(payload) FROM projects"), - ("work_items", "SELECT hex(payload) FROM work_items"), - ("routines", "SELECT hex(payload) FROM routines"), - ("usage_events", "SELECT hex(payload) FROM usage_events"), - ] - .into_iter() - .map(|(table, query)| { - let fingerprint = conn - .query_row(query, [], |row| row.get::<_, String>(0)) - .unwrap_or_else(|error| panic!("fingerprint {table}: {error}")); - (table.to_string(), fingerprint) - }) - .collect() - } - - #[test] - fn final_runtime_manifest_matches_the_frozen_release_contract() { - let manifest = expected_manifest().expect("final manifest"); - assert_eq!(manifest.len(), 104); - verify_frozen_runtime_contract(&manifest).expect("frozen final runtime contract"); - } - - #[test] - fn run_ddl_allows_cancelled_outcome_but_rejects_cancelled_team_status() { - let conn = connection(); - initialize(&conn).expect("initialize runtime schema"); - - conn.execute( - "INSERT INTO agent_org_runtime_runs ( - id, org_id, coordinator_agent_id, entry_mode, status, - last_activity_outcome, created_at, updated_at - ) VALUES ( - 'outcome-cancelled', 'org-a', 'coordinator-a', - 'standalone_session', 'idle', 'cancelled', - '2026-08-01T00:00:00Z', '2026-08-01T00:00:00Z' - )", - [], - ) - .expect("cancelled is a valid last_activity_outcome"); - - let error = conn - .execute( - "INSERT INTO agent_org_runtime_runs ( - id, org_id, coordinator_agent_id, entry_mode, status, - last_activity_outcome, created_at, updated_at - ) VALUES ( - 'status-cancelled', 'org-a', 'coordinator-a', - 'standalone_session', 'cancelled', 'completed', - '2026-08-01T00:00:00Z', '2026-08-01T00:00:00Z' - )", - [], - ) - .expect_err("cancelled must not become an Agent Org Team status"); - assert!( - matches!( - error, - SqliteError::SqliteFailure(ref code, _) - if code.code == rusqlite::ErrorCode::ConstraintViolation - ), - "unexpected SQLite error: {error}" - ); - } - - #[test] - fn exact_official_v1_3_0_home_initializes_final_without_touching_shared_data() { - let conn = connection(); - create_official_v1_3_0_fixture(&conn); - seed_shared_sentinels(&conn); - let shared_before = shared_sentinel_fingerprint(&conn); - assert_eq!(count_known_tables(&conn, &LEGACY_TABLES).unwrap(), 11); - for table in LEGACY_TABLES { - assert_eq!(row_count(&conn, table), 1, "fixture row missing in {table}"); - } - - initialize(&conn).expect("upgrade exact official v1.3.0 home"); - - for table in LEGACY_TABLES { - assert!(!object_exists(&conn, "table", table), "retained {table}"); - } - for table in RUNTIME_TABLES { - assert!(object_exists(&conn, "table", table), "missing {table}"); - assert_eq!(row_count(&conn, table), 0, "fresh {table} not empty"); - } - verify_manifest(&conn, &expected_manifest().expect("final manifest")) - .expect("exact final manifest"); - assert_eq!(shared_sentinel_fingerprint(&conn), shared_before); - } - - #[test] - fn repeated_downgrade_cleanup_preserves_the_complete_canonical_runtime() { - let conn = connection(); - initialize(&conn).expect("fresh runtime"); - conn.execute_batch( - "INSERT INTO agent_org_runtime_runs ( - id, org_id, coordinator_agent_id, root_session_id, - org_snapshot_json, entry_mode, status, created_at, updated_at - ) VALUES ( - 'team-a', 'org-a', 'coordinator-a', 'root-a', '{\"team\":\"A\"}', - 'standalone_session', 'idle', '2026-08-01T00:00:00Z', '2026-08-01T00:00:00Z' - ); - INSERT INTO agent_org_runtime_run_progress - (org_run_id, work_revision, completion_requested, updated_at) - VALUES ('team-a', 7, 1, '2026-08-01T00:00:00Z'); - INSERT INTO agent_org_runtime_member_materializations - (org_run_id, member_id, agent_id, generation, session_id, - authority_class, status, created_at, updated_at) - VALUES ('team-a', 'member-a', 'agent-a', 1, 'session-a', - 'starting', 'succeeded', '2026-08-01T00:00:00Z', '2026-08-01T00:00:00Z'); - INSERT INTO agent_org_runtime_initial_inputs - (org_run_id, turn_intent_id, message_id, content, payload_json, - status, created_at, updated_at) - VALUES ('team-a', 'turn-a', 'message-a', 'hello', '{}', - 'dispatched', '2026-08-01T00:00:00Z', '2026-08-01T00:00:00Z'); - INSERT INTO agent_org_runtime_tasks - (id, org_run_id, activation_generation, subject, status, execution_mode, - created_by_participant_id, source_turn_intent_id, created_at, updated_at) - VALUES ('task-a', 'team-a', 1, 'Task A', 'pending', 'build', - 'coordinator', 'turn-a', - '2026-08-01T00:00:00Z', '2026-08-01T00:00:00Z'); - INSERT INTO agent_org_runtime_task_events - (id, org_run_id, task_id, event_type, actor_member_id, actor_kind, created_at) - VALUES ('event-a', 'team-a', 'task-a', 'created', 'coordinator', 'graph_writer', - '2026-08-01T00:00:00Z'); - INSERT INTO agent_org_runtime_task_annotations - (id, org_run_id, task_id, kind, body, actor_kind, - actor_participant_id, created_at) - VALUES ('annotation-a', 'team-a', 'task-a', 'audit_note', 'fixture', - 'graph_writer', 'coordinator', '2026-08-01T00:00:00Z'); - INSERT INTO agent_org_runtime_inbox - (recipient_agent_id, recipient_member_id, sender_agent_id, - sender_member_id, org_run_id, payload_kind, payload_json, created_at, read_at) - VALUES ('agent-a', 'member-a', 'coordinator-a', 'coordinator', 'team-a', - 'message', '{}', '2026-08-01T00:00:00Z', '2026-08-01T00:00:01Z'); - INSERT INTO agent_org_runtime_inbox_materializations - (inbox_id, session_id, transcript_message_id, transcript_intent_id, materialized_at) - VALUES (1, 'session-a', 'message-a', 'turn-a', '2026-08-01T00:00:01Z'); - INSERT INTO agent_org_runtime_inbox_delivery_resolutions - (inbox_id, org_run_id, resolution_kind, resolved_by_member_id, - reason, created_at) - VALUES (2, 'team-a', 'cancelled', 'coordinator', 'done', '2026-08-01T00:00:02Z'); - INSERT INTO agent_org_runtime_plan_revisions - (plan_revision_id, org_run_id, source_task_id, source_member_id, - source_session_id, source_turn_intent_id, root_session_id, - revision_number, plan_title, plan_path, plan_content, - content_digest, created_at) - VALUES ('revision-a', 'team-a', 'task-a', 'member-a', - 'session-a', 'turn-a', 'root-a', 1, 'Plan', '/tmp/plan-a', - '# plan', - 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa', - '2026-08-01T00:00:00Z'); - INSERT INTO agent_org_runtime_plan_decisions - (approval_id, plan_revision_id, request_id, policy, status, - decision_by, created_at, resolved_at) - VALUES ('approval-a', 'revision-a', 'request-a', 'coordinator', - 'approved', 'coordinator', '2026-08-01T00:00:00Z', - '2026-08-01T00:00:01Z'); - INSERT INTO agent_org_runtime_recovery_attempts - (org_run_id, action_kind, target_key, reason_fingerprint, attempts, - next_allowed_at, updated_at) - VALUES ('team-a', 'member_rewake', 'member-a', 'fingerprint', 1, - '2026-08-01T00:00:00Z', '2026-08-01T00:00:00Z'); - INSERT INTO agent_org_runtime_member_interventions - (intervention_receipt_id,org_run_id,member_id,agent_id,session_id, - status,source_event_id,entered_at,last_user_activity_at,updated_at) - VALUES ('intervention-a','team-a','member-a','agent-a','session-a','active', - 'message-a','2026-08-01T00:00:00Z','2026-08-01T00:00:00Z', - '2026-08-01T00:00:00Z');", - ) - .expect("canonical Team A fixture"); - let before = RUNTIME_TABLES - .into_iter() - .map(|table| (table, row_count(&conn, table))) - .collect::>(); - - for _ in 0..2 { - create_official_v1_3_0_fixture(&conn); - initialize(&conn).expect("re-upgrade cleanup"); - assert_eq!( - RUNTIME_TABLES - .into_iter() - .map(|table| (table, row_count(&conn, table))) - .collect::>(), - before - ); - for table in LEGACY_TABLES { - assert!(!object_exists(&conn, "table", table)); - } - } - - let snapshot: String = conn - .query_row( - "SELECT org_snapshot_json FROM agent_org_runtime_runs WHERE id='team-a'", - [], - |row| row.get(0), - ) - .expect("preserved snapshot"); - assert_eq!(snapshot, "{\"team\":\"A\"}"); - } - - #[test] - fn unpublished_runtime_without_history_index_is_rejected_without_touching_data() { - let conn = connection(); - initialize(&conn).expect("create current runtime"); - conn.execute_batch( - "INSERT INTO agent_org_runtime_runs ( - id,org_id,coordinator_agent_id,entry_mode,status,created_at,updated_at - ) VALUES ( - 'run-history-index-upgrade','org-a','coordinator-agent', - 'standalone_session','running', - '2026-08-30T00:00:00Z','2026-08-30T00:00:00Z' - ); - INSERT INTO agent_org_runtime_tasks ( - id,org_run_id,activation_generation,subject,status,execution_mode, - created_by_participant_id,source_turn_intent_id,created_at,updated_at - ) VALUES ( - 'task-history-index-upgrade','run-history-index-upgrade',1, - 'Preserve this Task','pending','build','coordinator','turn-a', - '2026-08-30T00:00:00Z','2026-08-30T00:00:00Z' - ); - DROP INDEX idx_agent_org_runtime_tasks_history_page;", - ) - .expect("simulate unpublished runtime without the final history index"); - - let error = initialize(&conn).expect_err("intermediate runtime must be rejected"); - assert!(error.to_string().contains("Agent Org runtime schema")); - assert_eq!(row_count(&conn, "agent_org_runtime_tasks"), 1); - } - - #[test] - fn unpublished_runtime_without_task_bindings_is_rejected_without_backfill() { - let conn = connection(); - conn.execute_batch( - "CREATE TABLE session_turn_intents ( - session_id TEXT NOT NULL, - turn_intent_id TEXT NOT NULL, - client_message_id TEXT, - org_run_id TEXT, - source TEXT NOT NULL, - status TEXT NOT NULL, - created_at TEXT NOT NULL, - updated_at TEXT NOT NULL, - PRIMARY KEY(session_id,turn_intent_id) - );", - ) - .expect("shared Turn intent schema"); - initialize(&conn).expect("create current runtime"); - let now = "2026-08-29T00:00:00Z"; - conn.execute_batch( - "INSERT INTO agent_org_runtime_runs ( - id,org_id,coordinator_agent_id,root_session_id,entry_mode,status, - activation_generation,created_at,updated_at - ) VALUES ( - 'run-binding-upgrade','org-a','coordinator-agent','root-session', - 'standalone_session','running',2, - '2026-08-29T00:00:00Z','2026-08-29T00:00:00Z' - ); - INSERT INTO session_turn_intents ( - session_id,turn_intent_id,org_run_id,source,status,created_at,updated_at - ) VALUES ( - 'root-session','root-reply-turn','run-binding-upgrade', - 'resume','completed','2026-08-29T00:00:00Z','2026-08-29T00:00:00Z' - ); - INSERT INTO agent_org_runtime_turn_contexts ( - session_id,turn_intent_id,org_run_id,participant_id,turn_kind, - source_kind,source_id,activation_generation,created_at - ) VALUES ( - 'root-session','root-reply-turn','run-binding-upgrade','coordinator', - 'coordinator','root_turn','root-reply-turn',2, - '2026-08-29T00:00:00Z' - ); - INSERT INTO agent_org_runtime_tasks ( - id,org_run_id,activation_generation,subject,owner,status,execution_mode, - created_by_participant_id,source_turn_intent_id,created_at,updated_at - ) VALUES ( - 'task-upgrade','run-binding-upgrade',2,'Upgrade task','member-a', - 'in_progress','build','coordinator','root-reply-turn', - '2026-08-29T00:00:00Z','2026-08-29T00:00:00Z' - ); - INSERT INTO agent_org_runtime_inbox ( - recipient_agent_id,recipient_member_id,sender_agent_id,sender_member_id, - org_run_id,payload_kind,payload_json,created_at - ) VALUES ( - 'member-agent','member-a','coordinator-agent','coordinator', - 'run-binding-upgrade','plain', - '{\"kind\":\"plain\",\"summary\":\"reply\",\"text\":\"continue\"}', - '2026-08-29T00:00:00Z' - );", - ) - .expect("seed previous-release reply facts"); - let inbox_id = conn.last_insert_rowid(); - let result = serde_json::json!({ - "delivered": [{ - "inbox_id": inbox_id, - "recipient_member_id": "member-a" - }], - "kind": "plain", - "org_run_id": "run-binding-upgrade", - "related_task_id": "task-upgrade", - "sender_member_id": "coordinator" - }) - .to_string(); - conn.execute( - "INSERT INTO agent_org_runtime_tool_call_receipts ( - org_run_id,session_id,turn_intent_id,call_id,tool_name,operation, - canonical_digest,result_text,created_at - ) VALUES ( - 'run-binding-upgrade','root-session','root-reply-turn','call-reply', - 'org_send_message','plain',?1,?2,?3 - )", - rusqlite::params!["a".repeat(64), result, now], - ) - .expect("seed exactly-once send receipt"); - - conn.execute_batch( - "DROP TABLE agent_org_runtime_inbox_task_bindings; - DROP INDEX idx_agent_org_runtime_tasks_history_page;", - ) - .expect("simulate unpublished runtime without final task bindings"); - assert_eq!( - count_known_tables(&conn, &RUNTIME_TABLES).unwrap(), - RUNTIME_TABLES.len() - 1 - ); - - let error = initialize(&conn).expect_err("intermediate runtime must be rejected"); - assert!(error - .to_string() - .contains("partial Agent Org runtime schema")); - assert_eq!(row_count(&conn, "agent_org_runtime_tool_call_receipts"), 1); - } - - #[test] - fn partial_or_unknown_runtime_schema_fails_closed_before_legacy_cleanup() { - for mutate in ["partial", "changed", "extra_index"] { - let conn = connection(); - initialize(&conn).expect("canonical runtime"); - conn.execute_batch("CREATE TABLE agent_org_runs (sentinel TEXT); INSERT INTO agent_org_runs VALUES ('legacy');") - .expect("legacy sentinel"); - match mutate { - "partial" => { - conn.execute_batch( - "DROP TABLE agent_org_runtime_turn_contexts; - DROP TABLE agent_org_runtime_member_dispatch_allocators;", - ) - .expect("make partial schema"); - assert_eq!( - count_known_tables(&conn, &RUNTIME_TABLES).unwrap(), - RUNTIME_TABLES.len() - 2 - ); - } - "changed" => { - conn.execute_batch( - "DROP TABLE agent_org_runtime_member_intervention_turns; - DROP TABLE agent_org_runtime_member_interventions; - CREATE TABLE agent_org_runtime_member_interventions (sentinel TEXT);", - ) - .expect("make changed schema"); - } - "extra_index" => conn - .execute_batch( - "CREATE INDEX idx_agent_org_runtime_unknown - ON agent_org_runtime_runs(updated_at);", - ) - .expect("make unknown index"), - _ => unreachable!(), - } - - let error = initialize(&conn).expect_err("unknown runtime must fail closed"); - assert!( - error.to_string().contains("Agent Org runtime schema"), - "{error}" - ); - assert_eq!(row_count(&conn, "agent_org_runs"), 1); - } - } - - #[test] - fn incomplete_runtime_manifest_requires_an_isolated_database() { - let conn = connection(); - initialize(&conn).expect("canonical pause runtime"); - conn.execute_batch( - "DROP TABLE agent_org_runtime_pause_handoffs; - DROP TABLE agent_org_runtime_pause_episodes;", - ) - .expect("simulate an incomplete strict runtime manifest"); - assert_eq!( - count_known_tables(&conn, &RUNTIME_TABLES).unwrap(), - RUNTIME_TABLES.len() - 2 - ); - - let error = initialize(&conn).expect_err("previous runtime must not be migrated in place"); - let expected_message = format!( - "found {} of {} canonical tables", - RUNTIME_TABLES.len() - 2, - RUNTIME_TABLES.len() - ); - assert!( - error.to_string().contains(&expected_message), - "unexpected strict-schema error: {error}" - ); - } - - #[test] - fn create_failure_rolls_back_every_legacy_drop() { - let conn = connection(); - create_official_v1_3_0_fixture(&conn); - conn.execute_batch("CREATE VIEW agent_org_runtime_runs AS SELECT 1 AS id;") - .expect("runtime name conflict"); - - initialize(&conn).expect_err("runtime create must fail"); - - for table in LEGACY_TABLES { - assert!( - object_exists(&conn, "table", table), - "rollback lost {table}" - ); - assert_eq!(row_count(&conn, table), 1); - } - assert!(object_exists(&conn, "view", "agent_org_runtime_runs")); - } - - #[test] - fn unknown_agent_org_objects_are_preserved() { - let conn = connection(); - conn.execute_batch( - "CREATE TABLE agent_org_local_experiment (sentinel TEXT); - INSERT INTO agent_org_local_experiment VALUES ('keep');", - ) - .expect("unknown table"); - - initialize(&conn).expect("initialize around unknown object"); - - assert_eq!(row_count(&conn, "agent_org_local_experiment"), 1); - } - - #[test] - fn concurrent_initializers_serialize_to_one_canonical_schema() { - let directory = tempfile::tempdir().expect("temporary database directory"); - let path = directory.path().join("sessions.db"); - let barrier = Arc::new(Barrier::new(2)); - let handles = (0..2) - .map(|_| { - let path = path.clone(); - let barrier = Arc::clone(&barrier); - std::thread::spawn(move || { - let conn = Connection::open(path).expect("open shared SQLite database"); - conn.busy_timeout(Duration::from_secs(5)) - .expect("set busy timeout"); - conn.execute_batch("PRAGMA foreign_keys=ON;") - .expect("enable foreign keys"); - barrier.wait(); - initialize(&conn) - }) - }) - .collect::>(); - - for handle in handles { - handle - .join() - .expect("initializer thread") - .expect("initialize"); - } - - let conn = Connection::open(path).expect("reopen shared database"); - verify_manifest(&conn, &expected_manifest().expect("expected manifest")) - .expect("canonical manifest after concurrent init"); - assert_eq!( - count_known_tables(&conn, &RUNTIME_TABLES).unwrap(), - RUNTIME_TABLES.len() - ); - } - - #[test] - fn measures_constant_scale_startup_paths() { - const SAMPLES: usize = 25; - let mut fresh = Vec::with_capacity(SAMPLES); - let mut no_op = Vec::with_capacity(SAMPLES); - let mut cleanup = Vec::with_capacity(SAMPLES); - - for _ in 0..SAMPLES { - let conn = connection(); - let started = Instant::now(); - initialize(&conn).expect("fresh init"); - fresh.push(started.elapsed()); - - let started = Instant::now(); - initialize(&conn).expect("canonical no-op init"); - no_op.push(started.elapsed()); - - create_official_v1_3_0_fixture(&conn); - let started = Instant::now(); - initialize(&conn).expect("legacy cleanup init"); - cleanup.push(started.elapsed()); - } - - fn summary(samples: &mut [Duration]) -> (Duration, Duration) { - samples.sort_unstable(); - (samples[samples.len() / 2], *samples.last().unwrap()) - } - let (fresh_median, fresh_max) = summary(&mut fresh); - let (no_op_median, no_op_max) = summary(&mut no_op); - let (cleanup_median, cleanup_max) = summary(&mut cleanup); - eprintln!( - "Agent Org schema init, {SAMPLES} samples: fresh median={fresh_median:?} max={fresh_max:?}; canonical no-op median={no_op_median:?} max={no_op_max:?}; official-v1.3.0 cleanup median={cleanup_median:?} max={cleanup_max:?}" - ); - } -} +#[path = "schema_tests.rs"] +mod tests; diff --git a/src-tauri/crates/agent-core/src/core/coordination/schema_tests.rs b/src-tauri/crates/agent-core/src/core/coordination/schema_tests.rs new file mode 100644 index 0000000000..e65a488a17 --- /dev/null +++ b/src-tauri/crates/agent-core/src/core/coordination/schema_tests.rs @@ -0,0 +1,607 @@ +use std::sync::{Arc, Barrier}; +use std::time::{Duration, Instant}; + +use super::*; + +const LEGACY_TABLES: [&str; 11] = [ + "agent_org_runs", + "agent_org_run_progress", + "agent_org_plan_approvals", + "agent_org_recovery_attempts", + "agent_org_tasks", + "agent_org_task_events", + "agent_org_task_run_schema_migrations", + "agent_inbox", + "agent_inbox_materializations", + "agent_inbox_delivery_resolutions", + "agent_member_interventions", +]; + +fn count_known_tables(conn: &Connection, names: &[&str]) -> SqliteResult { + Ok(names + .iter() + .filter(|name| object_exists(conn, "table", name)) + .count()) +} + +fn connection() -> Connection { + let conn = Connection::open_in_memory().expect("in-memory SQLite"); + conn.execute_batch("PRAGMA foreign_keys=ON;") + .expect("enable foreign keys"); + conn +} + +fn object_exists(conn: &Connection, object_type: &str, name: &str) -> bool { + conn.query_row( + "SELECT EXISTS( + SELECT 1 FROM sqlite_master WHERE type=?1 AND name=?2 + )", + rusqlite::params![object_type, name], + |row| row.get(0), + ) + .expect("inspect schema object") +} + +fn row_count(conn: &Connection, table: &str) -> i64 { + conn.query_row(&format!("SELECT COUNT(*) FROM {table}"), [], |row| { + row.get(0) + }) + .unwrap_or_else(|error| panic!("count {table}: {error}")) +} + +fn create_official_v1_3_0_fixture(conn: &Connection) { + conn.execute_batch(include_str!("fixtures/official_v1_3_0_agent_org.sql")) + .expect("create exact official v1.3.0 Agent Org fixture"); +} + +fn seed_shared_sentinels(conn: &Connection) { + crate::persistence::session_snapshots::ensure_tables_with(conn) + .expect("create production Session/message schema"); + conn.execute_batch( + "CREATE TABLE code_sessions ( + id TEXT PRIMARY KEY, session_id TEXT UNIQUE, payload BLOB, org_member_id TEXT + ); + CREATE TABLE session_turn_intents (id TEXT PRIMARY KEY, payload BLOB, org_run_id TEXT); + CREATE TABLE projects (id TEXT PRIMARY KEY, payload BLOB); + CREATE TABLE work_items (id TEXT PRIMARY KEY, payload BLOB); + CREATE TABLE routines (id TEXT PRIMARY KEY, payload BLOB); + CREATE TABLE usage_events (id TEXT PRIMARY KEY, payload BLOB); + INSERT INTO agent_sessions ( + session_id,name,status,user_input,created_at,updated_at + ) VALUES ( + 'ordinary-session','Ordinary SDE','idle','ordinary sentinel', + '2026-08-01T00:00:00Z','2026-08-01T00:00:00Z' + ); + INSERT INTO agent_messages ( + id,session_id,role,content,sequence,created_at + ) VALUES ( + 'ordinary-message','ordinary-session','assistant', + 'ordinary message sentinel',1,'2026-08-01T00:00:00Z' + ); + INSERT INTO code_sessions VALUES ('cli', 'cli-session', x'060708', 'member-b'); + INSERT INTO session_turn_intents VALUES ('intent', x'090A0B', 'run-a'); + INSERT INTO projects VALUES ('project', x'0C0D0E'); + INSERT INTO work_items VALUES ('work-item', x'0F1011'); + INSERT INTO routines VALUES ('routine', x'121314'); + INSERT INTO usage_events VALUES ('usage', x'151617');", + ) + .expect("shared sentinels"); +} + +fn shared_sentinel_fingerprint(conn: &Connection) -> Vec<(String, String)> { + [ + ( + "agent_sessions", + "SELECT session_id || '|' || name || '|' || status || '|' || user_input + FROM agent_sessions WHERE session_id='ordinary-session'", + ), + ( + "agent_messages", + "SELECT id || '|' || session_id || '|' || role || '|' || content || '|' || sequence + FROM agent_messages WHERE id='ordinary-message'", + ), + ("code_sessions", "SELECT hex(payload) FROM code_sessions"), + ( + "session_turn_intents", + "SELECT hex(payload) FROM session_turn_intents", + ), + ("projects", "SELECT hex(payload) FROM projects"), + ("work_items", "SELECT hex(payload) FROM work_items"), + ("routines", "SELECT hex(payload) FROM routines"), + ("usage_events", "SELECT hex(payload) FROM usage_events"), + ] + .into_iter() + .map(|(table, query)| { + let fingerprint = conn + .query_row(query, [], |row| row.get::<_, String>(0)) + .unwrap_or_else(|error| panic!("fingerprint {table}: {error}")); + (table.to_string(), fingerprint) + }) + .collect() +} + +#[test] +fn final_runtime_manifest_matches_the_frozen_release_contract() { + let manifest = expected_manifest().expect("final manifest"); + assert_eq!(manifest.len(), 119); + verify_frozen_runtime_contract(&manifest).expect("frozen final runtime contract"); +} + +#[test] +fn run_ddl_allows_cancelled_outcome_but_rejects_cancelled_team_status() { + let conn = connection(); + initialize(&conn).expect("initialize runtime schema"); + + conn.execute( + "INSERT INTO agent_org_execution_runs ( + id, org_id, coordinator_agent_id, entry_mode, status, + last_activity_outcome, created_at, updated_at + ) VALUES ( + 'outcome-cancelled', 'org-a', 'coordinator-a', + 'standalone_session', 'idle', 'cancelled', + '2026-08-01T00:00:00Z', '2026-08-01T00:00:00Z' + )", + [], + ) + .expect("cancelled is a valid last_activity_outcome"); + + let error = conn + .execute( + "INSERT INTO agent_org_execution_runs ( + id, org_id, coordinator_agent_id, entry_mode, status, + last_activity_outcome, created_at, updated_at + ) VALUES ( + 'status-cancelled', 'org-a', 'coordinator-a', + 'standalone_session', 'cancelled', 'completed', + '2026-08-01T00:00:00Z', '2026-08-01T00:00:00Z' + )", + [], + ) + .expect_err("cancelled must not become an Agent Org Team status"); + assert!( + matches!( + error, + SqliteError::SqliteFailure(ref code, _) + if code.code == rusqlite::ErrorCode::ConstraintViolation + ), + "unexpected SQLite error: {error}" + ); +} + +#[test] +fn exact_official_v1_3_0_home_initializes_final_without_touching_shared_data() { + let conn = connection(); + create_official_v1_3_0_fixture(&conn); + seed_shared_sentinels(&conn); + let shared_before = shared_sentinel_fingerprint(&conn); + assert_eq!(count_known_tables(&conn, &LEGACY_TABLES).unwrap(), 11); + for table in LEGACY_TABLES { + assert_eq!(row_count(&conn, table), 1, "fixture row missing in {table}"); + } + + initialize(&conn).expect("upgrade exact official v1.3.0 home"); + + for table in LEGACY_TABLES { + assert!(!object_exists(&conn, "table", table), "retained {table}"); + } + for table in RUNTIME_TABLES { + assert!(object_exists(&conn, "table", table), "missing {table}"); + assert_eq!(row_count(&conn, table), 0, "fresh {table} not empty"); + } + verify_manifest(&conn, &expected_manifest().expect("final manifest")) + .expect("exact final manifest"); + assert_eq!(shared_sentinel_fingerprint(&conn), shared_before); +} + +#[test] +fn repeated_downgrade_cleanup_preserves_the_complete_canonical_runtime() { + let conn = connection(); + initialize(&conn).expect("fresh runtime"); + conn.execute_batch( + "INSERT INTO agent_org_execution_runs ( + id, org_id, coordinator_agent_id, root_session_id, + org_snapshot_json, entry_mode, status, created_at, updated_at + ) VALUES ( + 'team-a', 'org-a', 'coordinator-a', 'root-a', '{\"team\":\"A\"}', + 'standalone_session', 'idle', '2026-08-01T00:00:00Z', '2026-08-01T00:00:00Z' + ); + INSERT INTO agent_org_execution_run_progress + (org_run_id, work_revision, completion_requested, updated_at) + VALUES ('team-a', 7, 1, '2026-08-01T00:00:00Z'); + INSERT INTO agent_org_execution_member_materializations + (org_run_id, member_id, agent_id, generation, session_id, + authority_class, status, created_at, updated_at) + VALUES ('team-a', 'member-a', 'agent-a', 1, 'session-a', + 'starting', 'succeeded', '2026-08-01T00:00:00Z', '2026-08-01T00:00:00Z'); + INSERT INTO agent_org_execution_initial_inputs + (org_run_id, turn_intent_id, message_id, content, payload_json, + status, created_at, updated_at) + VALUES ('team-a', 'turn-a', 'message-a', 'hello', '{}', + 'dispatched', '2026-08-01T00:00:00Z', '2026-08-01T00:00:00Z'); + INSERT INTO agent_org_execution_tasks + (id, org_run_id, activation_generation, subject, status, execution_mode, + created_by_participant_id, source_turn_intent_id, created_at, updated_at) + VALUES ('task-a', 'team-a', 1, 'Task A', 'pending', 'build', + 'coordinator', 'turn-a', + '2026-08-01T00:00:00Z', '2026-08-01T00:00:00Z'); + INSERT INTO agent_org_execution_task_events + (id, org_run_id, task_id, event_type, actor_member_id, actor_kind, created_at) + VALUES ('event-a', 'team-a', 'task-a', 'created', 'coordinator', 'graph_writer', + '2026-08-01T00:00:00Z'); + INSERT INTO agent_org_execution_task_annotations + (id, org_run_id, task_id, kind, body, actor_kind, + actor_participant_id, created_at) + VALUES ('annotation-a', 'team-a', 'task-a', 'audit_note', 'fixture', + 'graph_writer', 'coordinator', '2026-08-01T00:00:00Z'); + INSERT INTO agent_org_execution_inbox + (recipient_agent_id, recipient_member_id, sender_agent_id, + sender_member_id, org_run_id, payload_kind, payload_json, created_at, read_at) + VALUES ('agent-a', 'member-a', 'coordinator-a', 'coordinator', 'team-a', + 'message', '{}', '2026-08-01T00:00:00Z', '2026-08-01T00:00:01Z'); + INSERT INTO agent_org_execution_inbox_materializations + (inbox_id, session_id, transcript_message_id, transcript_intent_id, materialized_at) + VALUES (1, 'session-a', 'message-a', 'turn-a', '2026-08-01T00:00:01Z'); + INSERT INTO agent_org_execution_inbox_delivery_resolutions + (inbox_id, org_run_id, resolution_kind, resolved_by_member_id, + reason, created_at) + VALUES (2, 'team-a', 'cancelled', 'coordinator', 'done', '2026-08-01T00:00:02Z'); + INSERT INTO agent_org_execution_plan_revisions + (plan_revision_id, org_run_id, source_task_id, source_member_id, + source_session_id, source_turn_intent_id, root_session_id, + revision_number, plan_title, plan_path, plan_content, + content_digest, created_at) + VALUES ('revision-a', 'team-a', 'task-a', 'member-a', + 'session-a', 'turn-a', 'root-a', 1, 'Plan', '/tmp/plan-a', + '# plan', + 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa', + '2026-08-01T00:00:00Z'); + INSERT INTO agent_org_execution_plan_decisions + (approval_id, plan_revision_id, request_id, policy, status, + decision_by, created_at, resolved_at) + VALUES ('approval-a', 'revision-a', 'request-a', 'coordinator', + 'approved', 'coordinator', '2026-08-01T00:00:00Z', + '2026-08-01T00:00:01Z'); + INSERT INTO agent_org_execution_recovery_attempts + (org_run_id, action_kind, target_key, reason_fingerprint, attempts, + next_allowed_at, updated_at) + VALUES ('team-a', 'member_rewake', 'member-a', 'fingerprint', 1, + '2026-08-01T00:00:00Z', '2026-08-01T00:00:00Z'); + INSERT INTO agent_org_execution_member_interventions + (intervention_receipt_id,org_run_id,member_id,agent_id,session_id, + status,source_event_id,entered_at,last_user_activity_at,updated_at) + VALUES ('intervention-a','team-a','member-a','agent-a','session-a','active', + 'message-a','2026-08-01T00:00:00Z','2026-08-01T00:00:00Z', + '2026-08-01T00:00:00Z');", + ) + .expect("canonical Team A fixture"); + let before = RUNTIME_TABLES + .into_iter() + .map(|table| (table, row_count(&conn, table))) + .collect::>(); + + for _ in 0..2 { + create_official_v1_3_0_fixture(&conn); + initialize(&conn).expect("re-upgrade cleanup"); + assert_eq!( + RUNTIME_TABLES + .into_iter() + .map(|table| (table, row_count(&conn, table))) + .collect::>(), + before + ); + for table in LEGACY_TABLES { + assert!(!object_exists(&conn, "table", table)); + } + } + + let snapshot: String = conn + .query_row( + "SELECT org_snapshot_json FROM agent_org_execution_runs WHERE id='team-a'", + [], + |row| row.get(0), + ) + .expect("preserved snapshot"); + assert_eq!(snapshot, "{\"team\":\"A\"}"); +} + +#[test] +fn unpublished_runtime_without_history_index_is_rejected_without_touching_data() { + let conn = connection(); + initialize(&conn).expect("create current runtime"); + conn.execute_batch( + "INSERT INTO agent_org_execution_runs ( + id,org_id,coordinator_agent_id,entry_mode,status,created_at,updated_at + ) VALUES ( + 'run-history-index-upgrade','org-a','coordinator-agent', + 'standalone_session','running', + '2026-08-30T00:00:00Z','2026-08-30T00:00:00Z' + ); + INSERT INTO agent_org_execution_tasks ( + id,org_run_id,activation_generation,subject,status,execution_mode, + created_by_participant_id,source_turn_intent_id,created_at,updated_at + ) VALUES ( + 'task-history-index-upgrade','run-history-index-upgrade',1, + 'Preserve this Task','pending','build','coordinator','turn-a', + '2026-08-30T00:00:00Z','2026-08-30T00:00:00Z' + ); + DROP INDEX idx_agent_org_execution_tasks_history_page;", + ) + .expect("simulate unpublished runtime without the final history index"); + + let error = initialize(&conn).expect_err("intermediate runtime must be rejected"); + assert!(error.to_string().contains("Agent Org runtime schema")); + assert_eq!(row_count(&conn, "agent_org_execution_tasks"), 1); +} + +#[test] +fn unpublished_runtime_without_task_bindings_is_rejected_without_backfill() { + let conn = connection(); + conn.execute_batch( + "CREATE TABLE session_turn_intents ( + session_id TEXT NOT NULL, + turn_intent_id TEXT NOT NULL, + client_message_id TEXT, + org_run_id TEXT, + source TEXT NOT NULL, + status TEXT NOT NULL, + created_at TEXT NOT NULL, + updated_at TEXT NOT NULL, + PRIMARY KEY(session_id,turn_intent_id) + );", + ) + .expect("shared Turn intent schema"); + initialize(&conn).expect("create current runtime"); + let now = "2026-08-29T00:00:00Z"; + conn.execute_batch( + "INSERT INTO agent_org_execution_runs ( + id,org_id,coordinator_agent_id,root_session_id,entry_mode,status, + activation_generation,created_at,updated_at + ) VALUES ( + 'run-binding-upgrade','org-a','coordinator-agent','root-session', + 'standalone_session','running',2, + '2026-08-29T00:00:00Z','2026-08-29T00:00:00Z' + ); + INSERT INTO session_turn_intents ( + session_id,turn_intent_id,org_run_id,source,status,created_at,updated_at + ) VALUES ( + 'root-session','root-reply-turn','run-binding-upgrade', + 'resume','completed','2026-08-29T00:00:00Z','2026-08-29T00:00:00Z' + ); + INSERT INTO agent_org_execution_turn_contexts ( + session_id,turn_intent_id,org_run_id,participant_id,turn_kind, + source_kind,source_id,activation_generation,created_at + ) VALUES ( + 'root-session','root-reply-turn','run-binding-upgrade','coordinator', + 'coordinator','root_turn','root-reply-turn',2, + '2026-08-29T00:00:00Z' + ); + INSERT INTO agent_org_execution_tasks ( + id,org_run_id,activation_generation,subject,owner,status,execution_mode, + created_by_participant_id,source_turn_intent_id,created_at,updated_at + ) VALUES ( + 'task-upgrade','run-binding-upgrade',2,'Upgrade task','member-a', + 'in_progress','build','coordinator','root-reply-turn', + '2026-08-29T00:00:00Z','2026-08-29T00:00:00Z' + ); + INSERT INTO agent_org_execution_inbox ( + recipient_agent_id,recipient_member_id,sender_agent_id,sender_member_id, + org_run_id,payload_kind,payload_json,created_at + ) VALUES ( + 'member-agent','member-a','coordinator-agent','coordinator', + 'run-binding-upgrade','plain', + '{\"kind\":\"plain\",\"summary\":\"reply\",\"text\":\"continue\"}', + '2026-08-29T00:00:00Z' + );", + ) + .expect("seed previous-release reply facts"); + let inbox_id = conn.last_insert_rowid(); + let result = serde_json::json!({ + "delivered": [{ + "inbox_id": inbox_id, + "recipient_member_id": "member-a" + }], + "kind": "plain", + "org_run_id": "run-binding-upgrade", + "related_task_id": "task-upgrade", + "sender_member_id": "coordinator" + }) + .to_string(); + conn.execute( + "INSERT INTO agent_org_execution_tool_call_receipts ( + org_run_id,session_id,turn_intent_id,call_id,tool_name,operation, + canonical_digest,result_text,created_at + ) VALUES ( + 'run-binding-upgrade','root-session','root-reply-turn','call-reply', + 'org_send_message','plain',?1,?2,?3 + )", + rusqlite::params!["a".repeat(64), result, now], + ) + .expect("seed exactly-once send receipt"); + + conn.execute_batch( + "DROP TABLE agent_org_execution_inbox_task_bindings; + DROP INDEX idx_agent_org_execution_tasks_history_page;", + ) + .expect("simulate unpublished runtime without final task bindings"); + assert_eq!( + count_known_tables(&conn, &RUNTIME_TABLES).unwrap(), + RUNTIME_TABLES.len() - 1 + ); + + let error = initialize(&conn).expect_err("intermediate runtime must be rejected"); + assert!(error + .to_string() + .contains("unknown Agent Org runtime schema")); + assert_eq!( + row_count(&conn, "agent_org_execution_tool_call_receipts"), + 1 + ); +} + +#[test] +fn partial_or_unknown_runtime_schema_fails_closed_before_legacy_cleanup() { + for mutate in ["partial", "changed", "extra_index"] { + let conn = connection(); + initialize(&conn).expect("canonical runtime"); + conn.execute_batch("CREATE TABLE agent_org_runs (sentinel TEXT); INSERT INTO agent_org_runs VALUES ('legacy');") + .expect("legacy sentinel"); + match mutate { + "partial" => { + conn.execute_batch( + "DROP TABLE agent_org_execution_turn_contexts; + DROP TABLE agent_org_execution_member_dispatch_allocators;", + ) + .expect("make partial schema"); + assert_eq!( + count_known_tables(&conn, &RUNTIME_TABLES).unwrap(), + RUNTIME_TABLES.len() - 2 + ); + } + "changed" => { + conn.execute_batch( + "DROP TABLE agent_org_execution_member_intervention_turns; + DROP TABLE agent_org_execution_member_interventions; + CREATE TABLE agent_org_execution_member_interventions (sentinel TEXT);", + ) + .expect("make changed schema"); + } + "extra_index" => conn + .execute_batch( + "CREATE INDEX idx_agent_org_runtime_unknown + ON agent_org_execution_runs(updated_at);", + ) + .expect("make unknown index"), + _ => unreachable!(), + } + + let error = initialize(&conn).expect_err("unknown runtime must fail closed"); + assert!( + error.to_string().contains("Agent Org runtime schema"), + "{error}" + ); + assert_eq!(row_count(&conn, "agent_org_runs"), 1); + } +} + +#[test] +fn incomplete_runtime_manifest_requires_an_isolated_database() { + let conn = connection(); + initialize(&conn).expect("canonical pause runtime"); + conn.execute_batch( + "DROP TABLE agent_org_execution_pause_handoffs; + DROP TABLE agent_org_execution_pause_episodes;", + ) + .expect("simulate an incomplete strict runtime manifest"); + assert_eq!( + count_known_tables(&conn, &RUNTIME_TABLES).unwrap(), + RUNTIME_TABLES.len() - 2 + ); + + let error = initialize(&conn).expect_err("previous runtime must not be migrated in place"); + assert!(error.to_string().contains("missing="), "{error}"); +} + +#[test] +fn create_failure_rolls_back_every_legacy_drop() { + let conn = connection(); + create_official_v1_3_0_fixture(&conn); + conn.execute_batch("CREATE VIEW agent_org_execution_runs AS SELECT 1 AS id;") + .expect("runtime name conflict"); + + initialize(&conn).expect_err("runtime create must fail"); + + for table in LEGACY_TABLES { + assert!( + object_exists(&conn, "table", table), + "rollback lost {table}" + ); + assert_eq!(row_count(&conn, table), 1); + } + assert!(object_exists(&conn, "view", "agent_org_execution_runs")); +} + +#[test] +fn unknown_agent_org_objects_are_preserved() { + let conn = connection(); + conn.execute_batch( + "CREATE TABLE agent_org_local_experiment (sentinel TEXT); + INSERT INTO agent_org_local_experiment VALUES ('keep');", + ) + .expect("unknown table"); + + initialize(&conn).expect("initialize around unknown object"); + + assert_eq!(row_count(&conn, "agent_org_local_experiment"), 1); +} + +#[test] +fn concurrent_initializers_serialize_to_one_canonical_schema() { + let directory = tempfile::tempdir().expect("temporary database directory"); + let path = directory.path().join("sessions.db"); + let barrier = Arc::new(Barrier::new(2)); + let handles = (0..2) + .map(|_| { + let path = path.clone(); + let barrier = Arc::clone(&barrier); + std::thread::spawn(move || { + let conn = Connection::open(path).expect("open shared SQLite database"); + conn.busy_timeout(Duration::from_secs(5)) + .expect("set busy timeout"); + conn.execute_batch("PRAGMA foreign_keys=ON;") + .expect("enable foreign keys"); + barrier.wait(); + initialize(&conn) + }) + }) + .collect::>(); + + for handle in handles { + handle + .join() + .expect("initializer thread") + .expect("initialize"); + } + + let conn = Connection::open(path).expect("reopen shared database"); + verify_manifest(&conn, &expected_manifest().expect("expected manifest")) + .expect("canonical manifest after concurrent init"); + assert_eq!( + count_known_tables(&conn, &RUNTIME_TABLES).unwrap(), + RUNTIME_TABLES.len() + ); +} + +#[test] +fn measures_constant_scale_startup_paths() { + const SAMPLES: usize = 25; + let mut fresh = Vec::with_capacity(SAMPLES); + let mut no_op = Vec::with_capacity(SAMPLES); + let mut cleanup = Vec::with_capacity(SAMPLES); + + for _ in 0..SAMPLES { + let conn = connection(); + let started = Instant::now(); + initialize(&conn).expect("fresh init"); + fresh.push(started.elapsed()); + + let started = Instant::now(); + initialize(&conn).expect("canonical no-op init"); + no_op.push(started.elapsed()); + + create_official_v1_3_0_fixture(&conn); + let started = Instant::now(); + initialize(&conn).expect("legacy cleanup init"); + cleanup.push(started.elapsed()); + } + + fn summary(samples: &mut [Duration]) -> (Duration, Duration) { + samples.sort_unstable(); + (samples[samples.len() / 2], *samples.last().unwrap()) + } + let (fresh_median, fresh_max) = summary(&mut fresh); + let (no_op_median, no_op_max) = summary(&mut no_op); + let (cleanup_median, cleanup_max) = summary(&mut cleanup); + eprintln!( + "Agent Org schema init, {SAMPLES} samples: fresh median={fresh_median:?} max={fresh_max:?}; canonical no-op median={no_op_median:?} max={no_op_max:?}; official-v1.3.0 cleanup median={cleanup_median:?} max={cleanup_max:?}" + ); +} diff --git a/src-tauri/crates/agent-core/src/core/definitions/orgs.rs b/src-tauri/crates/agent-core/src/core/definitions/orgs.rs index 6986de6c39..49b2c5d328 100644 --- a/src-tauri/crates/agent-core/src/core/definitions/orgs.rs +++ b/src-tauri/crates/agent-core/src/core/definitions/orgs.rs @@ -8,7 +8,7 @@ use std::path::Path; #[cfg(not(test))] use std::sync::OnceLock; use std::sync::{Arc, Mutex}; -use tracing::{error, info, warn}; +use tracing::{error, info}; use app_paths::agent_org_definitions as storage_path; use key_vault::ModelType; @@ -375,7 +375,6 @@ impl Default for AgentOrgsStore { impl AgentOrgsStore { pub fn new() -> Self { - retire_legacy_definitions_file(); let path = storage_path(); let (mut orgs, persistence_blocked, should_persist) = match load_from_disk(&path) { LoadOutcome::Missing => (Vec::new(), None, true), @@ -971,24 +970,6 @@ pub(crate) fn parse_definitions_content( Ok(file.definitions) } -fn retire_legacy_definitions_file() { - let legacy_path = app_paths::agent_orgs(); - match std::fs::remove_file(&legacy_path) { - Ok(()) => info!( - event = "agent_org_legacy_definitions_retired", - path = %legacy_path.display(), - "removed retired Agent Org definitions file" - ), - Err(err) if err.kind() == std::io::ErrorKind::NotFound => {} - Err(err) => warn!( - event = "agent_org_legacy_definitions_retirement_failed", - path = %legacy_path.display(), - error = %err, - "could not remove retired Agent Org definitions file; canonical store remains isolated" - ), - } -} - fn save_to_disk(path: &Path, orgs: &[OrgDefinition]) -> Result<(), String> { let file = AgentOrgDefinitionsFile { schema_version: AGENT_ORGS_FILE_SCHEMA_VERSION, @@ -1196,7 +1177,7 @@ mod tests { } #[test] - fn legacy_live_file_is_deleted_without_parsing_and_new_builtins_are_created() { + fn legacy_live_file_is_preserved_without_parsing_and_new_builtins_are_created() { let _sandbox = test_helpers::test_env::sandbox(); let new_path = storage_path(); let legacy_path = app_paths::agent_orgs(); @@ -1208,7 +1189,7 @@ mod tests { let store = AgentOrgsStore::new(); assert!(store.get(DEFAULT_SDE_TEMPLATE_TEAM_ID).is_ok()); - assert!(!legacy_path.exists()); + assert!(legacy_path.exists()); assert!(new_path.exists()); assert_eq!( std::fs::read(unrelated_path).unwrap(), @@ -1217,7 +1198,7 @@ mod tests { } #[test] - fn downgrade_recreated_legacy_file_is_deleted_without_changing_new_bytes() { + fn downgrade_recreated_legacy_file_is_preserved_without_changing_new_bytes() { let _sandbox = test_helpers::test_env::sandbox(); let store = AgentOrgsStore::new(); let mut org = custom_org(&["alice", "bob"]); @@ -1237,7 +1218,7 @@ mod tests { let restarted = AgentOrgsStore::new(); - assert!(!legacy_path.exists()); + assert!(legacy_path.exists()); assert_eq!( std::fs::read(&new_path).expect("new bytes after cleanup"), new_bytes diff --git a/src-tauri/crates/agent-core/src/core/session/persistence/crud/ops.rs b/src-tauri/crates/agent-core/src/core/session/persistence/crud/ops.rs index 011c7a8789..d967b4a8ec 100644 --- a/src-tauri/crates/agent-core/src/core/session/persistence/crud/ops.rs +++ b/src-tauri/crates/agent-core/src/core/session/persistence/crud/ops.rs @@ -264,7 +264,12 @@ pub fn get_session(session_id: &str) -> SqliteResult SqliteResult> { let conn = get_connection()?; - let mut conditions: Vec = Vec::new(); + // Compatibility copies are a downgrade representation; the current + // directory lists their authoritative source sessions exactly once. + let mut conditions: Vec = vec![ + "NOT EXISTS (SELECT 1 FROM org_history_copies c WHERE c.copy_session_id=s.session_id)" + .into(), + ]; let mut params_vec: Vec> = Vec::new(); if let Some(ref type_name) = filter.type_name { @@ -361,7 +366,8 @@ pub fn mark_stale_running_sessions_abandoned() -> SqliteResult { // adding a new in-flight variant only requires updating one place. let updated = conn.execute( "UPDATE agent_sessions SET status = ?1, updated_at = ?2 \ - WHERE status IN (?3, ?4, ?5)", + WHERE status IN (?3, ?4, ?5) + AND NOT EXISTS (SELECT 1 FROM org_history_sessions h WHERE h.session_id=agent_sessions.session_id)", params![ SessionStatus::Abandoned.as_str(), now, @@ -470,6 +476,7 @@ pub fn reconcile_sessions_with_terminal_turn_markers() -> SqliteResult { END, updated_at = COALESCE(last_terminal_turn_at, updated_at) WHERE status IN (?2, ?3, ?4) + AND NOT EXISTS (SELECT 1 FROM org_history_sessions h WHERE h.session_id=agent_sessions.session_id) AND last_terminal_turn_id IS NOT NULL AND last_terminal_turn_status IN (?5, ?7, ?9)", params![ diff --git a/src-tauri/crates/agent-core/src/core/session/persistence/messages.rs b/src-tauri/crates/agent-core/src/core/session/persistence/messages.rs index 4ac3e56dca..98ba2953a2 100644 --- a/src-tauri/crates/agent-core/src/core/session/persistence/messages.rs +++ b/src-tauri/crates/agent-core/src/core/session/persistence/messages.rs @@ -106,7 +106,7 @@ pub fn load_agent_org_inbox_transcript_materializations( receipt.transcript_message_id, receipt.transcript_intent_id, message.content - FROM agent_org_runtime_inbox_materializations receipt + FROM agent_org_execution_inbox_materializations receipt LEFT JOIN agent_messages message ON message.id=receipt.transcript_message_id AND message.session_id=receipt.session_id @@ -213,8 +213,8 @@ fn materialize_agent_org_inbox_transcript_internal( let mut stmt = tx .prepare( "SELECT inbox.org_run_id,run.status - FROM agent_org_runtime_inbox inbox - LEFT JOIN agent_org_runtime_runs run ON run.id=inbox.org_run_id + FROM agent_org_execution_inbox inbox + LEFT JOIN agent_org_execution_runs run ON run.id=inbox.org_run_id WHERE inbox.id=?1", ) .map_err(|err| err.to_string())?; @@ -238,7 +238,7 @@ fn materialize_agent_org_inbox_transcript_internal( let mut stmt = tx .prepare( "SELECT session_id, transcript_message_id, transcript_intent_id - FROM agent_org_runtime_inbox_materializations WHERE inbox_id=?1", + FROM agent_org_execution_inbox_materializations WHERE inbox_id=?1", ) .map_err(|err| err.to_string())?; for inbox_id in inbox_ids { @@ -266,7 +266,7 @@ fn materialize_agent_org_inbox_transcript_internal( let unread_count = { let mut stmt = tx - .prepare("SELECT read_at FROM agent_org_runtime_inbox WHERE id=?1") + .prepare("SELECT read_at FROM agent_org_execution_inbox WHERE id=?1") .map_err(|err| err.to_string())?; let mut count = 0usize; for inbox_id in inbox_ids { @@ -339,7 +339,7 @@ fn materialize_agent_org_inbox_transcript_internal( { let mut stmt = tx .prepare( - "INSERT INTO agent_org_runtime_inbox_materializations + "INSERT INTO agent_org_execution_inbox_materializations (inbox_id, session_id, transcript_message_id, transcript_intent_id, materialized_at) VALUES (?1, ?2, ?3, ?4, ?5)", ) @@ -1672,6 +1672,7 @@ mod tests { fn seed_session_for_message_tests(session_id: &str) { let conn = get_connection().expect("get_connection in seed_session_for_message_tests"); crate::persistence::test_schema::ensure_agent_sessions_schema(&conn); + crate::persistence::test_schema::ensure_session_events_schema(&conn); conn.execute_batch( "CREATE TABLE IF NOT EXISTS agent_messages ( id TEXT PRIMARY KEY, @@ -1709,6 +1710,8 @@ mod tests { let run_id = "archive-assistant-run"; let turn_intent_id = "archive-assistant-turn"; seed_session_for_message_tests(session_id); + // Current sessions are created only after startup has completed cutover. + crate::coordination::init_agent_org_schemas(&get_connection().unwrap()).unwrap(); crate::session::persistence::upsert_session( &crate::session::persistence::UnifiedSessionRecord { session_id: session_id.to_string(), @@ -1758,7 +1761,7 @@ mod tests { }) .to_string(); conn.execute( - "INSERT INTO agent_org_runtime_runs ( + "INSERT INTO agent_org_execution_runs ( id,org_id,coordinator_agent_id,root_session_id,org_snapshot_json, entry_mode,status,activation_generation,created_at,updated_at ) VALUES (?1,'org-archive-assistant','builtin:sde',?2,?3, @@ -1767,7 +1770,7 @@ mod tests { ) .expect("seed Run"); conn.execute( - "INSERT INTO agent_org_runtime_member_materializations ( + "INSERT INTO agent_org_execution_member_materializations ( org_run_id,member_id,agent_id,generation,session_id, authority_class,status,created_at,updated_at ) VALUES (?1,'coordinator','builtin:sde',1,?2, @@ -1789,7 +1792,7 @@ mod tests { materialization.agent_id,materialization.session_id, materialization.status,session.agent_definition_id, session.org_member_id - FROM agent_org_runtime_member_materializations materialization + FROM agent_org_execution_member_materializations materialization JOIN agent_sessions session ON session.session_id=materialization.session_id WHERE materialization.org_run_id=?1 AND materialization.session_id=?2", @@ -1827,7 +1830,7 @@ mod tests { ) .expect("seed Turn intent"); conn.execute( - "INSERT INTO agent_org_runtime_turn_contexts ( + "INSERT INTO agent_org_execution_turn_contexts ( session_id,turn_intent_id,org_run_id,participant_id,turn_kind, source_kind,source_id,activation_generation,created_at ) VALUES (?1,?2,?3,'coordinator','coordinator','root_turn',?2,1,?4)", @@ -1887,6 +1890,7 @@ mod tests { seed_session_for_message_tests(root_session_id); seed_session_for_message_tests(member_session_id); + crate::coordination::init_agent_org_schemas(&get_connection().unwrap()).unwrap(); for (session_id, member_id) in [ (root_session_id, "coordinator"), (member_session_id, "worker"), @@ -1941,7 +1945,7 @@ mod tests { }) .to_string(); conn.execute( - "INSERT INTO agent_org_runtime_runs ( + "INSERT INTO agent_org_execution_runs ( id,org_id,coordinator_agent_id,root_session_id,org_snapshot_json, entry_mode,status,activation_generation,created_at,updated_at ) VALUES (?1,'org-completed-assistant','builtin:sde',?2,?3, @@ -1950,7 +1954,7 @@ mod tests { ) .expect("seed Run"); conn.execute( - "INSERT INTO agent_org_runtime_member_materializations ( + "INSERT INTO agent_org_execution_member_materializations ( org_run_id,member_id,agent_id,generation,session_id, authority_class,status,created_at,updated_at ) VALUES (?1,'worker','builtin:sde',1,?2, @@ -1959,7 +1963,7 @@ mod tests { ) .expect("seed Member materialization"); conn.execute( - "INSERT INTO agent_org_runtime_tasks ( + "INSERT INTO agent_org_execution_tasks ( id,org_run_id,activation_generation,subject,description,owner,status,execution_mode, blocked_by_json,created_by_participant_id,source_turn_intent_id, created_at,updated_at @@ -1977,7 +1981,7 @@ mod tests { ) .expect("seed running Turn intent"); conn.execute( - "INSERT INTO agent_org_runtime_turn_contexts ( + "INSERT INTO agent_org_execution_turn_contexts ( session_id,turn_intent_id,org_run_id,participant_id,turn_kind,task_id, owner_member_id,dispatch_member_id,member_dispatch_sequence, source_kind,source_id,activation_generation,created_at @@ -2034,7 +2038,7 @@ mod tests { ) .expect("seed historical sibling base Turn"); conn.execute( - "INSERT INTO agent_org_runtime_turn_contexts ( + "INSERT INTO agent_org_execution_turn_contexts ( session_id,turn_intent_id,org_run_id,participant_id,turn_kind,task_id, owner_member_id,dispatch_member_id,member_dispatch_sequence, source_kind,source_id,activation_generation,created_at @@ -2077,7 +2081,7 @@ mod tests { .query_row( "SELECT previous_status,next_status,actor_kind,actor_member_id, source_turn_intent_id - FROM agent_org_runtime_task_events + FROM agent_org_execution_task_events WHERE org_run_id=?1 AND task_id=?2 ORDER BY rowid DESC LIMIT 1", params![run_id, task_id], diff --git a/src-tauri/crates/agent-core/src/core/session/persistence/sidebar.rs b/src-tauri/crates/agent-core/src/core/session/persistence/sidebar.rs index b2bee552b2..aafa84987a 100644 --- a/src-tauri/crates/agent-core/src/core/session/persistence/sidebar.rs +++ b/src-tauri/crates/agent-core/src/core/session/persistence/sidebar.rs @@ -55,21 +55,12 @@ fn list_agent_sessions_page( ) -> Result, String> { let conn = get_connection().map_err(|err| err.to_string())?; let root_predicate = match agent_org_root { - Some(true) => { - "AND EXISTS ( - SELECT 1 - FROM agent_org_runtime_runs r - WHERE r.root_session_id = s.session_id - )" - } - Some(false) => { - "AND s.org_member_id IS NULL - AND NOT EXISTS ( - SELECT 1 - FROM agent_org_runtime_runs r - WHERE r.root_session_id = s.session_id - )" - } + Some(true) => "AND (EXISTS (SELECT 1 FROM agent_org_execution_runs r + WHERE r.root_session_id=s.session_id) OR EXISTS (SELECT 1 FROM org_history_sessions h + WHERE h.session_id=s.session_id AND (h.root_session_id=s.session_id OR h.root_session_id IS NULL)))", + Some(false) => "AND s.org_member_id IS NULL AND NOT EXISTS + (SELECT 1 FROM agent_org_execution_runs r WHERE r.root_session_id=s.session_id) + AND NOT EXISTS (SELECT 1 FROM org_history_sessions h WHERE h.session_id=s.session_id)", None => "", }; let bounded_limit = limit.min(i64::MAX as usize) as i64; @@ -78,7 +69,8 @@ fn list_agent_sessions_page( let sql = format!( "{UNIFIED_SESSION_SELECT} WHERE s.session_type = ?1 - AND s.status != ?2 + AND (s.status != ?2 OR EXISTS (SELECT 1 FROM org_history_sessions h WHERE h.session_id=s.session_id)) + AND NOT EXISTS (SELECT 1 FROM org_history_copies c WHERE c.copy_session_id=s.session_id) AND s.pinned = 0 AND s.parent_session_id IS NULL {root_predicate} @@ -110,7 +102,8 @@ fn list_agent_sessions_page( let sql = format!( "{UNIFIED_SESSION_SELECT} WHERE s.session_type = ?1 - AND s.status != ?2 + AND (s.status != ?2 OR EXISTS (SELECT 1 FROM org_history_sessions h WHERE h.session_id=s.session_id)) + AND NOT EXISTS (SELECT 1 FROM org_history_copies c WHERE c.copy_session_id=s.session_id) AND s.pinned = 0 AND s.parent_session_id IS NULL {root_predicate} @@ -206,7 +199,7 @@ mod tests { ensure_runtime_schemas(); let conn = database::db::get_connection().expect("test sqlite connection"); conn.execute( - "INSERT INTO agent_org_runtime_runs ( + "INSERT INTO agent_org_execution_runs ( id, org_id, coordinator_agent_id, @@ -404,7 +397,7 @@ mod tests { AND s.org_member_id IS NULL AND NOT EXISTS ( SELECT 1 - FROM agent_org_runtime_runs r + FROM agent_org_execution_runs r WHERE r.root_session_id = s.session_id ) ORDER BY s.updated_at DESC, s.session_id DESC @@ -423,8 +416,12 @@ mod tests { "session page did not use ordered pin/type index:\n{details}" ); assert!( - details.contains("idx_agent_org_runtime_runs_root_session"), + details.contains("idx_agent_org_execution_runs_root_session"), "root membership probe did not use root-session index:\n{details}" ); } } + +#[cfg(test)] +#[path = "sidebar_history_tests.rs"] +mod history_tests; diff --git a/src-tauri/crates/agent-core/src/core/session/persistence/sidebar_history_tests.rs b/src-tauri/crates/agent-core/src/core/session/persistence/sidebar_history_tests.rs new file mode 100644 index 0000000000..66c11bb0ae --- /dev/null +++ b/src-tauri/crates/agent-core/src/core/session/persistence/sidebar_history_tests.rs @@ -0,0 +1,34 @@ +use super::*; + +#[test] +fn retired_archived_roots_remain_discoverable_and_copies_do_not_consume_page_slots() { + let _sandbox = test_helpers::test_env::sandbox(); + let conn = get_connection().unwrap(); + crate::persistence::test_schema::ensure_agent_sessions_schema(&conn); + crate::coordination::init_agent_org_schemas(&conn).unwrap(); + conn.execute_batch( + "INSERT INTO agent_sessions + (session_id,name,status,session_type,created_at,updated_at,org_member_id) + VALUES ('old-root','Old team','archived','sde','now','now','coordinator'), + ('copy','Ordinary old-reader copy','idle','sde','now','now',NULL), + ('ordinary','Ordinary session','idle','sde','now','now',NULL); + INSERT INTO org_history_sessions(session_id,root_session_id,source_table) + VALUES ('old-root','old-root','fixture'); + INSERT INTO org_history_copies VALUES ('old-root','copy');", + ) + .unwrap(); + let roots = list_agent_org_root_sessions_page(1, None).unwrap(); + assert_eq!(roots.len(), 1); + assert_eq!(roots[0].session_id, "old-root"); + let ordinary = list_standalone_coding_sessions_page(1, None).unwrap(); + assert_eq!(ordinary.len(), 1); + assert_eq!(ordinary[0].session_id, "ordinary"); + assert_eq!( + conn.query_row("SELECT COUNT(*) FROM agent_org_execution_runs", [], |r| r + .get::<_, i64>( + 0 + )) + .unwrap(), + 0 + ); +} diff --git a/src-tauri/crates/agent-core/src/core/session/turn/event_handler/final_summary_event_tests.rs b/src-tauri/crates/agent-core/src/core/session/turn/event_handler/final_summary_event_tests.rs index 4e1208110b..2013db239d 100644 --- a/src-tauri/crates/agent-core/src/core/session/turn/event_handler/final_summary_event_tests.rs +++ b/src-tauri/crates/agent-core/src/core/session/turn/event_handler/final_summary_event_tests.rs @@ -7,7 +7,7 @@ fn streamed_final_summary_uses_stable_identity_and_certificate_authority() { crate::coordination::init_agent_org_schemas(&conn).expect("Agent Org schema"); let now = chrono::Utc::now().to_rfc3339(); conn.execute( - "INSERT INTO agent_org_runtime_runs( + "INSERT INTO agent_org_execution_runs( id,org_id,coordinator_agent_id,root_session_id,entry_mode,status, activation_generation,has_initial_work,created_at,updated_at ) VALUES ('run','org','coordinator','coordinator-session', @@ -16,7 +16,7 @@ fn streamed_final_summary_uses_stable_identity_and_certificate_authority() { ) .expect("seed run"); conn.execute( - "INSERT INTO agent_org_runtime_run_completion_certificates( + "INSERT INTO agent_org_execution_run_completion_certificates( id,org_run_id,activation_generation,work_revision,request_id,request_digest, outcome,summary,coordinator_session_id,coordinator_turn_intent_id, evidence_task_ids_json,closure_task_ids_json,task_output_refs_json, @@ -27,7 +27,7 @@ fn streamed_final_summary_uses_stable_identity_and_certificate_authority() { ) .expect("seed certificate"); conn.execute( - "INSERT INTO agent_org_runtime_final_summary_receipts( + "INSERT INTO agent_org_execution_final_summary_receipts( receipt_id,org_run_id,activation_generation,certificate_id, evidence_digest,attempt,status,coordinator_session_id, turn_intent_id,started_at,created_at,updated_at @@ -71,7 +71,7 @@ fn streamed_final_summary_uses_stable_identity_and_certificate_authority() { ); conn.execute( - "UPDATE agent_org_runtime_final_summary_receipts + "UPDATE agent_org_execution_final_summary_receipts SET status='failed',typed_error='stopped',terminal_at=?2,updated_at=?2 WHERE receipt_id=?1", rusqlite::params!["summary-receipt", chrono::Utc::now().to_rfc3339()], diff --git a/src-tauri/crates/agent-core/src/core/session/turn/event_handler/initial_reply_event_tests.rs b/src-tauri/crates/agent-core/src/core/session/turn/event_handler/initial_reply_event_tests.rs index 555003890d..c2c58a4349 100644 --- a/src-tauri/crates/agent-core/src/core/session/turn/event_handler/initial_reply_event_tests.rs +++ b/src-tauri/crates/agent-core/src/core/session/turn/event_handler/initial_reply_event_tests.rs @@ -7,7 +7,7 @@ fn only_the_exact_initial_root_turn_gets_a_public_reply_marker() { crate::coordination::init_agent_org_schemas(&conn).expect("Agent Org schema"); let now = chrono::Utc::now().to_rfc3339(); conn.execute( - "INSERT INTO agent_org_runtime_runs( + "INSERT INTO agent_org_execution_runs( id,org_id,coordinator_agent_id,root_session_id,entry_mode,status, activation_generation,has_initial_work,created_at,updated_at ) VALUES ('run','org','coordinator','coordinator-session', @@ -16,7 +16,7 @@ fn only_the_exact_initial_root_turn_gets_a_public_reply_marker() { ) .expect("seed run"); conn.execute( - "INSERT INTO agent_org_runtime_initial_inputs( + "INSERT INTO agent_org_execution_initial_inputs( org_run_id,turn_intent_id,message_id,content,payload_json,status, created_at,updated_at ) VALUES ('run','initial-turn','initial-message','Build it','{}', diff --git a/src-tauri/crates/agent-core/src/core/session/turn/processor/inbox_drain/tests.rs b/src-tauri/crates/agent-core/src/core/session/turn/processor/inbox_drain/tests.rs index 7215632a61..04de4de200 100644 --- a/src-tauri/crates/agent-core/src/core/session/turn/processor/inbox_drain/tests.rs +++ b/src-tauri/crates/agent-core/src/core/session/turn/processor/inbox_drain/tests.rs @@ -1110,7 +1110,7 @@ fn materialized_batch_replay_delivers_only_rows_that_arrived_later() { let receipt_count: i64 = database::db::get_connection() .expect("receipt connection") .query_row( - "SELECT COUNT(*) FROM agent_org_runtime_inbox_materializations", + "SELECT COUNT(*) FROM agent_org_execution_inbox_materializations", [], |row| row.get(0), ) @@ -1289,7 +1289,7 @@ fn shutdown_notification_failure_leaves_source_unread_and_retries_before_deliver let conn = database::db::get_connection().expect("db"); conn.execute_batch( "CREATE TRIGGER fail_member_terminated - BEFORE INSERT ON agent_org_runtime_inbox + BEFORE INSERT ON agent_org_execution_inbox WHEN NEW.payload_kind='member_terminated' BEGIN SELECT RAISE(ABORT, 'forced member termination insert failure'); diff --git a/src-tauri/crates/agent-core/src/core/tools/impls/orchestration/agent_org/completion_wait_tests.rs b/src-tauri/crates/agent-core/src/core/tools/impls/orchestration/agent_org/completion_wait_tests.rs index 4e5f3ee6d8..81f6a886c6 100644 --- a/src-tauri/crates/agent-core/src/core/tools/impls/orchestration/agent_org/completion_wait_tests.rs +++ b/src-tauri/crates/agent-core/src/core/tools/impls/orchestration/agent_org/completion_wait_tests.rs @@ -78,13 +78,13 @@ fn count(table: &str) -> i64 { .unwrap() } fn certificates() -> i64 { - count("agent_org_runtime_run_completion_certificates") + count("agent_org_execution_run_completion_certificates") } fn resolutions() -> i64 { - database::db::get_connection().unwrap().query_row("SELECT COUNT(*) FROM agent_org_runtime_inbox_delivery_resolutions WHERE resolution_kind='system_reconciled'",[],|r|r.get(0)).unwrap() + database::db::get_connection().unwrap().query_row("SELECT COUNT(*) FROM agent_org_execution_inbox_delivery_resolutions WHERE resolution_kind='system_reconciled'",[],|r|r.get(0)).unwrap() } fn candidate() -> Option { - database::db::get_connection().unwrap().query_row("SELECT completion_candidate_json FROM agent_org_runtime_run_progress WHERE org_run_id=?1",[RUN_ID],|r|r.get(0)).unwrap() + database::db::get_connection().unwrap().query_row("SELECT completion_candidate_json FROM agent_org_execution_run_progress WHERE org_run_id=?1",[RUN_ID],|r|r.get(0)).unwrap() } fn idle( reason: MemberIdleReason, @@ -125,7 +125,7 @@ async fn final_member_exit_after_resume_rings_the_completion_doorbell_for_origin let task_id = completed_task().await; let conn = database::db::get_connection().unwrap(); conn.execute( - "UPDATE agent_org_runtime_runs SET activation_generation=3 WHERE id=?1", + "UPDATE agent_org_execution_runs SET activation_generation=3 WHERE id=?1", [RUN_ID], ) .unwrap(); @@ -140,7 +140,7 @@ async fn final_member_exit_after_resume_rings_the_completion_doorbell_for_origin ) = conn .query_row( "SELECT receipt_id,task_id,source_turn_intent_id,status,doorbell_status - FROM agent_org_runtime_formal_trigger_receipts + FROM agent_org_execution_formal_trigger_receipts WHERE inbox_id=?1", [inbox_id], |row| { @@ -192,13 +192,13 @@ async fn completion_waits_for_exact_success_and_settles_only_redundant_rows() { assert!(candidate().is_none()); let conn = database::db::get_connection().unwrap(); let (read_at,kind,reason):(Option,String,String)=conn.query_row( - "SELECT inbox.read_at,resolution.resolution_kind,resolution.reason FROM agent_org_runtime_inbox inbox JOIN agent_org_runtime_inbox_delivery_resolutions resolution ON resolution.inbox_id=inbox.id WHERE inbox.id=?1", + "SELECT inbox.read_at,resolution.resolution_kind,resolution.reason FROM agent_org_execution_inbox inbox JOIN agent_org_execution_inbox_delivery_resolutions resolution ON resolution.inbox_id=inbox.id WHERE inbox.id=?1", [idle_id],|r|Ok((r.get(0)?,r.get(1)?,r.get(2)?))).unwrap(); assert!(read_at.is_none()); assert_eq!(kind, "system_reconciled"); assert!(reason.contains(OWNER_TURN)); assert!(reason.contains(COORDINATOR_TURN)); - let output_evidence:String=conn.query_row("SELECT resolution.reason FROM agent_org_runtime_inbox_delivery_resolutions resolution JOIN agent_org_runtime_inbox inbox ON inbox.id=resolution.inbox_id WHERE inbox.payload_kind='task_completed' AND resolution.resolution_kind='system_reconciled'",[],|r|r.get(0)).unwrap(); + let output_evidence:String=conn.query_row("SELECT resolution.reason FROM agent_org_execution_inbox_delivery_resolutions resolution JOIN agent_org_execution_inbox inbox ON inbox.id=resolution.inbox_id WHERE inbox.payload_kind='task_completed' AND resolution.resolution_kind='system_reconciled'",[],|r|r.get(0)).unwrap(); let evidence: Value = serde_json::from_str(&output_evidence).unwrap(); assert_eq!( evidence["evidence"]["presentation"]["turnIntentId"], @@ -214,13 +214,13 @@ async fn completion_waits_for_exact_success_and_settles_only_redundant_rows() { AgentInboxStore::mark_many_read_for_session(&[idle_id], ROOT_SESSION).unwrap(), 0 ); - let pending:i64=conn.query_row("SELECT COUNT(*) FROM agent_org_runtime_formal_trigger_receipts WHERE trigger_kind<>'final_summary' AND status<>'resolved'",[],|r|r.get(0)).unwrap(); + let pending:i64=conn.query_row("SELECT COUNT(*) FROM agent_org_execution_formal_trigger_receipts WHERE trigger_kind<>'final_summary' AND status<>'resolved'",[],|r|r.get(0)).unwrap(); assert_eq!(pending, 0); for _ in 0..3 { assert!(!completion::recheck_pending(RUN_ID).unwrap()); } assert_eq!(certificates(), 1); - assert_eq!(count("agent_org_runtime_final_summary_receipts"), 1); + assert_eq!(count("agent_org_execution_final_summary_receipts"), 1); } #[tokio::test] @@ -264,7 +264,7 @@ async fn dense_redundant_notifications_do_not_require_a_model_turn() { assert_eq!(certificates(), 1); let conn = database::db::get_connection().unwrap(); for id in ids { - let disposed: bool = conn.query_row("SELECT EXISTS(SELECT 1 FROM agent_org_runtime_inbox_delivery_resolutions WHERE inbox_id=?1 AND resolution_kind='system_reconciled')", [id], |r| r.get(0)).unwrap(); + let disposed: bool = conn.query_row("SELECT EXISTS(SELECT 1 FROM agent_org_execution_inbox_delivery_resolutions WHERE inbox_id=?1 AND resolution_kind='system_reconciled')", [id], |r| r.get(0)).unwrap(); assert!(disposed); } } @@ -399,7 +399,7 @@ async fn disposition_and_certificate_rollback_together_on_storage_failure() { ) .unwrap(); let conn = database::db::get_connection().unwrap(); - conn.execute_batch("CREATE TRIGGER reject_completion BEFORE INSERT ON agent_org_runtime_run_completion_certificates BEGIN SELECT RAISE(ABORT,'injected completion storage failure'); END;").unwrap(); + conn.execute_batch("CREATE TRIGGER reject_completion BEFORE INSERT ON agent_org_execution_run_completion_certificates BEGIN SELECT RAISE(ABORT,'injected completion storage failure'); END;").unwrap(); // Session and formal-turn finality have different persistence boundaries; // the post-status recheck is where this fixture becomes quiescent. assert!( @@ -450,7 +450,7 @@ async fn pause_generation_change_and_new_root_invalidate_candidate() { .unwrap(); } "generation" => { - conn.execute("UPDATE agent_org_runtime_runs SET activation_generation=activation_generation+1 WHERE id=?1",[RUN_ID]).unwrap(); + conn.execute("UPDATE agent_org_execution_runs SET activation_generation=activation_generation+1 WHERE id=?1",[RUN_ID]).unwrap(); } "root" => insert_coordinator_context_for_turn(&conn, "new-root"), _ => { @@ -510,10 +510,10 @@ async fn late_redundant_idle_is_disposed_but_new_message_keeps_its_wake() { .unwrap(); assert!(!completion::completion_handles_wake(RUN_ID).unwrap()); let conn = database::db::get_connection().unwrap(); - let (kind,read):(String,Option)=conn.query_row("SELECT resolution.resolution_kind,inbox.read_at FROM agent_org_runtime_inbox inbox JOIN agent_org_runtime_inbox_delivery_resolutions resolution ON resolution.inbox_id=inbox.id WHERE inbox.id=?1",[late_id],|r|Ok((r.get(0)?,r.get(1)?))).unwrap(); + let (kind,read):(String,Option)=conn.query_row("SELECT resolution.resolution_kind,inbox.read_at FROM agent_org_execution_inbox inbox JOIN agent_org_execution_inbox_delivery_resolutions resolution ON resolution.inbox_id=inbox.id WHERE inbox.id=?1",[late_id],|r|Ok((r.get(0)?,r.get(1)?))).unwrap(); assert_eq!(kind, "system_reconciled"); assert!(read.is_none()); - let pending:bool=conn.query_row("SELECT EXISTS(SELECT 1 FROM agent_org_runtime_formal_trigger_receipts WHERE inbox_id=?1 AND status='pending')",[substantive.id],|r|r.get(0)).unwrap(); + let pending:bool=conn.query_row("SELECT EXISTS(SELECT 1 FROM agent_org_execution_formal_trigger_receipts WHERE inbox_id=?1 AND status='pending')",[substantive.id],|r|r.get(0)).unwrap(); assert!(pending); assert!( AgentInboxStore::list_unread_for_member(COORDINATOR_MEMBER_ID, RUN_ID) @@ -538,7 +538,7 @@ async fn old_idle_and_new_output_version_are_not_reconciled() { } else { // Inject an inconsistent producer version without a revision bump; // even corrupted storage must not reuse the old output proof. - conn.execute("UPDATE agent_org_runtime_tasks SET output_json=json_set(output_json,'$.content','New result and limits') WHERE id=?1",[&id]).unwrap(); + conn.execute("UPDATE agent_org_execution_tasks SET output_json=json_set(output_json,'$.content','New result and limits') WHERE id=?1",[&id]).unwrap(); } assert!(!completion::recheck_pending(RUN_ID).unwrap()); assert!(candidate().is_none()); diff --git a/src-tauri/crates/agent-core/src/core/tools/impls/orchestration/agent_org/inbox_repair.rs b/src-tauri/crates/agent-core/src/core/tools/impls/orchestration/agent_org/inbox_repair.rs index 791643c886..f5770fadd0 100644 --- a/src-tauri/crates/agent-core/src/core/tools/impls/orchestration/agent_org/inbox_repair.rs +++ b/src-tauri/crates/agent-core/src/core/tools/impls/orchestration/agent_org/inbox_repair.rs @@ -410,7 +410,7 @@ mod tests { }) .expect("seed coordinator session"); conn.execute( - "INSERT INTO agent_org_runtime_member_materializations ( + "INSERT INTO agent_org_execution_member_materializations ( org_run_id,member_id,agent_id,generation,session_id, authority_class,status,created_at,updated_at ) VALUES (?1,'coordinator','coordinator-agent',?2, @@ -430,7 +430,7 @@ mod tests { ) .expect("seed base Turn"); conn.execute( - "INSERT INTO agent_org_runtime_turn_contexts ( + "INSERT INTO agent_org_execution_turn_contexts ( session_id,turn_intent_id,org_run_id,participant_id,turn_kind, source_kind,source_id,activation_generation,created_at ) VALUES ('root-inbox-repair','repair-turn',?1,'coordinator','coordinator', @@ -448,7 +448,7 @@ mod tests { text: "Preserve this original message".into(), }; conn.execute( - "INSERT INTO agent_org_runtime_inbox ( + "INSERT INTO agent_org_execution_inbox ( recipient_agent_id, recipient_member_id, sender_agent_id, sender_member_id, org_run_id, payload_kind, payload_json, created_at @@ -521,13 +521,13 @@ mod tests { let conn = get_connection().expect("test sqlite connection"); let generation: i64 = conn .query_row( - "SELECT activation_generation FROM agent_org_runtime_runs WHERE id=?1", + "SELECT activation_generation FROM agent_org_execution_runs WHERE id=?1", [&fixture.run_id], |row| row.get(0), ) .expect("load run generation"); conn.execute( - "INSERT INTO agent_org_runtime_member_materializations ( + "INSERT INTO agent_org_execution_member_materializations ( org_run_id,member_id,agent_id,generation,session_id, authority_class,status,created_at,updated_at ) VALUES (?1,'worker','worker-agent',?2,'repair-worker-session', @@ -712,7 +712,7 @@ mod tests { let fixture = fixture(); let conn = get_connection().expect("test sqlite connection"); conn.execute( - "UPDATE agent_org_runtime_runs + "UPDATE agent_org_execution_runs SET status='archived',activation_generation=activation_generation+1, archived_at=?2,archive_receipt_id=?3 WHERE id=?1", diff --git a/src-tauri/crates/agent-core/src/core/tools/impls/orchestration/agent_org/next_work_tests.rs b/src-tauri/crates/agent-core/src/core/tools/impls/orchestration/agent_org/next_work_tests.rs index d200c904fd..04de59701b 100644 --- a/src-tauri/crates/agent-core/src/core/tools/impls/orchestration/agent_org/next_work_tests.rs +++ b/src-tauri/crates/agent-core/src/core/tools/impls/orchestration/agent_org/next_work_tests.rs @@ -61,12 +61,7 @@ fn dispatch(turn: &str) { } async fn report() -> summary::FinalSummaryReceipt { - let receipt = start_report().await; - database::db::get_connection() - .unwrap() - .execute_batch("ALTER TABLE events ADD COLUMN function_name TEXT;") - .unwrap(); - receipt + start_report().await } fn publish(receipt: &summary::FinalSummaryReceipt, failed: bool) { @@ -166,7 +161,7 @@ async fn publication_follow_up_activates_both_writers_and_keeps_later_user_autho ); assert_eq!( conn.query_row( - "SELECT COUNT(*) FROM agent_org_runtime_run_completion_certificates", + "SELECT COUNT(*) FROM agent_org_execution_run_completion_certificates", [], |r| r.get::<_, i64>(0) ) @@ -186,7 +181,7 @@ async fn publication_follow_up_rolls_back_generation_and_queued_authority_on_wri dispatch("new-request"); let conn = database::db::get_connection().unwrap(); conn.execute_batch( - "CREATE TRIGGER fail_new_task BEFORE INSERT ON agent_org_runtime_tasks + "CREATE TRIGGER fail_new_task BEFORE INSERT ON agent_org_execution_tasks BEGIN SELECT RAISE(ABORT,'disk I/O error: injected new task'); END;", ) .unwrap(); @@ -233,7 +228,7 @@ async fn publication_follow_up_never_promotes_unfinished_or_invalid_authority() let conn = database::db::get_connection().unwrap(); assert_eq!( conn.query_row( - "SELECT COUNT(*) FROM agent_org_runtime_turn_contexts + "SELECT COUNT(*) FROM agent_org_execution_turn_contexts WHERE turn_intent_id='new-request'", [], |row| row.get::<_, i64>(0) @@ -263,7 +258,7 @@ async fn publication_follow_up_never_promotes_unfinished_or_invalid_authority() } "paused" => { conn.execute( - "UPDATE agent_org_runtime_runs SET status='paused' WHERE id=?1", + "UPDATE agent_org_execution_runs SET status='paused' WHERE id=?1", [RUN_ID], ) .unwrap(); @@ -279,11 +274,11 @@ async fn publication_follow_up_never_promotes_unfinished_or_invalid_authority() .unwrap(); } "stale" => { - conn.execute("UPDATE agent_org_runtime_turn_contexts SET activation_generation=2 WHERE turn_intent_id='new-request'", []).unwrap(); + conn.execute("UPDATE agent_org_execution_turn_contexts SET activation_generation=2 WHERE turn_intent_id='new-request'", []).unwrap(); } "other-turn" => insert_coordinator_context_for_turn(&conn, "unsettled-old-wake"), "database" => { - conn.execute_batch("DROP TABLE agent_org_runtime_run_progress") + conn.execute_batch("DROP TABLE agent_org_execution_run_progress") .unwrap(); } _ => unreachable!(), diff --git a/src-tauri/crates/agent-core/src/core/tools/impls/orchestration/agent_org/rework_tests.rs b/src-tauri/crates/agent-core/src/core/tools/impls/orchestration/agent_org/rework_tests.rs index 2d016fb3a9..21b0accc00 100644 --- a/src-tauri/crates/agent-core/src/core/tools/impls/orchestration/agent_org/rework_tests.rs +++ b/src-tauri/crates/agent-core/src/core/tools/impls/orchestration/agent_org/rework_tests.rs @@ -150,7 +150,7 @@ async fn replacement_requires_explicit_consumer_patch_and_preserves_other_depend .any(|id| id == consumer_id)); let assignments: i64 = conn .query_row( - "SELECT COUNT(*) FROM agent_org_runtime_inbox WHERE org_run_id=?1 + "SELECT COUNT(*) FROM agent_org_execution_inbox WHERE org_run_id=?1 AND payload_kind='task_assigned' AND json_extract(payload_json,'$.task_id')=?2", rusqlite::params![RUN_ID, consumer_id], |row| row.get(0), diff --git a/src-tauri/crates/agent-core/src/core/tools/impls/orchestration/agent_org/send_message/persistence.rs b/src-tauri/crates/agent-core/src/core/tools/impls/orchestration/agent_org/send_message/persistence.rs index 88f7e01f18..2f0f4b6ccd 100644 --- a/src-tauri/crates/agent-core/src/core/tools/impls/orchestration/agent_org/send_message/persistence.rs +++ b/src-tauri/crates/agent-core/src/core/tools/impls/orchestration/agent_org/send_message/persistence.rs @@ -88,7 +88,7 @@ pub(super) fn user_directed_link_allowed_in_tx( } let snapshot_json: Option = conn .query_row( - "SELECT org_snapshot_json FROM agent_org_runtime_runs WHERE id=?1", + "SELECT org_snapshot_json FROM agent_org_execution_runs WHERE id=?1", [run_id], |row| row.get(0), ) @@ -154,7 +154,7 @@ pub(super) fn persist_user_directed_member_message_in_tx( } let status: Option = conn .query_row( - "SELECT status FROM agent_org_runtime_runs WHERE id=?1", + "SELECT status FROM agent_org_execution_runs WHERE id=?1", [run_id], |row| row.get(0), ) @@ -221,7 +221,7 @@ pub(super) fn persist_user_directed_member_message_in_tx( format!("{summary}\n\n{content}") }; conn.execute( - "UPDATE agent_org_runtime_inbox + "UPDATE agent_org_execution_inbox SET delivery_class='user_directed',display_text=?2 WHERE id=?1 AND delivery_class='formal_work'", params![record.id, &display_text], @@ -286,7 +286,7 @@ pub(super) fn persist_user_directed_coordinator_message_in_tx( } let status: Option = conn .query_row( - "SELECT status FROM agent_org_runtime_runs WHERE id=?1", + "SELECT status FROM agent_org_execution_runs WHERE id=?1", [run_id], |row| row.get(0), ) @@ -348,7 +348,7 @@ pub(super) fn persist_user_directed_coordinator_message_in_tx( format!("{summary}\n\n{content}") }; conn.execute( - "UPDATE agent_org_runtime_inbox + "UPDATE agent_org_execution_inbox SET delivery_class='user_directed',display_text=?2 WHERE id=?1 AND delivery_class='formal_work'", params![record.id, &display_text], @@ -462,7 +462,7 @@ fn member_coordination_guidance( let exact_task_is_active: bool = conn .query_row( "SELECT EXISTS( - SELECT 1 FROM agent_org_runtime_tasks + SELECT 1 FROM agent_org_execution_tasks WHERE org_run_id=?1 AND id=?2 AND owner=?3 AND status='in_progress' )", @@ -553,7 +553,7 @@ pub(super) fn persist_ordinary_message_in_tx( ) -> Result { let run_status: Option = conn .query_row( - "SELECT status FROM agent_org_runtime_runs WHERE id=?1", + "SELECT status FROM agent_org_execution_runs WHERE id=?1", params![run_id], |row| row.get(0), ) @@ -588,7 +588,7 @@ pub(super) fn persist_ordinary_message_in_tx( { let open_task_count = conn .query_row( - "SELECT COUNT(*) FROM agent_org_runtime_tasks + "SELECT COUNT(*) FROM agent_org_execution_tasks WHERE org_run_id=?1 AND owner=?2 AND status IN ('pending','in_progress')", params![run_id, &recipient.member_id], diff --git a/src-tauri/crates/agent-core/src/core/tools/impls/orchestration/agent_org/send_message/tests.rs b/src-tauri/crates/agent-core/src/core/tools/impls/orchestration/agent_org/send_message/tests.rs index a1b12c5180..235ae8dfb9 100644 --- a/src-tauri/crates/agent-core/src/core/tools/impls/orchestration/agent_org/send_message/tests.rs +++ b/src-tauri/crates/agent-core/src/core/tools/impls/orchestration/agent_org/send_message/tests.rs @@ -121,7 +121,7 @@ fn params(recipient_member_id: &str) -> serde_json::Value { fn grant_member_writer_in_frozen_snapshot(conn: &rusqlite::Connection, member_id: &str) { let mut snapshot: crate::definitions::orgs::AgentOrgLaunchSnapshot = conn .query_row( - "SELECT org_snapshot_json FROM agent_org_runtime_runs WHERE id='run-1'", + "SELECT org_snapshot_json FROM agent_org_execution_runs WHERE id='run-1'", [], |row| row.get::<_, String>(0), ) @@ -133,7 +133,7 @@ fn grant_member_writer_in_frozen_snapshot(conn: &rusqlite::Connection, member_id snapshot.additional_task_graph_writer_member_ids.sort(); snapshot.additional_task_graph_writer_member_ids.dedup(); conn.execute( - "UPDATE agent_org_runtime_runs SET org_snapshot_json=?1 WHERE id='run-1'", + "UPDATE agent_org_execution_runs SET org_snapshot_json=?1 WHERE id='run-1'", [serde_json::to_string(&snapshot).expect("encode frozen snapshot")], ) .expect("persist frozen writer capability"); @@ -265,7 +265,7 @@ fn init_inbox_schema() -> test_helpers::test_env::SandboxGuard { }; let now = chrono::Utc::now().to_rfc3339(); conn.execute( - "INSERT INTO agent_org_runtime_runs ( + "INSERT INTO agent_org_execution_runs ( id,org_id,coordinator_agent_id,root_session_id,org_snapshot_json, entry_mode,status,activation_generation,created_at,updated_at ) VALUES ('run-1','org-1','agent-coord','root-1',?1, @@ -309,7 +309,7 @@ fn init_inbox_schema() -> test_helpers::test_env::SandboxGuard { }) .expect("seed builder authority Task"); conn.execute_batch(&format!( - "INSERT INTO agent_org_runtime_member_materializations ( + "INSERT INTO agent_org_execution_member_materializations ( org_run_id,member_id,agent_id,generation,session_id, authority_class,status,created_at,updated_at ) VALUES @@ -323,7 +323,7 @@ fn init_inbox_schema() -> test_helpers::test_env::SandboxGuard { ) VALUES ('root-1','coordinator-turn','run-1','agent_org','running','{now}','{now}'), ('builder-session','builder-turn','run-1','agent_org','running','{now}','{now}'); - INSERT INTO agent_org_runtime_turn_contexts ( + INSERT INTO agent_org_execution_turn_contexts ( session_id,turn_intent_id,org_run_id,participant_id,turn_kind, task_id,owner_member_id,dispatch_member_id,member_dispatch_sequence, source_kind,source_id,root_authority_turn_id,actor_version, @@ -374,7 +374,7 @@ fn seed_started_group_udw_with_link() -> crate::tools::call_context::CallContext let conn = database::db::get_connection().expect("test sqlite connection"); let mut snapshot: crate::definitions::orgs::AgentOrgLaunchSnapshot = conn .query_row( - "SELECT org_snapshot_json FROM agent_org_runtime_runs WHERE id='run-1'", + "SELECT org_snapshot_json FROM agent_org_execution_runs WHERE id='run-1'", [], |row| row.get::<_, String>(0), ) @@ -383,7 +383,7 @@ fn seed_started_group_udw_with_link() -> crate::tools::call_context::CallContext snapshot.member_communication_links = vec![crate::definitions::orgs::MemberCommunicationLink::canonical("builder", "planner")]; conn.execute( - "UPDATE agent_org_runtime_runs SET org_snapshot_json=?1 WHERE id='run-1'", + "UPDATE agent_org_execution_runs SET org_snapshot_json=?1 WHERE id='run-1'", [serde_json::to_string(&snapshot).expect("encode launch snapshot")], ) .expect("install frozen communication link"); @@ -410,7 +410,7 @@ fn seed_started_group_udw_with_link() -> crate::tools::call_context::CallContext ) .expect("seed linked Planner session"); conn.execute( - "INSERT INTO agent_org_runtime_member_materializations ( + "INSERT INTO agent_org_execution_member_materializations ( org_run_id,member_id,agent_id,generation,session_id, authority_class,status,created_at,updated_at ) VALUES ('run-1','planner','agent-shared',1,'planner-session', @@ -434,7 +434,7 @@ fn seed_started_group_udw_with_link() -> crate::tools::call_context::CallContext ) .expect("seed Group source Inbox"); conn.execute( - "UPDATE agent_org_runtime_inbox + "UPDATE agent_org_execution_inbox SET delivery_class='user_directed',display_text='@Builder Check the boundary' WHERE id=?1", [source.id], @@ -448,7 +448,7 @@ fn seed_started_group_udw_with_link() -> crate::tools::call_context::CallContext ) .expect("seed UDW intent"); conn.execute( - "INSERT INTO agent_org_runtime_turn_contexts ( + "INSERT INTO agent_org_execution_turn_contexts ( session_id,turn_intent_id,org_run_id,participant_id,turn_kind, dispatch_member_id,member_dispatch_sequence,source_kind,source_id, root_authority_turn_id,actor_version,created_at @@ -505,7 +505,7 @@ fn seed_started_group_udw_with_link() -> crate::tools::call_context::CallContext fn builder_authority_task_id() -> String { let conn = database::db::get_connection().expect("test sqlite connection"); conn.query_row( - "SELECT task_id FROM agent_org_runtime_turn_contexts + "SELECT task_id FROM agent_org_execution_turn_contexts WHERE session_id='builder-session' AND turn_intent_id='builder-turn'", [], |row| row.get(0), @@ -762,7 +762,7 @@ async fn started_udw_can_send_exactly_once_to_a_snapshot_linked_peer() { let (child_count, child_parent, child_source, child_depth): (i64, i64, i64, i64) = conn .query_row( "SELECT COUNT(*),MIN(parent_delivery_id),MIN(source_inbox_id),MIN(depth) - FROM agent_org_runtime_user_directed_deliveries + FROM agent_org_execution_user_directed_deliveries WHERE source_kind='member_inbox' AND dispatch_member_id='planner'", [], |row| Ok((row.get(0)?, row.get(1)?, row.get(2)?, row.get(3)?)), @@ -788,7 +788,7 @@ async fn udw_link_is_revalidated_from_the_persisted_snapshot_in_the_write_transa let conn = database::db::get_connection().expect("test sqlite connection"); let mut snapshot: crate::definitions::orgs::AgentOrgLaunchSnapshot = conn .query_row( - "SELECT org_snapshot_json FROM agent_org_runtime_runs WHERE id='run-1'", + "SELECT org_snapshot_json FROM agent_org_execution_runs WHERE id='run-1'", [], |row| row.get::<_, String>(0), ) @@ -796,7 +796,7 @@ async fn udw_link_is_revalidated_from_the_persisted_snapshot_in_the_write_transa .expect("load launch snapshot"); snapshot.member_communication_links.clear(); conn.execute( - "UPDATE agent_org_runtime_runs SET org_snapshot_json=?1 WHERE id='run-1'", + "UPDATE agent_org_execution_runs SET org_snapshot_json=?1 WHERE id='run-1'", [serde_json::to_string(&snapshot).expect("encode launch snapshot")], ) .expect("remove persisted link after tool assembly"); @@ -836,7 +836,7 @@ async fn udw_rejects_self_unknown_depth_and_delivery_budget_without_writes() { let conn = database::db::get_connection().expect("test sqlite connection"); conn.execute( - "UPDATE agent_org_runtime_user_directed_roots + "UPDATE agent_org_execution_user_directed_roots SET max_cascade_depth=0 WHERE root_authority_turn_id='builder-udw-turn'", [], ) @@ -850,7 +850,7 @@ async fn udw_rejects_self_unknown_depth_and_delivery_budget_without_writes() { "{depth_error}" ); conn.execute( - "UPDATE agent_org_runtime_user_directed_roots + "UPDATE agent_org_execution_user_directed_roots SET max_cascade_depth=2,next_delivery_ordinal=max_deliveries+2 WHERE root_authority_turn_id='builder-udw-turn'", [], @@ -886,7 +886,7 @@ async fn udw_coordinator_side_quest_uses_root_binding_without_formal_work() { let conn = database::db::get_connection().expect("test sqlite connection"); let before_tasks: i64 = conn .query_row( - "SELECT COUNT(*) FROM agent_org_runtime_tasks WHERE org_run_id='run-1'", + "SELECT COUNT(*) FROM agent_org_execution_tasks WHERE org_run_id='run-1'", [], |row| row.get(0), ) @@ -914,26 +914,26 @@ async fn udw_coordinator_side_quest_uses_root_binding_without_formal_work() { .query_row( "SELECT (SELECT COUNT(*) - FROM agent_org_runtime_user_directed_coordinator_bindings), + FROM agent_org_execution_user_directed_coordinator_bindings), (SELECT COUNT(*) - FROM agent_org_runtime_formal_trigger_receipts receipt - JOIN agent_org_runtime_inbox inbox ON inbox.id=receipt.inbox_id + FROM agent_org_execution_formal_trigger_receipts receipt + JOIN agent_org_execution_inbox inbox ON inbox.id=receipt.inbox_id WHERE inbox.delivery_class='user_directed'), (SELECT context.turn_kind - FROM agent_org_runtime_turn_contexts context - JOIN agent_org_runtime_user_directed_coordinator_bindings binding + FROM agent_org_execution_turn_contexts context + JOIN agent_org_execution_user_directed_coordinator_bindings binding ON binding.session_id=context.session_id AND binding.turn_intent_id=context.turn_intent_id LIMIT 1), (SELECT context.source_kind - FROM agent_org_runtime_turn_contexts context - JOIN agent_org_runtime_user_directed_coordinator_bindings binding + FROM agent_org_execution_turn_contexts context + JOIN agent_org_execution_user_directed_coordinator_bindings binding ON binding.session_id=context.session_id AND binding.turn_intent_id=context.turn_intent_id LIMIT 1), (SELECT context.activation_generation - FROM agent_org_runtime_turn_contexts context - JOIN agent_org_runtime_user_directed_coordinator_bindings binding + FROM agent_org_execution_turn_contexts context + JOIN agent_org_execution_user_directed_coordinator_bindings binding ON binding.session_id=context.session_id AND binding.turn_intent_id=context.turn_intent_id LIMIT 1)", @@ -980,7 +980,7 @@ async fn udw_coordinator_side_quest_uses_root_binding_without_formal_work() { "{formal_staging_error}" ); conn.execute( - "UPDATE agent_org_runtime_runs SET status='idle' WHERE id='run-1'", + "UPDATE agent_org_execution_runs SET status='idle' WHERE id='run-1'", [], ) .expect("idle Team around the same durable side quest"); @@ -996,8 +996,8 @@ async fn udw_coordinator_side_quest_uses_root_binding_without_formal_work() { let (idle_activation_status, idle_activation_generation): (String, Option) = conn .query_row( "SELECT run.status,context.activation_generation - FROM agent_org_runtime_runs run - JOIN agent_org_runtime_turn_contexts context ON context.org_run_id=run.id + FROM agent_org_execution_runs run + JOIN agent_org_execution_turn_contexts context ON context.org_run_id=run.id WHERE run.id='run-1' AND context.session_id='root-1' AND context.turn_intent_id=?1", [&wakes[0].turn_intent_id], @@ -1007,7 +1007,7 @@ async fn udw_coordinator_side_quest_uses_root_binding_without_formal_work() { assert_eq!(idle_activation_status, "running"); assert_eq!(idle_activation_generation, None); conn.execute( - "UPDATE agent_org_runtime_runs SET status='paused' WHERE id='run-1'", + "UPDATE agent_org_execution_runs SET status='paused' WHERE id='run-1'", [], ) .expect("pause Team around the same durable side quest"); @@ -1030,7 +1030,7 @@ async fn udw_coordinator_side_quest_uses_root_binding_without_formal_work() { ); assert_eq!( conn.query_row( - "SELECT COUNT(*) FROM agent_org_runtime_tasks WHERE org_run_id='run-1'", + "SELECT COUNT(*) FROM agent_org_execution_tasks WHERE org_run_id='run-1'", [], |row| row.get::<_, i64>(0), ) @@ -1071,7 +1071,7 @@ async fn coordinator_side_quests_keep_durable_fifo_when_kicks_arrive_out_of_orde let queued_bindings: i64 = conn .query_row( "SELECT COUNT(*) - FROM agent_org_runtime_user_directed_coordinator_bindings binding + FROM agent_org_execution_user_directed_coordinator_bindings binding JOIN session_turn_intents intent ON intent.session_id=binding.session_id AND intent.turn_intent_id=binding.turn_intent_id @@ -1265,7 +1265,7 @@ async fn execute_persists_and_wakes_by_member_id() { let binding: (String, String, String) = conn .query_row( "SELECT task_id,recipient_member_id,source_turn_intent_id - FROM agent_org_runtime_inbox_task_bindings WHERE inbox_id=?1", + FROM agent_org_execution_inbox_task_bindings WHERE inbox_id=?1", [rows[0].id], |row| Ok((row.get(0)?, row.get(1)?, row.get(2)?)), ) @@ -1309,7 +1309,7 @@ async fn member_inbox_coordinator_task_dispatch_returns_root_guidance_with_zero_ let conn = database::db::get_connection().expect("test sqlite connection"); let before_bindings: i64 = conn .query_row( - "SELECT COUNT(*) FROM agent_org_runtime_inbox_task_bindings WHERE org_run_id='run-1'", + "SELECT COUNT(*) FROM agent_org_execution_inbox_task_bindings WHERE org_run_id='run-1'", [], |row| row.get(0), ) @@ -1350,7 +1350,7 @@ async fn member_inbox_coordinator_task_dispatch_returns_root_guidance_with_zero_ let inbox_count = AgentInboxStore::count_by_run("run-1").expect("count Inbox rows"); let binding_count: i64 = conn .query_row( - "SELECT COUNT(*) FROM agent_org_runtime_inbox_task_bindings WHERE org_run_id='run-1'", + "SELECT COUNT(*) FROM agent_org_execution_inbox_task_bindings WHERE org_run_id='run-1'", [], |row| row.get(0), ) @@ -1412,7 +1412,7 @@ fn formal_task_batch_validates_every_recipient_before_the_first_inbox_write() { assert_eq!(AgentInboxStore::count_by_run("run-1").unwrap(), 0); let binding_count: i64 = conn .query_row( - "SELECT COUNT(*) FROM agent_org_runtime_inbox_task_bindings WHERE org_run_id='run-1'", + "SELECT COUNT(*) FROM agent_org_execution_inbox_task_bindings WHERE org_run_id='run-1'", [], |row| row.get(0), ) @@ -1427,7 +1427,7 @@ async fn binding_write_failure_rolls_back_inbox_receipt_and_wake() { let conn = database::db::get_connection().expect("test sqlite connection"); conn.execute_batch( "CREATE TRIGGER fail_task_message_binding - BEFORE INSERT ON agent_org_runtime_inbox_task_bindings + BEFORE INSERT ON agent_org_execution_inbox_task_bindings BEGIN SELECT RAISE(ABORT,'injected task message binding failure'); END;", ) .expect("install binding failure injection"); @@ -1455,9 +1455,9 @@ async fn binding_write_failure_rolls_back_inbox_receipt_and_wake() { let conn = database::db::get_connection().expect("test sqlite connection"); for (table, expected) in [ - ("agent_org_runtime_inbox", 0_i64), - ("agent_org_runtime_inbox_task_bindings", 0_i64), - ("agent_org_runtime_tool_call_receipts", 0_i64), + ("agent_org_execution_inbox", 0_i64), + ("agent_org_execution_inbox_task_bindings", 0_i64), + ("agent_org_execution_tool_call_receipts", 0_i64), ] { let count: i64 = conn .query_row(&format!("SELECT COUNT(*) FROM {table}"), [], |row| { @@ -1503,7 +1503,7 @@ async fn ordinary_message_does_not_create_unread_work_after_run_is_archived() { let _sandbox = init_inbox_schema(); let conn = database::db::get_connection().expect("test sqlite connection"); conn.execute( - "UPDATE agent_org_runtime_runs + "UPDATE agent_org_execution_runs SET status='archived',activation_generation=activation_generation+1, archived_at=?1,archive_receipt_id='send-message-archive-receipt' WHERE id='run-1'", @@ -1651,7 +1651,7 @@ async fn shutdown_request_is_rejected_while_member_still_owns_open_tasks() { let conn = database::db::get_connection().expect("test sqlite connection"); conn.execute( - "UPDATE agent_org_runtime_tasks + "UPDATE agent_org_execution_tasks SET status='completed',output_json='{ \"summary\":\"done\", \"content\":null, @@ -1693,7 +1693,7 @@ async fn routine_member_progress_without_task_or_purpose_is_guidance_with_zero_w let conn = database::db::get_connection().expect("test sqlite connection"); let trigger_before: i64 = conn .query_row( - "SELECT COUNT(*) FROM agent_org_runtime_formal_trigger_receipts + "SELECT COUNT(*) FROM agent_org_execution_formal_trigger_receipts WHERE org_run_id='run-1'", [], |row| row.get(0), @@ -1724,7 +1724,7 @@ async fn routine_member_progress_without_task_or_purpose_is_guidance_with_zero_w let conn = database::db::get_connection().expect("test sqlite connection"); let trigger_after: i64 = conn .query_row( - "SELECT COUNT(*) FROM agent_org_runtime_formal_trigger_receipts + "SELECT COUNT(*) FROM agent_org_execution_formal_trigger_receipts WHERE org_run_id='run-1'", [], |row| row.get(0), @@ -1849,7 +1849,7 @@ async fn actionable_member_coordination_purposes_create_exact_triggers() { let conn = database::db::get_connection().expect("test sqlite connection"); let exact_triggers: i64 = conn .query_row( - "SELECT COUNT(*) FROM agent_org_runtime_formal_trigger_receipts + "SELECT COUNT(*) FROM agent_org_execution_formal_trigger_receipts WHERE org_run_id='run-1' AND source_kind IN ( 'blocker','decision_required','material_change','risk','requested_reply' @@ -1877,7 +1877,7 @@ async fn member_coordination_revalidates_task_run_and_turn_before_delivery() { let set_task = |status: &str, owner: &str| { let conn = database::db::get_connection().expect("test sqlite connection"); conn.execute( - "UPDATE agent_org_runtime_tasks + "UPDATE agent_org_execution_tasks SET status=?1, owner=?2, output_json=NULL, @@ -1891,7 +1891,7 @@ async fn member_coordination_revalidates_task_run_and_turn_before_delivery() { let set_run = |status: &str, generation: i64| { let conn = database::db::get_connection().expect("test sqlite connection"); conn.execute( - "UPDATE agent_org_runtime_runs + "UPDATE agent_org_execution_runs SET status=?1, activation_generation=?2, archived_at=CASE WHEN ?1='archived' THEN updated_at ELSE NULL END, diff --git a/src-tauri/crates/agent-core/src/core/tools/impls/orchestration/agent_org/summary_terminal_tests.rs b/src-tauri/crates/agent-core/src/core/tools/impls/orchestration/agent_org/summary_terminal_tests.rs index f6a19991d8..e7d8777a19 100644 --- a/src-tauri/crates/agent-core/src/core/tools/impls/orchestration/agent_org/summary_terminal_tests.rs +++ b/src-tauri/crates/agent-core/src/core/tools/impls/orchestration/agent_org/summary_terminal_tests.rs @@ -76,8 +76,12 @@ async fn stop_winning_publication_boundary_prevents_late_report_binding_and_rest assert_eq!(summary::reconcile_after_restart(&conn).unwrap(), 0); assert_eq!(receipt().typed_error.as_deref(), Some("stopped")); assert_eq!( - conn.query_row("SELECT COUNT(*) FROM events", [], |r| r.get::<_, i64>(0)) - .unwrap(), + conn.query_row( + "SELECT COUNT(*) FROM events WHERE session_id=?1", + [ROOT_SESSION], + |r| r.get::<_, i64>(0) + ) + .unwrap(), 0 ); } @@ -134,7 +138,7 @@ async fn interrupted_receipt_write_rolls_back_turn_and_recovers_from_stable_even .unwrap(); inject_event_commit_before_receipt_update(&event_id, &original.certificate_id); let conn = database::db::get_connection().unwrap(); - conn.execute_batch("CREATE TRIGGER fail_report_binding BEFORE UPDATE ON agent_org_runtime_final_summary_receipts WHEN NEW.status='persisted' BEGIN SELECT RAISE(FAIL,'injected_receipt_write'); END;").unwrap(); + conn.execute_batch("CREATE TRIGGER fail_report_binding BEFORE UPDATE ON agent_org_execution_final_summary_receipts WHEN NEW.status='persisted' BEGIN SELECT RAISE(FAIL,'injected_receipt_write'); END;").unwrap(); assert!( finish(ROOT_SESSION, SUMMARY_TURN, TurnTerminalStatus::Cancelled) .unwrap_err() diff --git a/src-tauri/crates/agent-core/src/core/tools/impls/orchestration/agent_org/task_formal_receipt_tests.rs b/src-tauri/crates/agent-core/src/core/tools/impls/orchestration/agent_org/task_formal_receipt_tests.rs index 6be5807dff..7c5abc2fdc 100644 --- a/src-tauri/crates/agent-core/src/core/tools/impls/orchestration/agent_org/task_formal_receipt_tests.rs +++ b/src-tauri/crates/agent-core/src/core/tools/impls/orchestration/agent_org/task_formal_receipt_tests.rs @@ -18,7 +18,7 @@ fn task_output_receipt_binds_the_exact_source_turn_and_output_digest() { .expect("FormalTriggerReceipt schema"); let now = chrono::Utc::now().to_rfc3339(); conn.execute( - "INSERT INTO agent_org_runtime_runs( + "INSERT INTO agent_org_execution_runs( id,org_id,coordinator_agent_id,root_session_id,org_snapshot_json, entry_mode,status,activation_generation,has_initial_work,created_at,updated_at ) VALUES (?1,'org-task-output','coordinator-agent','root-task-output',NULL, @@ -88,7 +88,7 @@ fn task_output_receipt_binds_the_exact_source_turn_and_output_digest() { .query_row( "SELECT source_kind,task_id,owner_member_id,source_turn_intent_id, task_output_digest,status - FROM agent_org_runtime_formal_trigger_receipts + FROM agent_org_execution_formal_trigger_receipts WHERE org_run_id='run-task-output'", [], |row| { diff --git a/src-tauri/crates/agent-core/src/core/tools/impls/orchestration/agent_org/task_tests.rs b/src-tauri/crates/agent-core/src/core/tools/impls/orchestration/agent_org/task_tests.rs index b6f9665561..89c1e329c6 100644 --- a/src-tauri/crates/agent-core/src/core/tools/impls/orchestration/agent_org/task_tests.rs +++ b/src-tauri/crates/agent-core/src/core/tools/impls/orchestration/agent_org/task_tests.rs @@ -178,6 +178,7 @@ fn sandbox() -> test_env::SandboxGuard { let sandbox = test_env::sandbox(); let conn = database::db::get_connection().expect("test sqlite"); crate::persistence::test_schema::ensure_agent_sessions_schema(&conn); + crate::persistence::test_schema::ensure_session_events_schema(&conn); conn.execute_batch( "CREATE TABLE code_sessions ( session_id TEXT PRIMARY KEY, @@ -218,7 +219,7 @@ fn sandbox() -> test_env::SandboxGuard { }) .to_string(); conn.execute( - "INSERT INTO agent_org_runtime_runs( + "INSERT INTO agent_org_execution_runs( id,org_id,coordinator_agent_id,root_session_id,org_snapshot_json, entry_mode,status,activation_generation,created_at,updated_at ) VALUES (?1,'org-task-tools','agent-coordinator',?2,?3, @@ -251,7 +252,7 @@ fn sandbox() -> test_env::SandboxGuard { ) .expect("participant Session"); conn.execute( - "INSERT INTO agent_org_runtime_member_materializations ( + "INSERT INTO agent_org_execution_member_materializations ( org_run_id,member_id,agent_id,generation,session_id, authority_class,status,created_at,updated_at ) VALUES (?1,?2,?3,1,?4,'formal','succeeded',?5,?5)", @@ -282,7 +283,7 @@ fn insert_coordinator_context_for_turn(conn: &rusqlite::Connection, turn_id: &st insert_base_turn(conn, ROOT_SESSION, turn_id); let now = chrono::Utc::now().to_rfc3339(); conn.execute( - "INSERT INTO agent_org_runtime_turn_contexts( + "INSERT INTO agent_org_execution_turn_contexts( session_id,turn_intent_id,org_run_id,participant_id,turn_kind, source_kind,source_id,activation_generation,created_at ) VALUES (?1,?2,?3,'coordinator','coordinator','root_turn',?2,1,?4)", @@ -294,12 +295,12 @@ fn insert_coordinator_context_for_turn(conn: &rusqlite::Connection, turn_id: &st fn seed_initial_empty_task_board(conn: &rusqlite::Connection) { let now = chrono::Utc::now().to_rfc3339(); conn.execute( - "UPDATE agent_org_runtime_runs SET has_initial_work=1 WHERE id=?1", + "UPDATE agent_org_execution_runs SET has_initial_work=1 WHERE id=?1", [RUN_ID], ) .expect("mark initial work"); conn.execute( - "INSERT INTO agent_org_runtime_initial_inputs ( + "INSERT INTO agent_org_execution_initial_inputs ( org_run_id,turn_intent_id,message_id,content,payload_json, status,created_at,updated_at ) VALUES (?1,?2,'message-initial','Build the requested app','{}', @@ -308,14 +309,14 @@ fn seed_initial_empty_task_board(conn: &rusqlite::Connection) { ) .expect("initial input"); conn.execute( - "INSERT INTO agent_org_runtime_run_progress (org_run_id,work_revision,updated_at) + "INSERT INTO agent_org_execution_run_progress (org_run_id,work_revision,updated_at) VALUES (?1,0,?2) ON CONFLICT(org_run_id) DO UPDATE SET work_revision=0,updated_at=excluded.updated_at", rusqlite::params![RUN_ID, &now], ) .expect("initial revision"); conn.execute( - "UPDATE agent_org_runtime_turn_contexts + "UPDATE agent_org_execution_turn_contexts SET coordinator_work_revision=0,terminal_reason=NULL WHERE session_id=?1 AND turn_intent_id=?2", rusqlite::params![ROOT_SESSION, COORDINATOR_TURN], @@ -325,7 +326,7 @@ fn seed_initial_empty_task_board(conn: &rusqlite::Connection) { fn coordinator_terminal_reason(conn: &rusqlite::Connection, turn_id: &str) -> Option { conn.query_row( - "SELECT terminal_reason FROM agent_org_runtime_turn_contexts + "SELECT terminal_reason FROM agent_org_execution_turn_contexts WHERE session_id=?1 AND turn_intent_id=?2", rusqlite::params![ROOT_SESSION, turn_id], |row| row.get(0), @@ -344,7 +345,7 @@ fn insert_owner_context(conn: &rusqlite::Connection, turn_id: &str, task_id: &st let sequence: i64 = conn .query_row( "SELECT COALESCE(MAX(member_dispatch_sequence),0)+1 - FROM agent_org_runtime_turn_contexts + FROM agent_org_execution_turn_contexts WHERE org_run_id=?1 AND dispatch_member_id=?2", rusqlite::params![RUN_ID, ALICE], |row| row.get(0), @@ -352,7 +353,7 @@ fn insert_owner_context(conn: &rusqlite::Connection, turn_id: &str, task_id: &st .unwrap(); let now = chrono::Utc::now().to_rfc3339(); conn.execute( - "INSERT INTO agent_org_runtime_turn_contexts( + "INSERT INTO agent_org_execution_turn_contexts( session_id,turn_intent_id,org_run_id,participant_id,turn_kind, task_id,owner_member_id,dispatch_member_id,member_dispatch_sequence, source_kind,source_id,activation_generation,created_at @@ -486,7 +487,7 @@ async fn empty_board_bypass_excludes_later_task_revision_and_certificate_states( let later_turn = "turn-after-initial-input"; insert_coordinator_context_for_turn(&conn, later_turn); conn.execute( - "UPDATE agent_org_runtime_turn_contexts SET coordinator_work_revision=0 + "UPDATE agent_org_execution_turn_contexts SET coordinator_work_revision=0 WHERE session_id=?1 AND turn_intent_id=?2", rusqlite::params![ROOT_SESSION, later_turn], ) @@ -501,7 +502,7 @@ async fn empty_board_bypass_excludes_later_task_revision_and_certificate_states( assert_task_list_ends_turn(&later); conn.execute( - "INSERT INTO agent_org_runtime_tasks ( + "INSERT INTO agent_org_execution_tasks ( id,org_run_id,activation_generation,subject,status,execution_mode, created_by_participant_id,source_turn_intent_id,created_at,updated_at ) VALUES ('existing-task',?1,1,'Existing task','pending','build', @@ -516,17 +517,17 @@ async fn empty_board_bypass_excludes_later_task_revision_and_certificate_states( assert_task_list_ends_turn(&with_task); conn.execute( - "DELETE FROM agent_org_runtime_tasks WHERE org_run_id=?1", + "DELETE FROM agent_org_execution_tasks WHERE org_run_id=?1", [RUN_ID], ) .expect("restore empty board"); conn.execute( - "UPDATE agent_org_runtime_run_progress SET work_revision=1 WHERE org_run_id=?1", + "UPDATE agent_org_execution_run_progress SET work_revision=1 WHERE org_run_id=?1", [RUN_ID], ) .expect("advance run revision"); conn.execute( - "UPDATE agent_org_runtime_turn_contexts + "UPDATE agent_org_execution_turn_contexts SET coordinator_work_revision=1,terminal_reason=NULL WHERE session_id=?1 AND turn_intent_id=?2", rusqlite::params![ROOT_SESSION, COORDINATOR_TURN], @@ -539,19 +540,19 @@ async fn empty_board_bypass_excludes_later_task_revision_and_certificate_states( assert_task_list_ends_turn(&advanced); conn.execute( - "UPDATE agent_org_runtime_run_progress SET work_revision=0 WHERE org_run_id=?1", + "UPDATE agent_org_execution_run_progress SET work_revision=0 WHERE org_run_id=?1", [RUN_ID], ) .expect("restore initial revision"); conn.execute( - "UPDATE agent_org_runtime_turn_contexts + "UPDATE agent_org_execution_turn_contexts SET coordinator_work_revision=0,terminal_reason=NULL WHERE session_id=?1 AND turn_intent_id=?2", rusqlite::params![ROOT_SESSION, COORDINATOR_TURN], ) .expect("restore initial Turn state"); conn.execute( - "INSERT INTO agent_org_runtime_run_completion_certificates ( + "INSERT INTO agent_org_execution_run_completion_certificates ( id,org_run_id,activation_generation,work_revision,request_id,request_digest, outcome,summary,coordinator_session_id,coordinator_turn_intent_id, evidence_task_ids_json,closure_task_ids_json,task_output_refs_json, @@ -608,8 +609,8 @@ async fn list_dir_then_initial_task_list_can_create_graph_and_advance_revision() let (task_count, work_revision): (i64, i64) = conn .query_row( "SELECT - (SELECT COUNT(*) FROM agent_org_runtime_tasks WHERE org_run_id=?1), - (SELECT work_revision FROM agent_org_runtime_run_progress WHERE org_run_id=?1)", + (SELECT COUNT(*) FROM agent_org_execution_tasks WHERE org_run_id=?1), + (SELECT work_revision FROM agent_org_execution_run_progress WHERE org_run_id=?1)", [RUN_ID], |row| Ok((row.get(0)?, row.get(1)?)), ) @@ -624,20 +625,20 @@ async fn completion_request_replays_without_rewriting_progress() { let conn = database::db::get_connection().expect("test sqlite"); let now = chrono::Utc::now().to_rfc3339(); conn.execute( - "INSERT INTO agent_org_runtime_run_progress (org_run_id,updated_at) + "INSERT INTO agent_org_execution_run_progress (org_run_id,updated_at) VALUES (?1,?2)", rusqlite::params![RUN_ID, &now], ) .expect("completion progress fixture"); conn.execute( - "UPDATE agent_org_runtime_turn_contexts + "UPDATE agent_org_execution_turn_contexts SET coordinator_work_revision=0 WHERE session_id=?1 AND turn_intent_id=?2", rusqlite::params![ROOT_SESSION, COORDINATOR_TURN], ) .expect("presented completion revision"); conn.execute( - "INSERT INTO agent_org_runtime_tasks ( + "INSERT INTO agent_org_execution_tasks ( id,org_run_id,activation_generation,subject,description,status,owner, execution_mode,blocked_by_json,output_json,created_by_participant_id, source_turn_intent_id,created_at,updated_at @@ -690,7 +691,7 @@ async fn completion_request_replays_without_rewriting_progress() { assert_eq!(replay, first); assert_eq!(progress_after, progress_before); let certificates: i64 = conn.query_row( - "SELECT COUNT(*) FROM agent_org_runtime_run_completion_certificates WHERE org_run_id=?1", + "SELECT COUNT(*) FROM agent_org_execution_run_completion_certificates WHERE org_run_id=?1", [RUN_ID], |row| row.get(0), ).unwrap(); assert_eq!( @@ -706,7 +707,7 @@ async fn configured_writer_uses_one_schema_for_graph_and_owned_lifecycle_authori let mut snapshot: Value = serde_json::from_str( &conn .query_row( - "SELECT org_snapshot_json FROM agent_org_runtime_runs WHERE id=?1", + "SELECT org_snapshot_json FROM agent_org_execution_runs WHERE id=?1", [RUN_ID], |row| row.get::<_, String>(0), ) @@ -715,7 +716,7 @@ async fn configured_writer_uses_one_schema_for_graph_and_owned_lifecycle_authori .unwrap(); snapshot["additionalTaskGraphWriterMemberIds"] = json!([ALICE]); conn.execute( - "UPDATE agent_org_runtime_runs SET org_snapshot_json=?2 WHERE id=?1", + "UPDATE agent_org_execution_runs SET org_snapshot_json=?2 WHERE id=?1", rusqlite::params![RUN_ID, serde_json::to_string(&snapshot).unwrap()], ) .unwrap(); @@ -883,7 +884,7 @@ async fn idle_first_task_activates_once_and_replay_stays_read_only_after_archive let _sandbox = sandbox(); let conn = database::db::get_connection().expect("test sqlite"); conn.execute( - "UPDATE agent_org_runtime_runs + "UPDATE agent_org_execution_runs SET status='idle',idled_at=?2,last_activity_outcome='completed' WHERE id=?1", rusqlite::params![RUN_ID, chrono::Utc::now().to_rfc3339()], @@ -914,7 +915,7 @@ async fn idle_first_task_activates_once_and_replay_stays_read_only_after_archive assert_eq!(activated.activation_generation, 2); let marker_generation: i64 = conn .query_row( - "SELECT activation_generation FROM agent_org_runtime_turn_contexts + "SELECT activation_generation FROM agent_org_execution_turn_contexts WHERE session_id=?1 AND turn_intent_id=?2", rusqlite::params![ROOT_SESSION, COORDINATOR_TURN], |row| row.get(0), @@ -952,7 +953,7 @@ async fn idle_first_task_activates_once_and_replay_stays_read_only_after_archive ); conn.execute( - "UPDATE agent_org_runtime_runs + "UPDATE agent_org_execution_runs SET status='archived',activation_generation=activation_generation+1, archived_at=?2,archive_receipt_id='idle-replay-archive' WHERE id=?1", @@ -962,13 +963,13 @@ async fn idle_first_task_activates_once_and_replay_stays_read_only_after_archive let before = ( AgentOrgTaskStore::list(RUN_ID).unwrap().len(), conn.query_row( - "SELECT COUNT(*) FROM agent_org_runtime_inbox WHERE org_run_id=?1", + "SELECT COUNT(*) FROM agent_org_execution_inbox WHERE org_run_id=?1", [RUN_ID], |row| row.get::<_, i64>(0), ) .unwrap(), conn.query_row( - "SELECT COUNT(*) FROM agent_org_runtime_tool_call_receipts WHERE org_run_id=?1", + "SELECT COUNT(*) FROM agent_org_execution_tool_call_receipts WHERE org_run_id=?1", [RUN_ID], |row| row.get::<_, i64>(0), ) @@ -982,13 +983,13 @@ async fn idle_first_task_activates_once_and_replay_stays_read_only_after_archive let after = ( AgentOrgTaskStore::list(RUN_ID).unwrap().len(), conn.query_row( - "SELECT COUNT(*) FROM agent_org_runtime_inbox WHERE org_run_id=?1", + "SELECT COUNT(*) FROM agent_org_execution_inbox WHERE org_run_id=?1", [RUN_ID], |row| row.get::<_, i64>(0), ) .unwrap(), conn.query_row( - "SELECT COUNT(*) FROM agent_org_runtime_tool_call_receipts WHERE org_run_id=?1", + "SELECT COUNT(*) FROM agent_org_execution_tool_call_receipts WHERE org_run_id=?1", [RUN_ID], |row| row.get::<_, i64>(0), ) @@ -1021,7 +1022,7 @@ async fn idle_after_cancelled_episode_accepts_new_work_and_clears_prior_outcome( let _sandbox = sandbox(); let conn = database::db::get_connection().expect("test sqlite"); conn.execute( - "UPDATE agent_org_runtime_runs + "UPDATE agent_org_execution_runs SET status='idle',idled_at=?2,last_activity_outcome='cancelled' WHERE id=?1", rusqlite::params![RUN_ID, chrono::Utc::now().to_rfc3339()], @@ -1057,7 +1058,7 @@ async fn concurrent_idle_task_creates_share_one_activation_generation() { let _sandbox = sandbox(); let conn = database::db::get_connection().expect("test sqlite"); conn.execute( - "UPDATE agent_org_runtime_runs + "UPDATE agent_org_execution_runs SET status='idle',idled_at=?2,last_activity_outcome='completed' WHERE id=?1", rusqlite::params![RUN_ID, chrono::Utc::now().to_rfc3339()], @@ -1098,7 +1099,7 @@ async fn concurrent_idle_task_creates_share_one_activation_generation() { assert_eq!(AgentOrgTaskStore::list(RUN_ID).unwrap().len(), 2); let marker_generation: i64 = conn .query_row( - "SELECT activation_generation FROM agent_org_runtime_turn_contexts + "SELECT activation_generation FROM agent_org_execution_turn_contexts WHERE session_id=?1 AND turn_intent_id=?2", rusqlite::params![ROOT_SESSION, COORDINATOR_TURN], |row| row.get(0), @@ -1112,7 +1113,7 @@ async fn paused_first_task_is_rejected_without_task_or_receipt() { let _sandbox = sandbox(); let conn = database::db::get_connection().expect("test sqlite"); conn.execute( - "UPDATE agent_org_runtime_runs + "UPDATE agent_org_execution_runs SET status='paused',activation_generation=2,updated_at=?2 WHERE id=?1", rusqlite::params![RUN_ID, chrono::Utc::now().to_rfc3339()], @@ -1137,7 +1138,7 @@ async fn paused_first_task_is_rejected_without_task_or_receipt() { assert!(AgentOrgTaskStore::list(RUN_ID).unwrap().is_empty()); let receipt_count: i64 = conn .query_row( - "SELECT COUNT(*) FROM agent_org_runtime_tool_call_receipts + "SELECT COUNT(*) FROM agent_org_execution_tool_call_receipts WHERE org_run_id=?1 AND call_id=?2", rusqlite::params![RUN_ID, &call.call_id], |row| row.get(0), diff --git a/src-tauri/crates/agent-core/src/core/tools/impls/orchestration/agent_org/tasks.rs b/src-tauri/crates/agent-core/src/core/tools/impls/orchestration/agent_org/tasks.rs index 85f2717ce8..33dafe9ef5 100644 --- a/src-tauri/crates/agent-core/src/core/tools/impls/orchestration/agent_org/tasks.rs +++ b/src-tauri/crates/agent-core/src/core/tools/impls/orchestration/agent_org/tasks.rs @@ -581,7 +581,7 @@ impl TaskToolsContext { )?; if suppress_self_wake { conn.execute( - "UPDATE agent_org_runtime_inbox SET read_at=?2 WHERE id=?1 AND read_at IS NULL", + "UPDATE agent_org_execution_inbox SET read_at=?2 WHERE id=?1 AND read_at IS NULL", rusqlite::params![record.id, chrono::Utc::now().to_rfc3339()], ) .map_err(|error| error.to_string())?; diff --git a/src-tauri/crates/agent-core/src/core/tools/impls/orchestration/inbox_wake/tests/formal_receipt_wake_tests.rs b/src-tauri/crates/agent-core/src/core/tools/impls/orchestration/inbox_wake/tests/formal_receipt_wake_tests.rs index 707bac671b..8887333aac 100644 --- a/src-tauri/crates/agent-core/src/core/tools/impls/orchestration/inbox_wake/tests/formal_receipt_wake_tests.rs +++ b/src-tauri/crates/agent-core/src/core/tools/impls/orchestration/inbox_wake/tests/formal_receipt_wake_tests.rs @@ -18,7 +18,7 @@ fn unstarted_wakes_refund_exact_reservations_without_reviving_older_tokens() { }; let count = || { conn.query_row( - "SELECT COUNT(*) FROM agent_org_runtime_recovery_attempts WHERE org_run_id='unstarted-run'", + "SELECT COUNT(*) FROM agent_org_execution_recovery_attempts WHERE org_run_id='unstarted-run'", [], |row| row.get::<_, i64>(0), ).unwrap() }; @@ -48,7 +48,7 @@ fn unstarted_wakes_refund_exact_reservations_without_reviving_older_tokens() { let next = reserve("new-empty-input"); drop(next); let (fingerprint, token): (String, Option) = conn.query_row( - "SELECT reason_fingerprint,reservation_token FROM agent_org_runtime_recovery_attempts WHERE org_run_id='unstarted-run'", + "SELECT reason_fingerprint,reservation_token FROM agent_org_execution_recovery_attempts WHERE org_run_id='unstarted-run'", [], |row| Ok((row.get(0)?,row.get(1)?)), ).unwrap(); assert_eq!(fingerprint, "actual-provider-work"); @@ -72,9 +72,9 @@ fn reservation_storage_failure_remains_retryable_error() { else { panic!("reservation deferred"); }; - conn.execute_batch("CREATE TRIGGER reject_refund BEFORE DELETE ON agent_org_runtime_recovery_attempts BEGIN SELECT RAISE(ABORT,'controlled storage failure'); END;").unwrap(); + conn.execute_batch("CREATE TRIGGER reject_refund BEFORE DELETE ON agent_org_execution_recovery_attempts BEGIN SELECT RAISE(ABORT,'controlled storage failure'); END;").unwrap(); assert!(refund_member_rewake_reservation(&reservation).is_err()); - assert!(conn.query_row("SELECT reservation_token IS NOT NULL FROM agent_org_runtime_recovery_attempts WHERE org_run_id='refund-error'",[],|row|row.get::<_,bool>(0)).unwrap()); + assert!(conn.query_row("SELECT reservation_token IS NOT NULL FROM agent_org_execution_recovery_attempts WHERE org_run_id='refund-error'",[],|row|row.get::<_,bool>(0)).unwrap()); conn.execute_batch("DROP TRIGGER reject_refund;").unwrap(); assert!(refund_member_rewake_reservation(&reservation).unwrap()); } diff --git a/src-tauri/crates/agent-core/src/core/tools/impls/orchestration/member_idle/tests.rs b/src-tauri/crates/agent-core/src/core/tools/impls/orchestration/member_idle/tests.rs index 60b536b47b..7713da2d50 100644 --- a/src-tauri/crates/agent-core/src/core/tools/impls/orchestration/member_idle/tests.rs +++ b/src-tauri/crates/agent-core/src/core/tools/impls/orchestration/member_idle/tests.rs @@ -57,7 +57,7 @@ fn seed_run(conn: &rusqlite::Connection, run_id: &str, status: &str) { crate::coordination::init_agent_org_schemas(conn).expect("canonical Agent Org schema"); let now = chrono::Utc::now().to_rfc3339(); conn.execute( - "INSERT INTO agent_org_runtime_runs ( + "INSERT INTO agent_org_execution_runs ( id, org_id, coordinator_agent_id, root_session_id, entry_mode, status, created_at, updated_at,archived_at,archive_receipt_id ) VALUES (?1, 'org-1', 'coord', 'root-1', 'build', ?2, ?3, ?3, @@ -72,7 +72,7 @@ fn seed_completed_task(conn: &rusqlite::Connection, run_id: &str, member_id: &st let now = chrono::Utc::now().to_rfc3339(); let episode_id = format!("{run_id}-episode"); conn.execute( - "INSERT INTO agent_org_runtime_work_episodes ( + "INSERT INTO agent_org_execution_work_episodes ( id,org_run_id,episode_sequence,status,opening_activation_generation, opening_work_revision,opened_by_turn_intent_id,created_at ) VALUES (?1,?2,1,'active',1,0,'turn-create',?3)", @@ -80,7 +80,7 @@ fn seed_completed_task(conn: &rusqlite::Connection, run_id: &str, member_id: &st ) .expect("seed active work episode"); conn.execute( - "INSERT INTO agent_org_runtime_tasks ( + "INSERT INTO agent_org_execution_tasks ( id,org_run_id,activation_generation,subject,description,owner,status, execution_mode,blocked_by_json,output_json,created_by_participant_id, source_turn_intent_id,created_at,updated_at @@ -92,7 +92,7 @@ fn seed_completed_task(conn: &rusqlite::Connection, run_id: &str, member_id: &st ) .expect("seed terminal Task"); conn.execute( - "INSERT INTO agent_org_runtime_work_episode_tasks ( + "INSERT INTO agent_org_execution_work_episode_tasks ( org_run_id,work_episode_id,task_id,associated_at ) VALUES (?1,?2,'task-terminal',?3)", rusqlite::params![run_id, &episode_id, &now], @@ -110,7 +110,7 @@ fn seed_active_task_turn(conn: &rusqlite::Connection, run_id: &str, member_id: & ) .expect("seed active worker Turn intent"); conn.execute( - "INSERT INTO agent_org_runtime_turn_contexts ( + "INSERT INTO agent_org_execution_turn_contexts ( session_id,turn_intent_id,org_run_id,participant_id,turn_kind, task_id,owner_member_id,dispatch_member_id,member_dispatch_sequence, source_kind,source_id,activation_generation,created_at @@ -168,7 +168,7 @@ fn routine_member_idle_persists_without_coordinator_provider_wake() { assert!(wake_hook.snapshot().is_empty()); let receipt_count: i64 = conn .query_row( - "SELECT COUNT(*) FROM agent_org_runtime_formal_trigger_receipts", + "SELECT COUNT(*) FROM agent_org_execution_formal_trigger_receipts", [], |row| row.get(0), ) @@ -212,7 +212,7 @@ fn final_member_idle_creates_exact_formal_receipt_and_wakes_coordinator() { let receipt: (String, String, String, String, String) = conn .query_row( "SELECT source_kind,status,task_id,owner_member_id,source_turn_intent_id - FROM agent_org_runtime_formal_trigger_receipts", + FROM agent_org_execution_formal_trigger_receipts", [], |row| { Ok(( diff --git a/src-tauri/crates/agent-core/src/core/tools/impls/plan_mode/create_plan.rs b/src-tauri/crates/agent-core/src/core/tools/impls/plan_mode/create_plan.rs index 7268361841..2f9b228478 100644 --- a/src-tauri/crates/agent-core/src/core/tools/impls/plan_mode/create_plan.rs +++ b/src-tauri/crates/agent-core/src/core/tools/impls/plan_mode/create_plan.rs @@ -873,7 +873,7 @@ mod tests { member_communication_links: Vec::new(), }; conn.execute( - "INSERT INTO agent_org_runtime_runs ( + "INSERT INTO agent_org_execution_runs ( id,org_id,coordinator_agent_id,root_session_id,org_snapshot_json, entry_mode,status,activation_generation,created_at,updated_at ) VALUES ('plan-run','plan-org','plan-coordinator-agent','plan-root',?1, @@ -915,7 +915,7 @@ mod tests { .unwrap(); } conn.execute( - "INSERT INTO agent_org_runtime_member_materializations ( + "INSERT INTO agent_org_execution_member_materializations ( org_run_id,member_id,agent_id,generation,session_id, authority_class,status,created_at,updated_at ) VALUES ('plan-run','planner','planner-agent',1,'planner-session', @@ -950,7 +950,7 @@ mod tests { ) .unwrap(); conn.execute( - "INSERT INTO agent_org_runtime_turn_contexts ( + "INSERT INTO agent_org_execution_turn_contexts ( session_id,turn_intent_id,org_run_id,participant_id,turn_kind, task_id,owner_member_id,dispatch_member_id,member_dispatch_sequence, source_kind,source_id,activation_generation,created_at @@ -1019,7 +1019,7 @@ mod tests { ); let receipt_count: i64 = conn .query_row( - "SELECT COUNT(*) FROM agent_org_runtime_tool_call_receipts + "SELECT COUNT(*) FROM agent_org_execution_tool_call_receipts WHERE org_run_id='plan-run' AND tool_name='create_plan'", [], |row| row.get(0), diff --git a/src-tauri/crates/agent-core/src/core/tools/registry.rs b/src-tauri/crates/agent-core/src/core/tools/registry.rs index 5e30dd82ba..ac1226c7c4 100644 --- a/src-tauri/crates/agent-core/src/core/tools/registry.rs +++ b/src-tauri/crates/agent-core/src/core/tools/registry.rs @@ -406,6 +406,8 @@ impl ToolRegistry { mut params: Value, ctx: &crate::tools::call_context::CallContext, ) -> Result { + crate::coordination::agent_org_history_store::require_writable_session(&ctx.session_id) + .await?; let Some(tool) = self.get(name) else { return Err(format!("Error: Tool '{}' not found", name)); }; @@ -432,6 +434,8 @@ impl ToolRegistry { policy: &ResolvedToolPolicy, ctx: &crate::tools::call_context::CallContext, ) -> Result { + crate::coordination::agent_org_history_store::require_writable_session(&ctx.session_id) + .await?; let mut refreshed_policy = policy .refreshed_for_execute_call(&ctx.session_id, &ctx.turn_intent_id) .map_err(|error| format!("Error: {error}"))?; diff --git a/src-tauri/crates/agent-core/src/foundation/persistence/db_helpers/messages/cleanup.rs b/src-tauri/crates/agent-core/src/foundation/persistence/db_helpers/messages/cleanup.rs index 871b2efe3f..80202a83e6 100644 --- a/src-tauri/crates/agent-core/src/foundation/persistence/db_helpers/messages/cleanup.rs +++ b/src-tauri/crates/agent-core/src/foundation/persistence/db_helpers/messages/cleanup.rs @@ -38,13 +38,13 @@ pub fn clear_messages(prefix: &str, session_id: &str) -> SqliteResult { with_sessions_writer(|| { let mut conn = get_connection()?; let tx = conn.transaction_with_behavior(rusqlite::TransactionBehavior::Immediate)?; - if prefix == "agent" && table_exists(&tx, "agent_org_runtime_inbox_materializations")? { + if prefix == "agent" && table_exists(&tx, "agent_org_execution_inbox_materializations")? { // Rewind/clear removes the durable transcript but intentionally // leaves the source Inbox row unread. Deleting its receipt lets // the next wake materialize the input again instead of pointing // forever at a transcript that no longer exists. tx.execute( - "DELETE FROM agent_org_runtime_inbox_materializations WHERE session_id=?1", + "DELETE FROM agent_org_execution_inbox_materializations WHERE session_id=?1", [session_id], )?; } @@ -76,9 +76,9 @@ pub fn truncate_messages_from_sequence( with_sessions_writer(|| { let mut conn = get_connection()?; let tx = conn.transaction_with_behavior(rusqlite::TransactionBehavior::Immediate)?; - if prefix == "agent" && table_exists(&tx, "agent_org_runtime_inbox_materializations")? { + if prefix == "agent" && table_exists(&tx, "agent_org_execution_inbox_materializations")? { tx.execute( - "DELETE FROM agent_org_runtime_inbox_materializations + "DELETE FROM agent_org_execution_inbox_materializations WHERE session_id=?1 AND transcript_message_id IN ( SELECT id FROM agent_messages diff --git a/src-tauri/crates/agent-core/src/foundation/persistence/db_helpers/mod.rs b/src-tauri/crates/agent-core/src/foundation/persistence/db_helpers/mod.rs index 68901c3b06..f79d0630a8 100644 --- a/src-tauri/crates/agent-core/src/foundation/persistence/db_helpers/mod.rs +++ b/src-tauri/crates/agent-core/src/foundation/persistence/db_helpers/mod.rs @@ -177,7 +177,7 @@ fn delete_session_rows_with_connection( let receipts_exist: bool = conn.query_row( "SELECT EXISTS( SELECT 1 FROM sqlite_master - WHERE type='table' AND name='agent_org_runtime_inbox_materializations' + WHERE type='table' AND name='agent_org_execution_inbox_materializations' )", [], |row| row.get(0), @@ -186,7 +186,7 @@ fn delete_session_rows_with_connection( // Keep the source Inbox rows unread while atomically removing // receipts for transcript rows deleted by this cascade. conn.execute( - "DELETE FROM agent_org_runtime_inbox_materializations WHERE session_id=?1", + "DELETE FROM agent_org_execution_inbox_materializations WHERE session_id=?1", [session_id], )?; } diff --git a/src-tauri/crates/agent-core/src/foundation/persistence/test_schema.rs b/src-tauri/crates/agent-core/src/foundation/persistence/test_schema.rs index 9f0672e714..6c4e216f54 100644 --- a/src-tauri/crates/agent-core/src/foundation/persistence/test_schema.rs +++ b/src-tauri/crates/agent-core/src/foundation/persistence/test_schema.rs @@ -142,6 +142,10 @@ pub(crate) const AGENT_SESSIONS_TEST_DDL: &str = r#" pub(crate) fn ensure_agent_sessions_schema(conn: &rusqlite::Connection) { conn.execute_batch(AGENT_SESSIONS_TEST_DDL) .expect("agent_sessions test schema"); + conn.execute_batch(include_str!( + "../../core/coordination/agent_org_history_store/schema.sql" + )) + .expect("history identity schema for session store tests"); let existing: std::collections::HashSet = conn .prepare("SELECT name FROM pragma_table_info('agent_sessions')") @@ -179,3 +183,17 @@ pub(crate) fn ensure_agent_sessions_schema(conn: &rusqlite::Connection) { } } } + +/// Event cache columns owned by session-persistence, for core-only fixtures +/// that cannot depend back on that crate. Full app tests use its initializer. +pub(crate) fn ensure_session_events_schema(conn: &rusqlite::Connection) { + conn.execute_batch( + "CREATE TABLE IF NOT EXISTS events ( + id TEXT PRIMARY KEY,session_id TEXT NOT NULL,event_type TEXT NOT NULL, + function_name TEXT,thread_id TEXT,args_json TEXT NOT NULL DEFAULT '{}', + result_json TEXT NOT NULL DEFAULT '{}',content TEXT NOT NULL DEFAULT '', + created_at TEXT NOT NULL,meta_json TEXT,history_sequence INTEGER, + UNIQUE(id,session_id));", + ) + .expect("session event schema"); +} diff --git a/src-tauri/crates/agent-core/src/init/mod.rs b/src-tauri/crates/agent-core/src/init/mod.rs index 49f95de10c..507806119b 100644 --- a/src-tauri/crates/agent-core/src/init/mod.rs +++ b/src-tauri/crates/agent-core/src/init/mod.rs @@ -349,6 +349,7 @@ async fn ensure_session_initialized( model_override, native_harness_type, } = request; + crate::coordination::agent_org_history_store::require_writable_session(session_id).await?; let workspace_root = resolved.workspace().to_path_buf(); @@ -772,7 +773,7 @@ mod tests { crate::coordination::init_agent_org_schemas(&conn).expect("Agent Org schemas"); let now = "2026-08-23T00:00:00Z"; conn.execute( - "INSERT INTO agent_org_runtime_runs ( + "INSERT INTO agent_org_execution_runs ( id,org_id,coordinator_agent_id,entry_mode,status, activation_generation,created_at,updated_at ) VALUES (?1,'org-runtime-admission','builtin:sde', @@ -811,7 +812,7 @@ mod tests { let conn = database::db::get_connection().expect("sandbox DB"); conn.execute( - "UPDATE agent_org_runtime_runs SET activation_generation=8 WHERE id=?1", + "UPDATE agent_org_execution_runs SET activation_generation=8 WHERE id=?1", [&admission.run_id], ) .expect("change lifecycle generation"); @@ -820,7 +821,7 @@ mod tests { assert!(stale.starts_with("agent_org_runtime_admission_stale:")); conn.execute( - "UPDATE agent_org_runtime_runs + "UPDATE agent_org_execution_runs SET status='archived',archived_at=?2,archive_receipt_id=?3 WHERE id=?1", params![ diff --git a/src-tauri/crates/agent-core/src/lifecycle.rs b/src-tauri/crates/agent-core/src/lifecycle.rs index f93820683a..286e20947d 100644 --- a/src-tauri/crates/agent-core/src/lifecycle.rs +++ b/src-tauri/crates/agent-core/src/lifecycle.rs @@ -468,7 +468,7 @@ pub fn finalize_agent_org_member_turn( )?; requeue_work && context.turn_kind == crate::coordination::agent_org_turn_contexts::AgentOrgTurnKind::TaskExecution && conn.query_row( - "SELECT EXISTS(SELECT 1 FROM agent_org_runtime_tasks + "SELECT EXISTS(SELECT 1 FROM agent_org_execution_tasks WHERE org_run_id=?1 AND id=?2 AND owner=?3 AND status='in_progress')", rusqlite::params![context.org_run_id, context.task_id, context.owner_member_id], |row| row.get::<_, bool>(0), @@ -648,13 +648,13 @@ fn should_rewake_agent_org_member_after_turn( .query_row( "SELECT EXISTS( SELECT 1 - FROM agent_org_runtime_formal_trigger_receipts receipt + FROM agent_org_execution_formal_trigger_receipts receipt WHERE receipt.org_run_id=?1 AND receipt.status='pending' AND receipt.doorbell_status IN ('missing','delivered') AND NOT EXISTS ( SELECT 1 - FROM agent_org_runtime_formal_trigger_attempts attempt + FROM agent_org_execution_formal_trigger_attempts attempt WHERE attempt.receipt_id=receipt.receipt_id AND attempt.status IN ('queued','running') ) diff --git a/src-tauri/crates/agent-core/src/state/commands/session/debug/org_runtime.rs b/src-tauri/crates/agent-core/src/state/commands/session/debug/org_runtime.rs index e8b6d07616..ac7f63ddc8 100644 --- a/src-tauri/crates/agent-core/src/state/commands/session/debug/org_runtime.rs +++ b/src-tauri/crates/agent-core/src/state/commands/session/debug/org_runtime.rs @@ -400,8 +400,8 @@ fn detached_task_call_context( let identity: Option<(String, String)> = conn .query_row( "SELECT context.turn_intent_id,context.session_id - FROM agent_org_runtime_turn_contexts context - JOIN agent_org_runtime_runs run ON run.id=context.org_run_id + FROM agent_org_execution_turn_contexts context + JOIN agent_org_execution_runs run ON run.id=context.org_run_id JOIN session_turn_intents intent ON intent.session_id=context.session_id AND intent.turn_intent_id=context.turn_intent_id diff --git a/src-tauri/crates/agent-core/src/state/commands/session/message/org_wake.rs b/src-tauri/crates/agent-core/src/state/commands/session/message/org_wake.rs index 05ec32d393..2d968a67ae 100644 --- a/src-tauri/crates/agent-core/src/state/commands/session/message/org_wake.rs +++ b/src-tauri/crates/agent-core/src/state/commands/session/message/org_wake.rs @@ -47,7 +47,7 @@ pub(super) fn promote_agent_org_wake_session_to_running( "WITH RECURSIVE run_anchor(root_session_id) AS ( SELECT root_session_id - FROM agent_org_runtime_runs + FROM agent_org_execution_runs WHERE id=?4 AND status=?5 AND root_session_id IS NOT NULL ), descendants(session_id) AS ( @@ -57,7 +57,7 @@ pub(super) fn promote_agent_org_wake_session_to_running( FROM agent_sessions child JOIN descendants parent ON child.parent_session_id=parent.session_id WHERE NOT EXISTS ( - SELECT 1 FROM agent_org_runtime_runs nested + SELECT 1 FROM agent_org_execution_runs nested WHERE nested.id<>?4 AND nested.root_session_id=child.session_id ) @@ -88,7 +88,7 @@ pub(super) fn promote_agent_org_wake_session_to_running( ) AND NOT EXISTS ( SELECT 1 - FROM agent_org_runtime_member_interventions intervention + FROM agent_org_execution_member_interventions intervention WHERE intervention.org_run_id=?4 AND intervention.member_id=CASE WHEN agent_sessions.session_id=(SELECT root_session_id FROM run_anchor) @@ -132,7 +132,7 @@ pub(super) fn promote_agent_org_user_directed_session_to_running( WHERE session_id=?3 AND EXISTS ( SELECT 1 - FROM agent_org_runtime_runs run + FROM agent_org_execution_runs run WHERE run.id=?4 AND run.status IN (?5,?6,?7) )", @@ -191,7 +191,7 @@ pub(crate) fn resolve_agent_org_wake_mode( let row: Option<(String, String)> = tx .query_row( "SELECT execution_mode, status - FROM agent_org_runtime_tasks + FROM agent_org_execution_tasks WHERE org_run_id=?1 AND id=?2 AND owner=?3", params![run_id, task_id, owner_member_id], |row| Ok((row.get(0)?, row.get(1)?)), diff --git a/src-tauri/crates/agent-core/src/state/commands/session/message/send.rs b/src-tauri/crates/agent-core/src/state/commands/session/message/send.rs index b561acb22e..ffed29074d 100644 --- a/src-tauri/crates/agent-core/src/state/commands/session/message/send.rs +++ b/src-tauri/crates/agent-core/src/state/commands/session/message/send.rs @@ -273,6 +273,7 @@ pub(crate) async fn send_message_impl( source: TurnIntentBridgeSource, wake_reservation: Option>, ) -> Result, String> { + crate::coordination::agent_org_history_store::require_writable_session(&session_id).await?; if state.is_shutting_down() { return Err("app_shutdown_in_progress: refusing to enqueue a new Agent turn".into()); } diff --git a/src-tauri/crates/agent-core/src/state/commands/session/message/tests.rs b/src-tauri/crates/agent-core/src/state/commands/session/message/tests.rs index 9b9546723c..529d8db9f5 100644 --- a/src-tauri/crates/agent-core/src/state/commands/session/message/tests.rs +++ b/src-tauri/crates/agent-core/src/state/commands/session/message/tests.rs @@ -31,6 +31,8 @@ use crate::definitions::orgs::{FlatOrgMember, OrgDefinition, PlanApprovalPolicy} use crate::session::{AgentExecMode, SessionStatus}; use core_types::key_source::KeySource; +#[path = "tests/history_read_only_tests.rs"] +mod history_read_only_tests; #[path = "tests/pause_continuation_tests.rs"] mod pause_continuation_tests; @@ -116,7 +118,7 @@ fn setup_wake_mode_fixture(execution_mode: &str, task_status: TaskStatus) -> Wak .expect("seed member session"); let materialized_at = chrono::Utc::now().to_rfc3339(); conn.execute( - "INSERT INTO agent_org_runtime_member_materializations ( + "INSERT INTO agent_org_execution_member_materializations ( org_run_id,member_id,agent_id,generation,session_id, authority_class,status,created_at,updated_at ) VALUES (?1,?2,'planner-agent',1,?3,'formal','succeeded',?4,?4)", @@ -167,7 +169,7 @@ fn seed_task_execution_context(fixture: &WakeModeFixture, turn_intent_id: &str) .expect("canonical Turn Intent test schema"); let generation: i64 = conn .query_row( - "SELECT activation_generation FROM agent_org_runtime_runs WHERE id=?1", + "SELECT activation_generation FROM agent_org_execution_runs WHERE id=?1", [&fixture.run_id], |row| row.get(0), ) @@ -182,7 +184,7 @@ fn seed_task_execution_context(fixture: &WakeModeFixture, turn_intent_id: &str) ) .expect("seed base Turn"); conn.execute( - "INSERT INTO agent_org_runtime_turn_contexts ( + "INSERT INTO agent_org_execution_turn_contexts ( session_id, turn_intent_id, org_run_id, participant_id, turn_kind, task_id, owner_member_id, dispatch_member_id, member_dispatch_sequence, source_kind, source_id, activation_generation, created_at @@ -349,7 +351,7 @@ fn queued_agent_org_wake_rechecks_run_member_and_intervention_at_turn_start() { ) .expect("restore member idle"); conn.execute( - "UPDATE agent_org_runtime_runs SET status='paused' WHERE id=?1", + "UPDATE agent_org_execution_runs SET status='paused' WHERE id=?1", rusqlite::params![&fixture.run_id], ) .expect("pause run"); @@ -360,7 +362,7 @@ fn queued_agent_org_wake_rechecks_run_member_and_intervention_at_turn_start() { ); conn.execute( - "UPDATE agent_org_runtime_runs SET status='running' WHERE id=?1", + "UPDATE agent_org_execution_runs SET status='running' WHERE id=?1", rusqlite::params![&fixture.run_id], ) .expect("resume run"); @@ -431,7 +433,7 @@ fn task_execution_starts_after_materialized_input_before_provider_tools() { assert_eq!(task.status, TaskStatus::InProgress); let assignment_remains_unread: bool = conn .query_row( - "SELECT read_at IS NULL FROM agent_org_runtime_inbox WHERE id=?1", + "SELECT read_at IS NULL FROM agent_org_execution_inbox WHERE id=?1", [inbox_id], |row| row.get(0), ) @@ -443,7 +445,7 @@ fn task_execution_starts_after_materialized_input_before_provider_tools() { let start_event: (String, String, String, String) = conn .query_row( "SELECT previous_status,next_status,actor_kind,source_turn_intent_id - FROM agent_org_runtime_task_events + FROM agent_org_execution_task_events WHERE org_run_id=?1 AND task_id=?2 ORDER BY rowid DESC LIMIT 1", rusqlite::params![&fixture.run_id, &fixture.task_id], @@ -525,7 +527,7 @@ fn cancelled_task_cannot_start_after_assignment_materialization() { let inbox_id = enqueue_and_materialize_task_assignment(&fixture, turn_intent_id); let conn = database::db::get_connection().expect("test db"); conn.execute( - "UPDATE agent_org_runtime_tasks + "UPDATE agent_org_execution_tasks SET status='cancelled',cancel_reason_json=?3,updated_at=?4 WHERE org_run_id=?1 AND id=?2", rusqlite::params![ @@ -568,7 +570,7 @@ fn paused_run_cannot_start_task_after_assignment_materialization() { let inbox_id = enqueue_and_materialize_task_assignment(&fixture, turn_intent_id); let conn = database::db::get_connection().expect("test db"); conn.execute( - "UPDATE agent_org_runtime_runs SET status='paused',updated_at=?2 WHERE id=?1", + "UPDATE agent_org_execution_runs SET status='paused',updated_at=?2 WHERE id=?1", rusqlite::params![&fixture.run_id, chrono::Utc::now().to_rfc3339()], ) .expect("pause run before Provider boundary"); @@ -623,7 +625,7 @@ fn invalidated_queued_wake_does_not_start_its_task() { let started: bool = conn .query_row( "SELECT EXISTS( - SELECT 1 FROM agent_org_runtime_task_events + SELECT 1 FROM agent_org_execution_task_events WHERE org_run_id=?1 AND task_id=?2 AND previous_status='pending' AND next_status='in_progress' )", @@ -641,7 +643,7 @@ fn cancelled_queued_task_cannot_be_restarted_by_its_old_turn() { seed_task_execution_context(&fixture, turn_intent_id); let mut conn = database::db::get_connection().expect("test db"); conn.execute( - "UPDATE agent_org_runtime_tasks + "UPDATE agent_org_execution_tasks SET status='cancelled',cancel_reason_json=?3,updated_at=?4 WHERE org_run_id=?1 AND id=?2", rusqlite::params![ @@ -705,7 +707,7 @@ fn user_directed_turn_allows_running_idle_and_paused_without_changing_team() { AgentOrgRunStatus::Archived, ] { conn.execute( - "UPDATE agent_org_runtime_runs + "UPDATE agent_org_execution_runs SET status=?1, archived_at=CASE WHEN ?1='archived' THEN ?3 ELSE NULL END, archive_receipt_id=CASE WHEN ?1='archived' THEN ?4 ELSE NULL END @@ -744,7 +746,7 @@ fn user_directed_turn_allows_running_idle_and_paused_without_changing_team() { AgentOrgRunStatus::Paused, ] { conn.execute( - "UPDATE agent_org_runtime_runs + "UPDATE agent_org_execution_runs SET status=?1,archived_at=NULL,archive_receipt_id=NULL WHERE id=?2", rusqlite::params![status.as_str(), &fixture.run_id], ) @@ -765,7 +767,7 @@ fn user_directed_turn_allows_running_idle_and_paused_without_changing_team() { ); let run_status: String = conn .query_row( - "SELECT status FROM agent_org_runtime_runs WHERE id=?1", + "SELECT status FROM agent_org_execution_runs WHERE id=?1", [&fixture.run_id], |row| row.get(0), ) @@ -905,7 +907,7 @@ fn task_wake_mode_fails_closed_for_corrupt_first_class_value() { conn.execute_batch("PRAGMA ignore_check_constraints=ON;") .expect("simulate corrupt canonical row"); conn.execute( - "UPDATE agent_org_runtime_tasks SET execution_mode='future_mode' + "UPDATE agent_org_execution_tasks SET execution_mode='future_mode' WHERE org_run_id=?1 AND id=?2", rusqlite::params![&fixture.run_id, &fixture.task_id], ) diff --git a/src-tauri/crates/agent-core/src/state/commands/session/message/tests/history_read_only_tests.rs b/src-tauri/crates/agent-core/src/state/commands/session/message/tests/history_read_only_tests.rs new file mode 100644 index 0000000000..d077bfe8aa --- /dev/null +++ b/src-tauri/crates/agent-core/src/state/commands/session/message/tests/history_read_only_tests.rs @@ -0,0 +1,74 @@ +use crate::coordination::agent_org_history_store::READ_ONLY_ERROR; +use crate::foundation::session_bridge::TurnIntentBridgeSource; +use crate::state::commands::session::identity::IdentityOverrides; +use crate::state::AgentAppState; + +#[tokio::test(flavor = "multi_thread")] +async fn all_send_sources_and_tool_entries_reject_history_before_loading_a_runtime() { + let _sandbox = test_helpers::test_env::sandbox(); + let conn = database::db::get_connection().unwrap(); + crate::persistence::test_schema::ensure_agent_sessions_schema(&conn); + crate::coordination::init_agent_org_schemas(&conn).unwrap(); + conn.execute( + "INSERT INTO org_history_sessions (session_id,root_session_id,source_table) + VALUES ('sdeagent-history','sdeagent-history','fixture')", + [], + ) + .unwrap(); + let state = AgentAppState::new(); + for source in [ + TurnIntentBridgeSource::UserSubmit, + TurnIntentBridgeSource::Queue, + TurnIntentBridgeSource::ForceSend, + TurnIntentBridgeSource::Resume, + TurnIntentBridgeSource::AgentOrg, + TurnIntentBridgeSource::MobileRemote, + ] { + let result = super::super::send::send_message_impl( + &state, + "sdeagent-history".into(), + "Try to run".into(), + None, + IdentityOverrides::default(), + None, + None, + None, + false, + None, + None, + false, + None, + None, + None, + None, + None, + source, + None, + ) + .await; + assert!(matches!(result,Err(ref error) if error==READ_ONLY_ERROR)); + assert!( + state.get_session("sdeagent-history").await.is_none(), + "no Provider runtime may be registered" + ); + } + let registry = crate::tools::registry::ToolRegistry::new(); + let context = crate::tools::call_context::CallContext::new("attempt", "sdeagent-history"); + let direct = registry + .execute("run_shell", serde_json::json!({}), &context) + .await; + assert!(matches!(direct,Err(ref error) if error==READ_ONLY_ERROR)); + let policy = crate::tools::policy::ResolvedToolPolicy::permissive(); + let checked = registry + .execute_with_policy("run_shell", serde_json::json!({}), &policy, &context) + .await; + assert!(matches!(checked,Err(ref error) if error==READ_ONLY_ERROR)); + assert_eq!( + conn.query_row("SELECT COUNT(*) FROM agent_org_execution_runs", [], |r| r + .get::<_, i64>( + 0 + )) + .unwrap(), + 0 + ); +} diff --git a/src-tauri/crates/agent-core/src/state/commands/session/message/tests/pause_continuation_tests.rs b/src-tauri/crates/agent-core/src/state/commands/session/message/tests/pause_continuation_tests.rs index 8feb6ef6e4..ed47909e79 100644 --- a/src-tauri/crates/agent-core/src/state/commands/session/message/tests/pause_continuation_tests.rs +++ b/src-tauri/crates/agent-core/src/state/commands/session/message/tests/pause_continuation_tests.rs @@ -98,7 +98,7 @@ async fn released_pause_records_cancelled_execution_without_finishing_task() { TaskStatus::InProgress ); let idle_notices: i64 = conn.query_row( - "SELECT count(*) FROM agent_org_runtime_inbox WHERE org_run_id=?1 AND payload_kind='member_idle'", + "SELECT count(*) FROM agent_org_execution_inbox WHERE org_run_id=?1 AND payload_kind='member_idle'", [&fixture.run_id], |r| r.get(0), ).unwrap(); assert_eq!( @@ -139,14 +139,14 @@ fn pause_terminal_authority_requires_exact_released_runtime() { match invalid { "unbound" => { conn.execute( - "UPDATE agent_org_runtime_pause_handoffs SET runtime_lease_id=NULL,dialog_turn_generation=NULL", + "UPDATE agent_org_execution_pause_handoffs SET runtime_lease_id=NULL,dialog_turn_generation=NULL", [], ) .unwrap(); } "draining" => { conn.execute( - "UPDATE agent_org_runtime_pause_handoffs SET drain_status='waiting'", + "UPDATE agent_org_execution_pause_handoffs SET drain_status='waiting'", [], ) .unwrap(); @@ -223,10 +223,10 @@ fn pause_continuation_rejects_unclaimed_draining_and_obsolete_receipts() { .unwrap(); } if invalid == "draining" { - conn.execute("UPDATE agent_org_runtime_pause_handoffs SET drain_status='waiting' WHERE episode_id=?1", [&dispatch.episode_id]).unwrap(); + conn.execute("UPDATE agent_org_execution_pause_handoffs SET drain_status='waiting' WHERE episode_id=?1", [&dispatch.episode_id]).unwrap(); } if invalid == "obsolete" { - conn.execute("UPDATE agent_org_runtime_runs SET activation_generation=activation_generation+1 WHERE id=?1", [&fixture.run_id]).unwrap(); + conn.execute("UPDATE agent_org_execution_runs SET activation_generation=activation_generation+1 WHERE id=?1", [&fixture.run_id]).unwrap(); } let tx = conn.transaction().unwrap(); assert!( diff --git a/src-tauri/crates/agent-core/src/state/commands/session/org_tasks/context.rs b/src-tauri/crates/agent-core/src/state/commands/session/org_tasks/context.rs index 27a34e75a9..ff4e5b8b39 100644 --- a/src-tauri/crates/agent-core/src/state/commands/session/org_tasks/context.rs +++ b/src-tauri/crates/agent-core/src/state/commands/session/org_tasks/context.rs @@ -43,6 +43,8 @@ pub(super) async fn session_org_read_context( // durable identity in one blocking job instead of stalling Tokio's async // executor at every call site. tokio::task::spawn_blocking(move || -> Result, String> { + let conn = get_connection().map_err(|error| error.to_string())?; + crate::coordination::agent_org_history_store::require_writable(&conn, &session_id)?; let persisted = persistence::get_session(&session_id).map_err(|err| err.to_string())?; let member_id = match persisted.as_ref() { Some(record) => Some(record.org_member_id.clone()), diff --git a/src-tauri/crates/agent-core/src/state/commands/session/org_tasks/group_actions.rs b/src-tauri/crates/agent-core/src/state/commands/session/org_tasks/group_actions.rs index bc9a5ec04e..d25de82f96 100644 --- a/src-tauri/crates/agent-core/src/state/commands/session/org_tasks/group_actions.rs +++ b/src-tauri/crates/agent-core/src/state/commands/session/org_tasks/group_actions.rs @@ -225,7 +225,7 @@ fn remove_unadmitted_group_root_source_event_with_connection( let admitted: bool = tx .query_row( "SELECT EXISTS( - SELECT 1 FROM agent_org_runtime_turn_contexts + SELECT 1 FROM agent_org_execution_turn_contexts WHERE session_id=?1 AND turn_intent_id=?2 AND source_kind='group_root' AND source_id=?3 )", @@ -482,7 +482,7 @@ fn resolve_group_turn_with_connection( let mut stmt = conn .prepare( "SELECT session_id,turn_intent_id,source_kind - FROM agent_org_runtime_turn_contexts + FROM agent_org_execution_turn_contexts WHERE org_run_id=?1 AND turn_intent_id=?2 AND source_kind IN ('group_root','group_mention') ORDER BY context_id ASC @@ -528,7 +528,7 @@ fn prepare_group_root_cancellation_with_connection( .query_row( "SELECT intent.status FROM session_turn_intents intent - JOIN agent_org_runtime_turn_contexts context + JOIN agent_org_execution_turn_contexts context ON context.session_id=intent.session_id AND context.turn_intent_id=intent.turn_intent_id WHERE context.org_run_id=?1 AND context.session_id=?2 @@ -599,11 +599,11 @@ fn load_retry_envelope_with_connection( AND CAST(json_extract(reply.result_json,'$.agent_org_user_directed_reply.source_inbox_id') AS INTEGER)=CAST(context.source_id AS INTEGER) ) END - FROM agent_org_runtime_turn_contexts context + FROM agent_org_execution_turn_contexts context JOIN session_turn_intents intent ON intent.session_id=context.session_id AND intent.turn_intent_id=context.turn_intent_id - LEFT JOIN agent_org_runtime_user_directed_deliveries delivery + LEFT JOIN agent_org_execution_user_directed_deliveries delivery ON delivery.session_id=context.session_id AND delivery.turn_intent_id=context.turn_intent_id LEFT JOIN events event @@ -844,7 +844,7 @@ mod tests { updated_at TEXT NOT NULL, PRIMARY KEY(session_id,turn_intent_id) ); - CREATE TABLE agent_org_runtime_turn_contexts ( + CREATE TABLE agent_org_execution_turn_contexts ( context_id INTEGER PRIMARY KEY AUTOINCREMENT, session_id TEXT NOT NULL, turn_intent_id TEXT NOT NULL, @@ -854,7 +854,7 @@ mod tests { source_id TEXT NOT NULL, UNIQUE(session_id,turn_intent_id) ); - CREATE TABLE agent_org_runtime_user_directed_deliveries ( + CREATE TABLE agent_org_execution_user_directed_deliveries ( session_id TEXT NOT NULL, turn_intent_id TEXT NOT NULL, status TEXT NOT NULL, @@ -898,7 +898,7 @@ mod tests { ) .expect("insert Root intent"); conn.execute( - "INSERT INTO agent_org_runtime_turn_contexts ( + "INSERT INTO agent_org_execution_turn_contexts ( session_id,turn_intent_id,org_run_id,participant_id,source_kind,source_id ) VALUES ('session-root',?1,'run-actions','coordinator','group_root',?2)", params![turn_intent_id, source_id], @@ -1001,7 +1001,7 @@ mod tests { ) .expect("insert Member intent"); conn.execute( - "INSERT INTO agent_org_runtime_turn_contexts ( + "INSERT INTO agent_org_execution_turn_contexts ( session_id,turn_intent_id,org_run_id,participant_id,source_kind,source_id ) VALUES ('session-member','turn-member-retry','run-actions','reviewer', 'group_mention','42')", @@ -1009,7 +1009,7 @@ mod tests { ) .expect("insert Member context"); conn.execute( - "INSERT INTO agent_org_runtime_user_directed_deliveries ( + "INSERT INTO agent_org_execution_user_directed_deliveries ( session_id,turn_intent_id,status,dispatch_content,display_content,images_json ) VALUES ('session-member','turn-member-retry','cancelled', 'Member frozen body','@Reviewer visible body','[\"member-image\"]')", @@ -1168,7 +1168,7 @@ mod tests { assert_eq!(exact.session_id, "session-root"); conn.execute( - "INSERT INTO agent_org_runtime_turn_contexts ( + "INSERT INTO agent_org_execution_turn_contexts ( session_id,turn_intent_id,org_run_id,participant_id,source_kind,source_id ) VALUES ('session-member','unique-turn','run-actions','reviewer', 'group_mention','42')", diff --git a/src-tauri/crates/agent-core/src/state/commands/session/org_tasks/group_chat.rs b/src-tauri/crates/agent-core/src/state/commands/session/org_tasks/group_chat.rs index ff58affb70..26527d8cc6 100644 --- a/src-tauri/crates/agent-core/src/state/commands/session/org_tasks/group_chat.rs +++ b/src-tauri/crates/agent-core/src/state/commands/session/org_tasks/group_chat.rs @@ -361,7 +361,7 @@ pub(super) fn persist_group_chat_deliveries( .query_row( "SELECT EXISTS( - SELECT 1 FROM agent_org_runtime_turn_contexts context + SELECT 1 FROM agent_org_execution_turn_contexts context WHERE context.org_run_id=?1 AND context.turn_intent_id=?2 ) OR EXISTS( @@ -382,7 +382,7 @@ pub(super) fn persist_group_chat_deliveries( let pending: i64 = tx .query_row( "SELECT COUNT(*) - FROM agent_org_runtime_user_directed_deliveries + FROM agent_org_execution_user_directed_deliveries WHERE org_run_id=?1 AND dispatch_member_id=?2 AND status IN ('pending','started')", params![&context.run_id, &input.target_member_id], @@ -414,13 +414,22 @@ pub(super) fn persist_group_chat_deliveries( }, )?; tx.execute( - "UPDATE agent_org_runtime_inbox + "UPDATE agent_org_execution_inbox SET delivery_class='user_directed',display_text=?2 WHERE id=?1 AND delivery_class='formal_work'", params![inbox_row.id, effective_display], ) .map_err(|error| error.to_string())?; + crate::coordination::agent_org_history_store::mirror_visible_item( + &tx, + &context.run_id, + &inbox_row.id.to_string(), + "group_message", + effective_display, + &inbox_row.created_at, + ) + .map_err(|error| error.to_string())?; let admission = crate::coordination::agent_org_turn_contexts::AgentOrgTurnAdmission::group_mention( &context.run_id, @@ -483,7 +492,7 @@ pub(super) fn persist_group_chat_deliveries( fn validate_group_run_status(conn: &rusqlite::Connection, run_id: &str) -> Result<(), String> { let status: Option = conn .query_row( - "SELECT status FROM agent_org_runtime_runs WHERE id=?1", + "SELECT status FROM agent_org_execution_runs WHERE id=?1", [run_id], |row| row.get(0), ) @@ -515,7 +524,7 @@ fn resolve_group_target( ) -> Result<(String, String), String> { conn.query_row( "SELECT materialization.session_id,materialization.agent_id - FROM agent_org_runtime_member_materializations materialization + FROM agent_org_execution_member_materializations materialization JOIN agent_sessions session ON session.session_id=materialization.session_id WHERE materialization.org_run_id=?1 AND materialization.member_id=?2 @@ -525,7 +534,7 @@ fn resolve_group_target( AND session.status<>'archived' AND materialization.generation=( SELECT MAX(latest.generation) - FROM agent_org_runtime_member_materializations latest + FROM agent_org_execution_member_materializations latest WHERE latest.org_run_id=?1 AND latest.member_id=?2 AND latest.status='succeeded' ) @@ -563,7 +572,7 @@ fn load_existing_group_delivery( delivery.dispatch_member_id,delivery.member_dispatch_sequence, delivery.status,delivery.dispatch_content,delivery.display_content, delivery.images_json,delivery.source_kind - FROM agent_org_runtime_user_directed_deliveries delivery + FROM agent_org_execution_user_directed_deliveries delivery WHERE delivery.org_run_id=?1 AND delivery.turn_intent_id=?2", params![run_id, &input.turn_intent_id], |row| { @@ -644,7 +653,7 @@ fn load_inbox_record( "SELECT id,recipient_agent_id,recipient_member_id,sender_agent_id, sender_member_id,org_run_id,payload_kind,payload_json,request_id, created_at,read_at - FROM agent_org_runtime_inbox + FROM agent_org_execution_inbox WHERE id=?1 AND org_run_id=?2 AND delivery_class='user_directed'", params![inbox_id, run_id], |row| { diff --git a/src-tauri/crates/agent-core/src/state/commands/session/org_tasks/group_projection/tests.rs b/src-tauri/crates/agent-core/src/state/commands/session/org_tasks/group_projection/tests.rs index 235994e934..901a9d134b 100644 --- a/src-tauri/crates/agent-core/src/state/commands/session/org_tasks/group_projection/tests.rs +++ b/src-tauri/crates/agent-core/src/state/commands/session/org_tasks/group_projection/tests.rs @@ -172,7 +172,7 @@ fn projection_context() -> AgentOrgRunContext { fn seed_run(conn: &Connection) { let now = "2026-01-01T00:00:00Z"; conn.execute( - "INSERT INTO agent_org_runtime_runs ( + "INSERT INTO agent_org_execution_runs ( id,org_id,coordinator_agent_id,root_session_id,org_snapshot_json, entry_mode,status,created_at,updated_at ) VALUES ('run-projection','org-projection','agent-coordinator', @@ -206,7 +206,7 @@ fn seed_initial_exchange(conn: &Connection) { ) .expect("insert initial intent"); conn.execute( - "INSERT INTO agent_org_runtime_initial_inputs ( + "INSERT INTO agent_org_execution_initial_inputs ( org_run_id,turn_intent_id,message_id,content,payload_json,status,created_at,updated_at ) VALUES ('run-projection','turn-initial','message-initial','Build the Team result', '{}','dispatched','2026-01-01T00:00:00Z','2026-01-01T00:00:00Z')", @@ -232,7 +232,7 @@ fn seed_initial_exchange(conn: &Connection) { fn seed_task_activity(conn: &Connection) { conn.execute( - "INSERT INTO agent_org_runtime_tasks ( + "INSERT INTO agent_org_execution_tasks ( id,org_run_id,activation_generation,subject,description,owner,status, execution_mode,blocked_by_json,output_json,created_by_participant_id, source_turn_intent_id,created_at,updated_at @@ -243,7 +243,7 @@ fn seed_task_activity(conn: &Connection) { ) .expect("insert task"); conn.execute_batch( - "INSERT INTO agent_org_runtime_task_events ( + "INSERT INTO agent_org_execution_task_events ( id,org_run_id,task_id,event_type,previous_owner,next_owner, previous_status,next_status,actor_member_id,actor_kind,source_turn_intent_id,created_at ) VALUES @@ -327,7 +327,7 @@ fn task_lifecycle_is_merged_into_the_same_public_timeline() { fn seed_team_lifecycle(conn: &Connection) { let digest = "a".repeat(64); conn.execute( - "INSERT INTO agent_org_runtime_pause_episodes ( + "INSERT INTO agent_org_execution_pause_episodes ( episode_id,org_run_id,pause_request_id,pause_generation,status, resume_request_id,resume_generation,teardown_owner_id,created_at,updated_at,resumed_at ) VALUES ('pause-1','run-projection','pause-request-1',2,'consumed', @@ -337,7 +337,7 @@ fn seed_team_lifecycle(conn: &Connection) { ) .expect("insert pause/resume episode"); conn.execute( - "INSERT INTO agent_org_runtime_member_interventions ( + "INSERT INTO agent_org_execution_member_interventions ( intervention_receipt_id,org_run_id,member_id,agent_id,session_id,status, source_event_id,entered_at,last_user_activity_at,return_request_id, return_outcome,cleared_revision,cleared_at,updated_at @@ -349,7 +349,7 @@ fn seed_team_lifecycle(conn: &Connection) { ) .expect("insert member Return receipt"); conn.execute( - "INSERT INTO agent_org_runtime_run_completion_certificates ( + "INSERT INTO agent_org_execution_run_completion_certificates ( id,org_run_id,activation_generation,work_revision,request_id,request_digest, outcome,summary,coordinator_session_id,coordinator_turn_intent_id, evidence_task_ids_json,closure_task_ids_json,task_output_refs_json, @@ -370,7 +370,7 @@ fn seed_team_lifecycle(conn: &Connection) { ) .expect("insert final report event"); conn.execute( - "INSERT INTO agent_org_runtime_final_summary_receipts ( + "INSERT INTO agent_org_execution_final_summary_receipts ( receipt_id,org_run_id,activation_generation,certificate_id,evidence_digest, attempt,status,coordinator_session_id,turn_intent_id,started_at,terminal_at, event_id,created_at,updated_at @@ -382,7 +382,7 @@ fn seed_team_lifecycle(conn: &Connection) { ) .expect("insert persisted final report receipt"); conn.execute( - "INSERT INTO agent_org_runtime_final_summary_receipts ( + "INSERT INTO agent_org_execution_final_summary_receipts ( receipt_id,org_run_id,activation_generation,certificate_id,evidence_digest, attempt,status,coordinator_session_id,turn_intent_id,retry_request_id, started_at,terminal_at,typed_error,created_at,updated_at @@ -394,7 +394,7 @@ fn seed_team_lifecycle(conn: &Connection) { ) .expect("insert failed final report receipt"); conn.execute( - "INSERT INTO agent_org_runtime_archive_episodes ( + "INSERT INTO agent_org_execution_archive_episodes ( archive_receipt_id,org_run_id,archive_request_id,archive_generation, teardown_status,deadline_at,archived_at,updated_at,quiesced_at ) VALUES ('archive-1','run-projection','archive-request-1',4,'quiesced', @@ -454,7 +454,7 @@ fn cursor_v2_pages_identical_timestamps_without_duplicates() { seed_run(&conn); seed_task_activity(&conn); conn.execute( - "UPDATE agent_org_runtime_task_events SET created_at='2026-01-01T00:00:03Z'", + "UPDATE agent_org_execution_task_events SET created_at='2026-01-01T00:00:03Z'", [], ) .expect("align fixture timestamps"); @@ -535,7 +535,7 @@ fn public_timeline_p90_stays_bounded_for_fifty_members_and_ten_thousand_events() context_index % 60 ); conn.execute( - "INSERT INTO agent_org_runtime_inbox ( + "INSERT INTO agent_org_execution_inbox ( delivery_class,recipient_agent_id,recipient_member_id,sender_agent_id, org_run_id,payload_kind,payload_json,created_at ) VALUES ('user_directed',?1,?2,'_user','run-projection','plain',?3,?4)", @@ -562,7 +562,7 @@ fn public_timeline_p90_stays_bounded_for_fifty_members_and_ten_thousand_events() ) .expect("insert performance Turn intent"); conn.execute( - "INSERT INTO agent_org_runtime_turn_contexts ( + "INSERT INTO agent_org_execution_turn_contexts ( session_id,turn_intent_id,org_run_id,participant_id,turn_kind, dispatch_member_id,member_dispatch_sequence,source_kind,source_id, root_authority_turn_id,actor_version,created_at diff --git a/src-tauri/crates/agent-core/src/state/commands/session/org_tasks/group_projection/timeline.rs b/src-tauri/crates/agent-core/src/state/commands/session/org_tasks/group_projection/timeline.rs index efd53f9fa1..34f9bdc6a8 100644 --- a/src-tauri/crates/agent-core/src/state/commands/session/org_tasks/group_projection/timeline.rs +++ b/src-tauri/crates/agent-core/src/state/commands/session/org_tasks/group_projection/timeline.rs @@ -242,7 +242,7 @@ fn resolve_context(conn: &Connection, session_id: &str) -> Result Result, String> { + tokio::task::spawn_blocking(move || { + let conn = database::db::get_connection().map_err(|e| e.to_string())?; + agent_org_history_store::descriptor(&conn, &session_id).map_err(|e| e.to_string()) + }) + .await + .map_err(|e| e.to_string())? +} + +#[tauri::command] +pub async fn agent_org_history_page( + session_id: String, + cursor: Option, + limit: usize, +) -> Result { + tokio::task::spawn_blocking(move || { + let conn = database::db::get_connection().map_err(|e| e.to_string())?; + agent_org_history_store::page(&conn, &session_id, cursor.as_deref(), limit) + }) + .await + .map_err(|e| e.to_string())? +} diff --git a/src-tauri/crates/agent-core/src/state/commands/session/org_tasks/history_provenance_tests.rs b/src-tauri/crates/agent-core/src/state/commands/session/org_tasks/history_provenance_tests.rs index 85059f5317..cbbe6e097e 100644 --- a/src-tauri/crates/agent-core/src/state/commands/session/org_tasks/history_provenance_tests.rs +++ b/src-tauri/crates/agent-core/src/state/commands/session/org_tasks/history_provenance_tests.rs @@ -45,7 +45,7 @@ fn materialize(id: i64, session: &str, message: &str) { get_connection() .unwrap() .execute( - "INSERT INTO agent_org_runtime_inbox_materializations + "INSERT INTO agent_org_execution_inbox_materializations (inbox_id,session_id,transcript_message_id,transcript_intent_id,materialized_at) VALUES (?1,?2,?3,'stable-message-identity',?4)", params![id, session, message, chrono::Utc::now().to_rfc3339()], @@ -140,12 +140,12 @@ fn summary_source_requires_its_real_receipt_and_survives_terminal_status() { ); let conn = get_connection().unwrap(); let now = chrono::Utc::now().to_rfc3339(); - conn.execute("INSERT INTO agent_org_runtime_run_completion_certificates( + conn.execute("INSERT INTO agent_org_execution_run_completion_certificates( id,org_run_id,activation_generation,work_revision,request_id,request_digest,outcome,summary, coordinator_session_id,coordinator_turn_intent_id,evidence_task_ids_json,closure_task_ids_json, task_output_refs_json,resolution_links_json,validator_version,created_at) VALUES ('certificate',?1,1,1,'request',?2,'delivered','done','root-shared-agent','root','[]','[]','[]','[]',1,?3)", params![context.run_id, "a".repeat(64), now]).unwrap(); - conn.execute("INSERT INTO agent_org_runtime_final_summary_receipts( + conn.execute("INSERT INTO agent_org_execution_final_summary_receipts( receipt_id,org_run_id,activation_generation,certificate_id,evidence_digest,attempt,status, coordinator_session_id,turn_intent_id,started_at,terminal_at,typed_error,created_at,updated_at) VALUES ('summary',?1,1,'certificate',?2,1,'failed','root-shared-agent','root',?3,?3,'stopped',?3,?3)", params![context.run_id, "b".repeat(64), now]).unwrap(); @@ -208,14 +208,14 @@ fn coordinator_mail_wake_uses_its_trigger_receipt_without_relabeling_user_input( AgentOrgInputSource::UserInput ); conn.execute("UPDATE session_turn_intents SET source='resume',status='completed' WHERE turn_intent_id='root'", []).unwrap(); - conn.execute("UPDATE agent_org_runtime_formal_trigger_attempts SET status='resolved' WHERE turn_intent_id='root'", []).unwrap(); + conn.execute("UPDATE agent_org_execution_formal_trigger_attempts SET status='resolved' WHERE turn_intent_id='root'", []).unwrap(); assert_eq!( execution("root-shared-agent", "root").unwrap().source_kind, AgentOrgInputSource::MemberMessages ); let now = chrono::Utc::now().to_rfc3339(); conn.execute( - "INSERT INTO agent_org_runtime_initial_inputs ( + "INSERT INTO agent_org_execution_initial_inputs ( org_run_id,turn_intent_id,message_id,content,payload_json,status,created_at,updated_at) VALUES (?1,'root','initial-input','User request','{}','dispatched',?2,?2)", params![context.run_id, now], diff --git a/src-tauri/crates/agent-core/src/state/commands/session/org_tasks/lifecycle.rs b/src-tauri/crates/agent-core/src/state/commands/session/org_tasks/lifecycle.rs index fdbac4f8ce..9add24eee7 100644 --- a/src-tauri/crates/agent-core/src/state/commands/session/org_tasks/lifecycle.rs +++ b/src-tauri/crates/agent-core/src/state/commands/session/org_tasks/lifecycle.rs @@ -264,7 +264,7 @@ async fn teardown_archive_receipt(state: &AgentAppState, receipt_id: &str) -> Re let conn = database::db::get_connection().map_err(|error| error.to_string())?; let run_id: String = conn .query_row( - "SELECT org_run_id FROM agent_org_runtime_archive_episodes + "SELECT org_run_id FROM agent_org_execution_archive_episodes WHERE archive_receipt_id=?1", [&summary_receipt_id], |row| row.get(0), diff --git a/src-tauri/crates/agent-core/src/state/commands/session/org_tasks/mod.rs b/src-tauri/crates/agent-core/src/state/commands/session/org_tasks/mod.rs index a23799f0a1..b1af91b149 100644 --- a/src-tauri/crates/agent-core/src/state/commands/session/org_tasks/mod.rs +++ b/src-tauri/crates/agent-core/src/state/commands/session/org_tasks/mod.rs @@ -24,6 +24,7 @@ mod group_actions; mod group_chat; mod group_projection; mod handoff; +mod history; mod intervention; mod lifecycle; mod plan_approval; @@ -40,6 +41,7 @@ pub use group_actions::*; pub use group_chat::*; pub use group_projection::*; pub use handoff::*; +pub use history::*; pub use intervention::*; pub use lifecycle::*; pub use plan_approval::*; diff --git a/src-tauri/crates/agent-core/src/state/commands/session/org_tasks/rejected_request_draft.rs b/src-tauri/crates/agent-core/src/state/commands/session/org_tasks/rejected_request_draft.rs index 4c1fb70214..396e1172b0 100644 --- a/src-tauri/crates/agent-core/src/state/commands/session/org_tasks/rejected_request_draft.rs +++ b/src-tauri/crates/agent-core/src/state/commands/session/org_tasks/rejected_request_draft.rs @@ -55,7 +55,7 @@ fn load_rejected_request_draft_with_connection( let source: Option<(String, String)> = conn .query_row( "SELECT source_kind,source_id - FROM agent_org_runtime_turn_contexts + FROM agent_org_execution_turn_contexts WHERE org_run_id=?1 AND session_id=?2 AND turn_intent_id=?3 AND turn_kind='coordinator' AND participant_id='coordinator' AND source_kind IN ('root_turn','group_root')", @@ -71,7 +71,7 @@ fn load_rejected_request_draft_with_connection( let mut statement = conn .prepare( "SELECT result_text - FROM agent_org_runtime_tool_call_receipts + FROM agent_org_execution_tool_call_receipts WHERE org_run_id=?1 AND session_id=?2 AND turn_intent_id=?3 AND tool_name IN ('task_create','task_graph_create') AND result_text IS NOT NULL @@ -178,11 +178,11 @@ mod tests { fn fixture() -> Connection { let conn = Connection::open_in_memory().expect("in-memory database"); conn.execute_batch( - "CREATE TABLE agent_org_runtime_turn_contexts( + "CREATE TABLE agent_org_execution_turn_contexts( org_run_id TEXT,session_id TEXT,turn_intent_id TEXT, turn_kind TEXT,participant_id TEXT,source_kind TEXT,source_id TEXT ); - CREATE TABLE agent_org_runtime_tool_call_receipts( + CREATE TABLE agent_org_execution_tool_call_receipts( org_run_id TEXT,session_id TEXT,turn_intent_id TEXT,call_id TEXT, tool_name TEXT,result_text TEXT,created_at TEXT ); @@ -190,10 +190,10 @@ mod tests { id TEXT,session_id TEXT,function_name TEXT,result_json TEXT, meta_json TEXT,history_sequence INTEGER ); - INSERT INTO agent_org_runtime_turn_contexts VALUES( + INSERT INTO agent_org_execution_turn_contexts VALUES( 'run','session','turn','coordinator','coordinator','root_turn','turn' ); - INSERT INTO agent_org_runtime_tool_call_receipts VALUES( + INSERT INTO agent_org_execution_tool_call_receipts VALUES( 'run','session','turn','call','task_create', '{\"created\":false,\"requires_episode_resolution\":true,\"rejected_request_turn_intent_id\":\"turn\"}', 'now' @@ -219,7 +219,7 @@ mod tests { assert_eq!(draft.turn_intent_id, "turn"); conn.execute( - "UPDATE agent_org_runtime_tool_call_receipts + "UPDATE agent_org_execution_tool_call_receipts SET result_text=replace(result_text,'\"turn\"','\"other-turn\"')", [], ) diff --git a/src-tauri/crates/agent-core/src/state/commands/session/org_tasks/resource_teardown_tests.rs b/src-tauri/crates/agent-core/src/state/commands/session/org_tasks/resource_teardown_tests.rs index 150febb7ba..8f364655b6 100644 --- a/src-tauri/crates/agent-core/src/state/commands/session/org_tasks/resource_teardown_tests.rs +++ b/src-tauri/crates/agent-core/src/state/commands/session/org_tasks/resource_teardown_tests.rs @@ -35,7 +35,7 @@ async fn verify_task_resource_teardown(intervention: bool) { }) .unwrap() }); - conn.execute("INSERT INTO agent_org_runtime_tasks ( + conn.execute("INSERT INTO agent_org_execution_tasks ( id,org_run_id,activation_generation,subject,description,owner,status,execution_mode, blocked_by_json,created_by_participant_id,source_turn_intent_id,created_at,updated_at,output_json ) VALUES (?1,?2,1,?1,'service','member-planner',?3,'build','[]','coordinator','seed',?4,?4, @@ -85,7 +85,7 @@ async fn verify_task_resource_teardown(intervention: bool) { runtime_lease_id: "newer-lease".into(), dialog_turn_generation: "newer-generation".into(), }; - conn.execute("INSERT INTO agent_org_runtime_member_interventions ( + conn.execute("INSERT INTO agent_org_execution_member_interventions ( intervention_receipt_id,org_run_id,member_id,agent_id,session_id,status,source_event_id, original_task_id,original_turn_intent_id,runtime_lease_id,dialog_turn_generation, entered_at,last_user_activity_at,updated_at diff --git a/src-tauri/crates/agent-core/src/state/commands/session/org_tasks/run_view.rs b/src-tauri/crates/agent-core/src/state/commands/session/org_tasks/run_view.rs index 8388a7418f..707b6a405b 100644 --- a/src-tauri/crates/agent-core/src/state/commands/session/org_tasks/run_view.rs +++ b/src-tauri/crates/agent-core/src/state/commands/session/org_tasks/run_view.rs @@ -322,7 +322,7 @@ pub(super) fn build_agent_org_run_view( "SELECT COALESCE(SUM(CASE WHEN status='failed' THEN 1 ELSE 0 END),0), COALESCE(SUM(CASE WHEN status='cancelled' THEN 1 ELSE 0 END),0) - FROM agent_org_runtime_tasks WHERE org_run_id=?1", + FROM agent_org_execution_tasks WHERE org_run_id=?1", params![&context.run_id], |row| Ok((row.get(0)?, row.get(1)?)), ) @@ -585,12 +585,12 @@ pub(super) fn load_task_state_window( "SELECT task.id,task.status,task.owner,task.activation_generation, task.replaces_task_id, (SELECT replacement.id - FROM agent_org_runtime_tasks replacement + FROM agent_org_execution_tasks replacement WHERE replacement.org_run_id=task.org_run_id AND replacement.replaces_task_id=task.id ORDER BY replacement.created_at,replacement.id LIMIT 1), task.updated_at - FROM agent_org_runtime_tasks task + FROM agent_org_execution_tasks task WHERE task.org_run_id=?1 ORDER BY task.updated_at DESC,task.id LIMIT ?2", @@ -673,7 +673,7 @@ pub(super) fn latest_coordinator_is_waiting_for_org_event( "SELECT COALESCE(( SELECT context.terminal_reason='waiting_for_org_event' AND intent.status IN ('completed','failed','cancelled','abandoned') - FROM agent_org_runtime_turn_contexts context + FROM agent_org_execution_turn_contexts context JOIN session_turn_intents intent ON intent.session_id=context.session_id AND intent.turn_intent_id=context.turn_intent_id @@ -831,7 +831,7 @@ fn task_counts_by_owner_with_connection( COALESCE(SUM(CASE WHEN status='pending' THEN 1 ELSE 0 END), 0), COALESCE(SUM(CASE WHEN status='in_progress' THEN 1 ELSE 0 END), 0), COALESCE(SUM(CASE WHEN status='completed' THEN 1 ELSE 0 END), 0) - FROM agent_org_runtime_tasks + FROM agent_org_execution_tasks WHERE org_run_id=?1 AND owner IS NOT NULL GROUP BY owner", ) diff --git a/src-tauri/crates/agent-core/src/state/commands/session/org_tasks/tests.rs b/src-tauri/crates/agent-core/src/state/commands/session/org_tasks/tests.rs index 97676b48ea..dd9d3179a9 100644 --- a/src-tauri/crates/agent-core/src/state/commands/session/org_tasks/tests.rs +++ b/src-tauri/crates/agent-core/src/state/commands/session/org_tasks/tests.rs @@ -65,6 +65,7 @@ fn prepare_command_run(status: &str) -> AgentOrgRunContext { let context = context_with_shared_member_agent_id(); let conn = get_connection().expect("db connection"); crate::foundation::persistence::test_schema::ensure_agent_sessions_schema(&conn); + crate::foundation::persistence::test_schema::ensure_session_events_schema(&conn); conn.execute_batch( "CREATE TABLE IF NOT EXISTS session_turn_intents ( session_id TEXT NOT NULL, @@ -82,7 +83,7 @@ fn prepare_command_run(status: &str) -> AgentOrgRunContext { crate::coordination::init_agent_org_schemas(&conn).expect("complete Agent Org schemas"); let now = chrono::Utc::now().to_rfc3339(); conn.execute( - "INSERT INTO agent_org_runtime_runs ( + "INSERT INTO agent_org_execution_runs ( id, org_id, coordinator_agent_id, root_session_id, org_snapshot_json, entry_mode, status, work_item_id, project_slug, routine_fire_id, summary, last_error, @@ -109,7 +110,7 @@ fn inbox_count_for_member(context: &AgentOrgRunContext, member_id: &str) -> usiz let conn = get_connection().expect("db connection"); let count: i64 = conn .query_row( - "SELECT COUNT(*) FROM agent_org_runtime_inbox + "SELECT COUNT(*) FROM agent_org_execution_inbox WHERE org_run_id=?1 AND recipient_member_id=?2", params![&context.run_id, member_id], |row| row.get(0), @@ -203,7 +204,7 @@ fn seed_pause_turn_context( other => panic!("unknown test Turn kind {other}"), }; conn.execute( - "INSERT INTO agent_org_runtime_turn_contexts ( + "INSERT INTO agent_org_execution_turn_contexts ( session_id,turn_intent_id,org_run_id,participant_id,turn_kind,task_id, owner_member_id,dispatch_member_id,member_dispatch_sequence,source_kind, source_id,root_authority_turn_id,actor_version,activation_generation,created_at @@ -284,7 +285,7 @@ fn configure_pause_resume_authority(conn: &rusqlite::Connection, context: &Agent member_communication_links: Vec::new(), }; conn.execute( - "UPDATE agent_org_runtime_runs SET org_snapshot_json=?2 WHERE id=?1", + "UPDATE agent_org_execution_runs SET org_snapshot_json=?2 WHERE id=?1", params![ &context.run_id, serde_json::to_string(&snapshot).expect("serialize test snapshot") @@ -311,7 +312,7 @@ fn configure_pause_resume_authority(conn: &rusqlite::Connection, context: &Agent .expect("seed canonical materialized Agent session"); } conn.execute( - "INSERT INTO agent_org_runtime_member_materializations ( + "INSERT INTO agent_org_execution_member_materializations ( org_run_id,member_id,agent_id,generation,session_id,authority_class, status,created_at,updated_at ) VALUES (?1,?2,?3,1,?4,'formal','succeeded',?5,?5)", @@ -325,7 +326,7 @@ fn configure_pause_resume_authority(conn: &rusqlite::Connection, context: &Agent ) .expect("materialize coordinator"); conn.execute( - "INSERT INTO agent_org_runtime_member_materializations ( + "INSERT INTO agent_org_execution_member_materializations ( org_run_id,member_id,agent_id,generation,session_id,authority_class, status,created_at,updated_at ) VALUES (?1,'member-planner','builtin:sde',1,'planner-session','formal', @@ -334,7 +335,7 @@ fn configure_pause_resume_authority(conn: &rusqlite::Connection, context: &Agent ) .expect("materialize planner"); conn.execute( - "INSERT INTO agent_org_runtime_member_materializations ( + "INSERT INTO agent_org_execution_member_materializations ( org_run_id,member_id,agent_id,generation,session_id,authority_class, status,created_at,updated_at ) VALUES (?1,'member-builder','builtin:sde',1,'builder-session','formal', @@ -368,9 +369,9 @@ fn group_chat_member_delivery_has_exact_udw_authority() { let (delivery_class, turn_kind, source_kind): (String, String, String) = conn .query_row( "SELECT inbox.delivery_class,context.turn_kind,context.source_kind - FROM agent_org_runtime_user_directed_deliveries delivery - JOIN agent_org_runtime_inbox inbox ON inbox.id=delivery.source_inbox_id - JOIN agent_org_runtime_turn_contexts context + FROM agent_org_execution_user_directed_deliveries delivery + JOIN agent_org_execution_inbox inbox ON inbox.id=delivery.source_inbox_id + JOIN agent_org_execution_turn_contexts context ON context.session_id=delivery.session_id AND context.turn_intent_id=delivery.turn_intent_id WHERE delivery.turn_intent_id='group-turn-planner'", @@ -421,7 +422,7 @@ fn group_delivery_is_atomic_idempotent_and_conflict_safe() { assert!(error.contains("group_idempotency_mixed"), "{error}"); let mixed_new_count: i64 = conn .query_row( - "SELECT COUNT(*) FROM agent_org_runtime_turn_contexts + "SELECT COUNT(*) FROM agent_org_execution_turn_contexts WHERE turn_intent_id='atomic-builder-mixed'", [], |row| row.get(0), @@ -560,11 +561,11 @@ fn concurrent_exact_group_replays_commit_one_batch() { let (inbox_count, delivery_count, context_count): (i64, i64, i64) = conn .query_row( "SELECT - (SELECT COUNT(*) FROM agent_org_runtime_inbox + (SELECT COUNT(*) FROM agent_org_execution_inbox WHERE org_run_id=?1 AND delivery_class='user_directed'), - (SELECT COUNT(*) FROM agent_org_runtime_user_directed_deliveries + (SELECT COUNT(*) FROM agent_org_execution_user_directed_deliveries WHERE org_run_id=?1), - (SELECT COUNT(*) FROM agent_org_runtime_turn_contexts + (SELECT COUNT(*) FROM agent_org_execution_turn_contexts WHERE org_run_id=?1 AND turn_kind='user_directed_work')", [&context.run_id], |row| Ok((row.get(0)?, row.get(1)?, row.get(2)?)), @@ -757,8 +758,8 @@ fn formal_drain_never_claims_group_udw_and_udw_claims_only_its_source() { let (formal_read_at, group_read_at): (Option, Option) = conn .query_row( "SELECT - (SELECT read_at FROM agent_org_runtime_inbox WHERE id=?1), - (SELECT read_at FROM agent_org_runtime_inbox WHERE id=?2)", + (SELECT read_at FROM agent_org_execution_inbox WHERE id=?1), + (SELECT read_at FROM agent_org_execution_inbox WHERE id=?2)", params![formal.id, group[0].inbox_row.id], |row| Ok((row.get(0)?, row.get(1)?)), ) @@ -838,7 +839,7 @@ fn udw_recovery_is_keyset_bounded_and_never_replays_started_work() { let (delivery_status, intent_status): (String, String) = conn .query_row( "SELECT delivery.status,intent.status - FROM agent_org_runtime_user_directed_deliveries delivery + FROM agent_org_execution_user_directed_deliveries delivery JOIN session_turn_intents intent ON intent.session_id=delivery.session_id AND intent.turn_intent_id=delivery.turn_intent_id @@ -851,7 +852,7 @@ fn udw_recovery_is_keyset_bounded_and_never_replays_started_work() { assert_eq!(intent_status, "failed"); conn.execute( - "UPDATE agent_org_runtime_runs SET status='archived',archived_at=?2, + "UPDATE agent_org_execution_runs SET status='archived',archived_at=?2, archive_receipt_id='recovery-archive' WHERE id=?1", params![&context.run_id, chrono::Utc::now().to_rfc3339()], @@ -924,7 +925,7 @@ fn interrupted_udw_classification_is_keyset_bounded_across_pages() { let (unknown_deliveries, failed_intents): (i64, i64) = conn .query_row( "SELECT - (SELECT COUNT(*) FROM agent_org_runtime_user_directed_deliveries + (SELECT COUNT(*) FROM agent_org_execution_user_directed_deliveries WHERE turn_intent_id LIKE 'started-page-%' AND status='unknown'), (SELECT COUNT(*) FROM session_turn_intents WHERE turn_intent_id LIKE 'started-page-%' AND status='failed')", @@ -1113,7 +1114,7 @@ fn coordinator_work_state_uses_only_the_latest_current_generation_turn() { }, ); conn.execute( - "UPDATE agent_org_runtime_turn_contexts + "UPDATE agent_org_execution_turn_contexts SET terminal_reason='waiting_for_org_event' WHERE turn_intent_id='coordinator-waiting-old'", [], @@ -1143,7 +1144,7 @@ fn coordinator_work_state_uses_only_the_latest_current_generation_turn() { ); conn.execute( - "UPDATE agent_org_runtime_turn_contexts + "UPDATE agent_org_execution_turn_contexts SET terminal_reason='waiting_for_org_event' WHERE turn_intent_id='coordinator-finished-new'", [], @@ -1158,6 +1159,7 @@ fn coordinator_work_state_uses_only_the_latest_current_generation_turn() { fn ensure_run_view_runtime_schema() { let conn = get_connection().expect("db connection"); crate::foundation::persistence::test_schema::ensure_agent_sessions_schema(&conn); + crate::foundation::persistence::test_schema::ensure_session_events_schema(&conn); crate::foundation::persistence::session_snapshots::ensure_tables_with(&conn) .expect("session snapshot schema"); crate::session::persistence::init(&conn).expect("session schema"); @@ -1211,7 +1213,7 @@ fn assert_run_view_is_a_pure_read(status: &str) { .expect("read data version"); let before_updated_at: String = observer .query_row( - "SELECT updated_at FROM agent_org_runtime_runs WHERE id=?1", + "SELECT updated_at FROM agent_org_execution_runs WHERE id=?1", [&context.run_id], |row| row.get(0), ) @@ -1225,7 +1227,7 @@ fn assert_run_view_is_a_pure_read(status: &str) { .expect("read data version after Run View"); let after_updated_at: String = observer .query_row( - "SELECT updated_at FROM agent_org_runtime_runs WHERE id=?1", + "SELECT updated_at FROM agent_org_execution_runs WHERE id=?1", [&context.run_id], |row| row.get(0), ) @@ -1362,7 +1364,7 @@ fn run_view_marks_historical_unbound_coordinator_task_message_as_repairable() { }; let conn = get_connection().expect("db connection"); conn.execute( - "UPDATE agent_org_runtime_runs SET org_snapshot_json=?2 WHERE id=?1", + "UPDATE agent_org_execution_runs SET org_snapshot_json=?2 WHERE id=?1", params![ &context.run_id, serde_json::to_string(&snapshot).expect("snapshot json") @@ -1433,7 +1435,7 @@ fn task_state_window_projects_current_identity_owner_generation_and_replacement( let conn = get_connection().expect("db connection"); let now = "2026-09-06T00:00:00Z"; conn.execute_batch(&format!( - "INSERT INTO agent_org_runtime_tasks ( + "INSERT INTO agent_org_execution_tasks ( id,org_run_id,activation_generation,subject,description,owner,status, execution_mode,blocked_by_json,created_by_participant_id, source_turn_intent_id,created_at,updated_at @@ -1441,7 +1443,7 @@ fn task_state_window_projects_current_identity_owner_generation_and_replacement( 'task-original','{run_id}',1,'Original','',NULL,'pending','build','[]', 'coordinator','turn-create','{now}','{now}' ); - INSERT INTO agent_org_runtime_tasks ( + INSERT INTO agent_org_execution_tasks ( id,org_run_id,activation_generation,subject,description,owner,status, execution_mode,blocked_by_json,created_by_participant_id, source_turn_intent_id,replaces_task_id,created_at,updated_at @@ -1519,7 +1521,7 @@ fn run_view_projects_only_active_interventions_and_distinguishes_formal_handoffs let conn = get_connection().expect("db connection"); let now = "2026-08-26T00:00:00Z"; conn.execute( - "INSERT INTO agent_org_runtime_member_interventions ( + "INSERT INTO agent_org_execution_member_interventions ( intervention_receipt_id,org_run_id,member_id,agent_id,session_id, status,source_event_id,entered_at,last_user_activity_at,updated_at ) VALUES ('receipt-side-quest',?1,'member-planner','builtin:sde', @@ -1528,7 +1530,7 @@ fn run_view_projects_only_active_interventions_and_distinguishes_formal_handoffs ) .expect("insert nonbusy direct receipt"); conn.execute( - "INSERT INTO agent_org_runtime_member_interventions ( + "INSERT INTO agent_org_execution_member_interventions ( intervention_receipt_id,org_run_id,member_id,agent_id,session_id, status,source_event_id,original_task_id,original_turn_intent_id, entered_at,last_user_activity_at,updated_at @@ -1561,7 +1563,7 @@ fn run_view_projects_only_active_interventions_and_distinguishes_formal_handoffs ) .expect("insert direct base Turn"); conn.execute( - "INSERT INTO agent_org_runtime_member_intervention_turns ( + "INSERT INTO agent_org_execution_member_intervention_turns ( intervention_receipt_id,session_id,turn_intent_id,source_event_id, dispatch_content,display_content,member_dispatch_sequence, chain_position,status,enqueued_at,started_at @@ -1777,7 +1779,7 @@ fn archived_group_message_writes_neither_inbox_nor_intervention_clear() { }) .expect("enter intervention"); conn.execute( - "UPDATE agent_org_runtime_runs + "UPDATE agent_org_execution_runs SET status='archived',activation_generation=activation_generation+1, archived_at=?2,archive_receipt_id=?3 WHERE id=?1", @@ -1857,7 +1859,7 @@ fn ordinary_group_message_is_not_a_formal_lifecycle_trigger() { let receipt_count: i64 = conn .query_row( "SELECT COUNT(*) - FROM agent_org_runtime_formal_trigger_receipts + FROM agent_org_execution_formal_trigger_receipts WHERE org_run_id=?1 AND inbox_id=?2", params![&context.run_id, rows[0].inbox_row.id], |db_row| db_row.get(0), @@ -2043,8 +2045,8 @@ fn concurrent_pause_and_resume_requests_advance_each_episode_once() { let final_state: (String, i64, i64) = conn .query_row( "SELECT status,activation_generation, - (SELECT COUNT(*) FROM agent_org_runtime_pause_episodes WHERE org_run_id=?1) - FROM agent_org_runtime_runs WHERE id=?1", + (SELECT COUNT(*) FROM agent_org_execution_pause_episodes WHERE org_run_id=?1) + FROM agent_org_execution_runs WHERE id=?1", [&run_id], |row| Ok((row.get(0)?, row.get(1)?, row.get(2)?)), ) @@ -2059,7 +2061,7 @@ fn pause_run_update_failure_writes_no_episode_or_handoff() { let conn = get_connection().expect("db connection"); conn.execute_batch( "CREATE TRIGGER reject_pause_run_update - BEFORE UPDATE ON agent_org_runtime_runs + BEFORE UPDATE ON agent_org_execution_runs WHEN OLD.status='running' AND NEW.status='paused' BEGIN SELECT RAISE(ABORT, 'injected pause run update failure'); END;", ) @@ -2076,9 +2078,9 @@ fn pause_run_update_failure_writes_no_episode_or_handoff() { let state: (String, i64, i64, i64) = conn .query_row( "SELECT status,activation_generation, - (SELECT COUNT(*) FROM agent_org_runtime_pause_episodes WHERE org_run_id=?1), - (SELECT COUNT(*) FROM agent_org_runtime_pause_handoffs WHERE org_run_id=?1) - FROM agent_org_runtime_runs WHERE id=?1", + (SELECT COUNT(*) FROM agent_org_execution_pause_episodes WHERE org_run_id=?1), + (SELECT COUNT(*) FROM agent_org_execution_pause_handoffs WHERE org_run_id=?1) + FROM agent_org_execution_runs WHERE id=?1", [&context.run_id], |row| Ok((row.get(0)?, row.get(1)?, row.get(2)?, row.get(3)?)), ) @@ -2093,14 +2095,14 @@ fn pause_episode_insert_failure_rolls_back_status_generation_and_episode() { let conn = get_connection().expect("db connection"); let original_generation: i64 = conn .query_row( - "SELECT activation_generation FROM agent_org_runtime_runs WHERE id=?1", + "SELECT activation_generation FROM agent_org_execution_runs WHERE id=?1", params![&context.run_id], |row| row.get(0), ) .expect("original generation"); conn.execute_batch( "CREATE TRIGGER reject_pause_episode - BEFORE INSERT ON agent_org_runtime_pause_episodes + BEFORE INSERT ON agent_org_execution_pause_episodes BEGIN SELECT RAISE(ABORT, 'injected pause episode failure'); END;", ) .expect("install failure trigger"); @@ -2116,8 +2118,8 @@ fn pause_episode_insert_failure_rolls_back_status_generation_and_episode() { let state: (String, i64, i64) = conn .query_row( "SELECT status,activation_generation, - (SELECT COUNT(*) FROM agent_org_runtime_pause_episodes WHERE org_run_id=?1) - FROM agent_org_runtime_runs WHERE id=?1", + (SELECT COUNT(*) FROM agent_org_execution_pause_episodes WHERE org_run_id=?1) + FROM agent_org_execution_runs WHERE id=?1", params![&context.run_id], |row| Ok((row.get(0)?, row.get(1)?, row.get(2)?)), ) @@ -2210,7 +2212,7 @@ fn pause_captures_only_current_generation_formal_in_flight_turns() { let mut statement = conn .prepare( "SELECT original_turn_intent_id,turn_kind,drain_status - FROM agent_org_runtime_pause_handoffs + FROM agent_org_execution_pause_handoffs WHERE episode_id=?1 ORDER BY original_turn_intent_id", ) .expect("prepare receipt query"); @@ -2314,7 +2316,7 @@ fn pause_release_receipt_requires_the_exact_runtime_lease_and_turn_generation() let conn = get_connection().expect("db connection"); let still_waiting: String = conn .query_row( - "SELECT drain_status FROM agent_org_runtime_pause_handoffs + "SELECT drain_status FROM agent_org_execution_pause_handoffs WHERE episode_id=?1 AND session_id='release-owner-session'", [&paused.episode_id], |row| row.get(0), @@ -2336,7 +2338,7 @@ fn pause_release_receipt_requires_the_exact_runtime_lease_and_turn_generation() let conn = get_connection().expect("db connection"); let released: String = conn .query_row( - "SELECT drain_status FROM agent_org_runtime_pause_handoffs + "SELECT drain_status FROM agent_org_execution_pause_handoffs WHERE episode_id=?1 AND session_id='release-owner-session'", [&paused.episode_id], |row| row.get(0), @@ -2371,7 +2373,7 @@ fn pause_nth_child_failure_rolls_back_fence_and_all_receipts() { } conn.execute_batch( "CREATE TRIGGER reject_second_pause_child - BEFORE INSERT ON agent_org_runtime_pause_handoffs + BEFORE INSERT ON agent_org_execution_pause_handoffs WHEN NEW.original_turn_intent_id='child-two' BEGIN SELECT RAISE(ABORT, 'injected second child failure'); END;", ) @@ -2388,9 +2390,9 @@ fn pause_nth_child_failure_rolls_back_fence_and_all_receipts() { let state: (String, i64, i64, i64) = conn .query_row( "SELECT status,activation_generation, - (SELECT COUNT(*) FROM agent_org_runtime_pause_episodes WHERE org_run_id=?1), - (SELECT COUNT(*) FROM agent_org_runtime_pause_handoffs WHERE org_run_id=?1) - FROM agent_org_runtime_runs WHERE id=?1", + (SELECT COUNT(*) FROM agent_org_execution_pause_episodes WHERE org_run_id=?1), + (SELECT COUNT(*) FROM agent_org_execution_pause_handoffs WHERE org_run_id=?1) + FROM agent_org_execution_runs WHERE id=?1", [&context.run_id], |row| Ok((row.get(0)?, row.get(1)?, row.get(2)?, row.get(3)?)), ) @@ -2443,7 +2445,7 @@ fn stale_formal_turn_cannot_materialize_or_ack_inbox_after_pause_fence() { .expect("insert ack race row"); let conn = get_connection().expect("db connection"); conn.execute( - "INSERT INTO agent_org_runtime_inbox_materializations ( + "INSERT INTO agent_org_execution_inbox_materializations ( inbox_id,session_id,transcript_message_id,transcript_intent_id,materialized_at ) VALUES (?1,'root-shared-agent','message-ack','intent-ack',?2)", params![ack_row.id, chrono::Utc::now().to_rfc3339()], @@ -2486,7 +2488,7 @@ fn stale_formal_turn_cannot_materialize_or_ack_inbox_after_pause_fence() { let conn = get_connection().expect("db connection"); let unread_count: i64 = conn .query_row( - "SELECT COUNT(*) FROM agent_org_runtime_inbox + "SELECT COUNT(*) FROM agent_org_execution_inbox WHERE id IN (?1,?2) AND read_at IS NULL", params![materialize_row.id, ack_row.id], |row| row.get(0), @@ -2494,7 +2496,7 @@ fn stale_formal_turn_cannot_materialize_or_ack_inbox_after_pause_fence() { .expect("read post-race Inbox state"); let materialize_receipt_count: i64 = conn .query_row( - "SELECT COUNT(*) FROM agent_org_runtime_inbox_materializations + "SELECT COUNT(*) FROM agent_org_execution_inbox_materializations WHERE inbox_id=?1", [materialize_row.id], |row| row.get(0), @@ -2512,7 +2514,7 @@ fn resume_continues_only_legal_work_and_preserves_member_fifo_without_mutating_t configure_pause_resume_authority(&conn, &context); let now = chrono::Utc::now().to_rfc3339(); conn.execute_batch( - "INSERT INTO agent_org_runtime_member_dispatch_allocators + "INSERT INTO agent_org_execution_member_dispatch_allocators (org_run_id,member_id,next_sequence) VALUES ('run-shared-agent','member-planner',6);", ) @@ -2529,7 +2531,7 @@ fn resume_continues_only_legal_work_and_preserves_member_fifo_without_mutating_t ("old-materialization-e", "pending", None), ] { conn.execute( - "INSERT INTO agent_org_runtime_tasks ( + "INSERT INTO agent_org_execution_tasks ( id,org_run_id,activation_generation,subject,description,owner,status,execution_mode, blocked_by_json,output_json,cancel_reason_json,created_by_participant_id, source_turn_intent_id,created_at,updated_at @@ -2548,13 +2550,13 @@ fn resume_continues_only_legal_work_and_preserves_member_fifo_without_mutating_t .expect("associate seeded Task with the active work episode"); } conn.execute( - "UPDATE agent_org_runtime_tasks SET owner='member-builder' + "UPDATE agent_org_execution_tasks SET owner='member-builder' WHERE org_run_id=?1 AND id='reassigned-d'", [&context.run_id], ) .expect("seed reassigned Task owner"); conn.execute( - "INSERT INTO agent_org_runtime_inbox ( + "INSERT INTO agent_org_execution_inbox ( recipient_agent_id,recipient_member_id,sender_agent_id,sender_member_id, org_run_id,payload_kind,payload_json,created_at ) VALUES ('planner-agent','member-planner','coordinator-agent','coordinator', @@ -2568,7 +2570,7 @@ fn resume_continues_only_legal_work_and_preserves_member_fifo_without_mutating_t .expect("seed terminal Task assignment Inbox row"); let terminal_assignment_inbox_id = conn.last_insert_rowid(); conn.execute( - "INSERT INTO agent_org_runtime_inbox_materializations ( + "INSERT INTO agent_org_execution_inbox_materializations ( inbox_id,session_id,transcript_message_id,transcript_intent_id,materialized_at ) VALUES (?1,'planner-session','terminal-assignment-message', 'terminal-assignment-intent',?2)", @@ -2616,7 +2618,7 @@ fn resume_continues_only_legal_work_and_preserves_member_fifo_without_mutating_t let tasks_before: Vec<(String, String, Option)> = { let mut statement = conn .prepare( - "SELECT id,status,owner FROM agent_org_runtime_tasks + "SELECT id,status,owner FROM agent_org_execution_tasks WHERE org_run_id=?1 ORDER BY id", ) .expect("prepare Task snapshot"); @@ -2648,7 +2650,7 @@ fn resume_continues_only_legal_work_and_preserves_member_fifo_without_mutating_t let tasks_after: Vec<(String, String, Option)> = { let mut statement = conn .prepare( - "SELECT id,status,owner FROM agent_org_runtime_tasks + "SELECT id,status,owner FROM agent_org_execution_tasks WHERE org_run_id=?1 ORDER BY id", ) .expect("prepare post-Resume Task snapshot"); @@ -2668,8 +2670,8 @@ fn resume_continues_only_legal_work_and_preserves_member_fifo_without_mutating_t let mut statement = conn .prepare( "SELECT context.member_dispatch_sequence - FROM agent_org_runtime_pause_handoffs handoff - JOIN agent_org_runtime_turn_contexts context + FROM agent_org_execution_pause_handoffs handoff + JOIN agent_org_execution_turn_contexts context ON context.session_id=handoff.session_id AND context.turn_intent_id=handoff.continuation_turn_intent_id WHERE handoff.episode_id=?1 @@ -2687,7 +2689,7 @@ fn resume_continues_only_legal_work_and_preserves_member_fifo_without_mutating_t assert_eq!(planner_sequences, vec![6, 7]); let skipped_reason: String = conn .query_row( - "SELECT skip_reason FROM agent_org_runtime_pause_handoffs + "SELECT skip_reason FROM agent_org_execution_pause_handoffs WHERE episode_id=?1 AND task_id='completed-c'", [&resumed.episode_id], |row| row.get(0), @@ -2698,10 +2700,10 @@ fn resume_continues_only_legal_work_and_preserves_member_fifo_without_mutating_t .query_row( "SELECT resolution.resolution_kind,resolution.reason,inbox.read_at, (SELECT COUNT(*) - FROM agent_org_runtime_inbox_materializations materialization + FROM agent_org_execution_inbox_materializations materialization WHERE materialization.inbox_id=inbox.id) - FROM agent_org_runtime_inbox inbox - JOIN agent_org_runtime_inbox_delivery_resolutions resolution + FROM agent_org_execution_inbox inbox + JOIN agent_org_execution_inbox_delivery_resolutions resolution ON resolution.inbox_id=inbox.id WHERE inbox.id=?1", [terminal_assignment_inbox_id], @@ -2721,7 +2723,7 @@ fn resume_continues_only_legal_work_and_preserves_member_fifo_without_mutating_t let other_skip_reasons: Vec<(String, String)> = { let mut statement = conn .prepare( - "SELECT task_id,skip_reason FROM agent_org_runtime_pause_handoffs + "SELECT task_id,skip_reason FROM agent_org_execution_pause_handoffs WHERE episode_id=?1 AND task_id IN ('reassigned-d','old-materialization-e') ORDER BY task_id", ) @@ -2752,14 +2754,14 @@ fn exact_resume_continuation_consumes_old_assignment_only_after_task_success() { configure_pause_resume_authority(&conn, &context); let now = chrono::Utc::now().to_rfc3339(); conn.execute( - "INSERT INTO agent_org_runtime_member_dispatch_allocators + "INSERT INTO agent_org_execution_member_dispatch_allocators (org_run_id,member_id,next_sequence) VALUES (?1,'member-planner',2)", [&context.run_id], ) .expect("seed continuation FIFO"); conn.execute( - "INSERT INTO agent_org_runtime_tasks ( + "INSERT INTO agent_org_execution_tasks ( id,org_run_id,activation_generation,subject,description,owner,status,execution_mode, blocked_by_json,output_json,cancel_reason_json,created_by_participant_id, source_turn_intent_id,created_at,updated_at @@ -2823,7 +2825,7 @@ fn exact_resume_continuation_consumes_old_assignment_only_after_task_success() { }, ); conn.execute( - "INSERT INTO agent_org_runtime_inbox_materializations ( + "INSERT INTO agent_org_execution_inbox_materializations ( inbox_id,session_id,transcript_message_id,transcript_intent_id,materialized_at ) VALUES (?1,'planner-session','resume-owned-message', 'resume-owned-transcript-intent',?2)", @@ -2854,7 +2856,7 @@ fn exact_resume_continuation_consumes_old_assignment_only_after_task_success() { let continuation_turn_intent_id: String = conn .query_row( "SELECT continuation_turn_intent_id - FROM agent_org_runtime_pause_handoffs + FROM agent_org_execution_pause_handoffs WHERE episode_id=?1 AND task_id='resume-owned-task'", [&resumed.episode_id], |row| row.get(0), @@ -2914,7 +2916,7 @@ fn exact_resume_continuation_consumes_old_assignment_only_after_task_success() { let conn = get_connection().expect("db connection"); conn.execute( - "UPDATE agent_org_runtime_tasks + "UPDATE agent_org_execution_tasks SET status='completed',output_json='{}',updated_at=?3 WHERE org_run_id=?1 AND id=?2", params![ @@ -2938,7 +2940,7 @@ fn exact_resume_continuation_consumes_old_assignment_only_after_task_success() { let conn = get_connection().expect("db connection"); let read_at: Option = conn .query_row( - "SELECT read_at FROM agent_org_runtime_inbox WHERE id=?1", + "SELECT read_at FROM agent_org_execution_inbox WHERE id=?1", [assignment.id], |row| row.get(0), ) @@ -2946,7 +2948,7 @@ fn exact_resume_continuation_consumes_old_assignment_only_after_task_success() { assert!(read_at.is_some()); let unrelated_read_at: Option = conn .query_row( - "SELECT read_at FROM agent_org_runtime_inbox WHERE id=?1", + "SELECT read_at FROM agent_org_execution_inbox WHERE id=?1", [unrelated_assignment.id], |row| row.get(0), ) @@ -2985,7 +2987,7 @@ fn resume_run_update_failure_keeps_active_episode_without_continuations() { let conn = get_connection().expect("db connection"); conn.execute_batch( "CREATE TRIGGER reject_resume_run_update - BEFORE UPDATE ON agent_org_runtime_runs + BEFORE UPDATE ON agent_org_execution_runs WHEN OLD.status='paused' AND NEW.status='running' BEGIN SELECT RAISE(ABORT, 'injected Resume run update failure'); END;", ) @@ -3002,13 +3004,13 @@ fn resume_run_update_failure_keeps_active_episode_without_continuations() { let state: (String, i64, String, i64, i64) = conn .query_row( "SELECT run.status,run.activation_generation,episode.status, - (SELECT COUNT(*) FROM agent_org_runtime_pause_handoffs handoff + (SELECT COUNT(*) FROM agent_org_execution_pause_handoffs handoff WHERE handoff.episode_id=episode.episode_id AND handoff.continuation_status IS NOT NULL), (SELECT COUNT(*) FROM session_turn_intents intent WHERE intent.org_run_id=run.id AND intent.source='resume') - FROM agent_org_runtime_runs run - JOIN agent_org_runtime_pause_episodes episode ON episode.org_run_id=run.id + FROM agent_org_execution_runs run + JOIN agent_org_execution_pause_episodes episode ON episode.org_run_id=run.id WHERE run.id=?1", [&context.run_id], |row| { @@ -3079,13 +3081,13 @@ fn resume_continuation_insert_failure_rolls_back_run_and_receipts() { let state: (String, i64, String, i64, i64) = conn .query_row( "SELECT run.status,run.activation_generation,episode.status, - (SELECT COUNT(*) FROM agent_org_runtime_pause_handoffs handoff + (SELECT COUNT(*) FROM agent_org_execution_pause_handoffs handoff WHERE handoff.episode_id=episode.episode_id AND handoff.continuation_status IS NOT NULL), (SELECT COUNT(*) FROM session_turn_intents intent WHERE intent.org_run_id=run.id AND intent.source='resume') - FROM agent_org_runtime_runs run - JOIN agent_org_runtime_pause_episodes episode ON episode.org_run_id=run.id + FROM agent_org_execution_runs run + JOIN agent_org_execution_pause_episodes episode ON episode.org_run_id=run.id WHERE run.id=?1", [&context.run_id], |row| { @@ -3139,7 +3141,7 @@ fn resume_precommit_failure_rolls_back_generation_episode_and_continuations() { let conn = get_connection().expect("db connection"); conn.execute_batch( "CREATE TRIGGER reject_resume_precommit - BEFORE UPDATE ON agent_org_runtime_pause_episodes + BEFORE UPDATE ON agent_org_execution_pause_episodes WHEN NEW.status='consumed' BEGIN SELECT RAISE(ABORT, 'injected Resume precommit failure'); END;", ) @@ -3159,13 +3161,13 @@ fn resume_precommit_failure_rolls_back_generation_episode_and_continuations() { let state: (String, i64, String, i64, i64) = conn .query_row( "SELECT run.status,run.activation_generation,episode.status, - (SELECT COUNT(*) FROM agent_org_runtime_pause_handoffs handoff + (SELECT COUNT(*) FROM agent_org_execution_pause_handoffs handoff WHERE handoff.episode_id=episode.episode_id AND handoff.continuation_status IS NOT NULL), (SELECT COUNT(*) FROM session_turn_intents intent WHERE intent.org_run_id=run.id AND intent.source='resume') - FROM agent_org_runtime_runs run - JOIN agent_org_runtime_pause_episodes episode ON episode.org_run_id=run.id + FROM agent_org_execution_runs run + JOIN agent_org_execution_pause_episodes episode ON episode.org_run_id=run.id WHERE run.id=?1", [&context.run_id], |row| { @@ -3225,7 +3227,7 @@ fn restart_recovers_one_durable_continuation_without_replaying_it_twice() { let continuation_turn_intent_id: String = conn .query_row( "SELECT continuation_turn_intent_id - FROM agent_org_runtime_pause_handoffs WHERE episode_id=?1", + FROM agent_org_execution_pause_handoffs WHERE episode_id=?1", [&resumed.episode_id], |row| row.get(0), ) @@ -3262,7 +3264,7 @@ fn restart_recovers_one_durable_continuation_without_replaying_it_twice() { let recovered: (String, String, String) = conn .query_row( "SELECT handoff.drain_status,handoff.continuation_status,intent.status - FROM agent_org_runtime_pause_handoffs handoff + FROM agent_org_execution_pause_handoffs handoff JOIN session_turn_intents intent ON intent.session_id=handoff.session_id AND intent.turn_intent_id=handoff.continuation_turn_intent_id diff --git a/src-tauri/crates/agent-core/src/state/commands/session/persistence.rs b/src-tauri/crates/agent-core/src/state/commands/session/persistence.rs index 362b1c50b6..951f10d23b 100644 --- a/src-tauri/crates/agent-core/src/state/commands/session/persistence.rs +++ b/src-tauri/crates/agent-core/src/state/commands/session/persistence.rs @@ -523,7 +523,7 @@ fn ensure_agent_org_hierarchy_absent( } let run_exists = conn .query_row( - "SELECT EXISTS(SELECT 1 FROM agent_org_runtime_runs WHERE id=?1)", + "SELECT EXISTS(SELECT 1 FROM agent_org_execution_runs WHERE id=?1)", [&plan.run_id], |row| row.get::<_, bool>(0), ) diff --git a/src-tauri/crates/agent-core/src/state/commands/session/persistence_tests.rs b/src-tauri/crates/agent-core/src/state/commands/session/persistence_tests.rs index 665a036ba6..daaf9abd6a 100644 --- a/src-tauri/crates/agent-core/src/state/commands/session/persistence_tests.rs +++ b/src-tauri/crates/agent-core/src/state/commands/session/persistence_tests.rs @@ -217,7 +217,7 @@ fn seed_run_with_status(run_id: &str, root_session_id: &str, status: &str) { if status == "archived" { let receipt_id = format!("archive-receipt-{run_id}"); conn.execute( - "INSERT INTO agent_org_runtime_runs ( + "INSERT INTO agent_org_execution_runs ( id, org_id, coordinator_agent_id, root_session_id, entry_mode, status, activation_generation, archived_at, archive_receipt_id, created_at, updated_at @@ -227,7 +227,7 @@ fn seed_run_with_status(run_id: &str, root_session_id: &str, status: &str) { ) .expect("seed archived run"); conn.execute( - "INSERT INTO agent_org_runtime_archive_episodes ( + "INSERT INTO agent_org_execution_archive_episodes ( archive_receipt_id,org_run_id,archive_request_id, archive_generation,teardown_status,teardown_attempt_count, retained_runtime_count,deadline_at,archived_at,updated_at,quiesced_at @@ -243,7 +243,7 @@ fn seed_run_with_status(run_id: &str, root_session_id: &str, status: &str) { .expect("seed quiesced Archive receipt"); } else { conn.execute( - "INSERT INTO agent_org_runtime_runs ( + "INSERT INTO agent_org_execution_runs ( id, org_id, coordinator_agent_id, root_session_id, entry_mode, status, created_at, updated_at ) VALUES (?1, 'org-delete-test', 'coordinator-agent', ?2, @@ -495,7 +495,7 @@ fn seed_session_owned_rows(session_id: &str) { fn seed_run_owned_rows(run_id: &str) { let conn = get_connection().expect("sandbox DB"); conn.execute( - "INSERT INTO agent_org_runtime_inbox ( + "INSERT INTO agent_org_execution_inbox ( recipient_agent_id, recipient_member_id, sender_agent_id, org_run_id, payload_kind, payload_json, created_at ) VALUES ('worker-agent', 'worker', 'system', ?1, @@ -504,7 +504,7 @@ fn seed_run_owned_rows(run_id: &str) { ) .expect("seed run inbox history"); conn.execute( - r#"INSERT INTO agent_org_runtime_tasks ( + r#"INSERT INTO agent_org_execution_tasks ( id, org_run_id, activation_generation, subject, description, owner, status, execution_mode, blocked_by_json, output_json, created_by_participant_id, source_turn_intent_id, @@ -519,7 +519,7 @@ fn seed_run_owned_rows(run_id: &str) { ) .expect("seed run task history"); conn.execute( - "INSERT INTO agent_org_runtime_task_execution_handoffs ( + "INSERT INTO agent_org_execution_task_execution_handoffs ( id,org_run_id,activation_generation,request_id,request_digest, old_task_id,old_owner_member_id,state,requested_at,updated_at ) VALUES (?1,?2,1,?3,?4,?5,'worker','unknown',?6,?6)", @@ -560,7 +560,7 @@ fn seed_linked_user_directed_history( let root_inbox_id = conn .query_row( - "INSERT INTO agent_org_runtime_inbox ( + "INSERT INTO agent_org_execution_inbox ( delivery_class,recipient_agent_id,recipient_member_id, sender_agent_id,sender_member_id,org_run_id,payload_kind, payload_json,created_at,display_text @@ -575,7 +575,7 @@ fn seed_linked_user_directed_history( .expect("seed root UDW Inbox"); let linked_inbox_id = conn .query_row( - "INSERT INTO agent_org_runtime_inbox ( + "INSERT INTO agent_org_execution_inbox ( delivery_class,recipient_agent_id,recipient_member_id, sender_agent_id,sender_member_id,org_run_id,payload_kind, payload_json,created_at,causation_inbox_id,display_text @@ -590,7 +590,7 @@ fn seed_linked_user_directed_history( .expect("seed linked UDW Inbox"); let coordinator_inbox_id = conn .query_row( - "INSERT INTO agent_org_runtime_inbox ( + "INSERT INTO agent_org_execution_inbox ( delivery_class,recipient_agent_id,recipient_member_id, sender_agent_id,sender_member_id,org_run_id,payload_kind, payload_json,created_at,causation_inbox_id,display_text @@ -605,7 +605,7 @@ fn seed_linked_user_directed_history( .expect("seed Coordinator UDW Inbox"); conn.execute( - "INSERT INTO agent_org_runtime_turn_contexts ( + "INSERT INTO agent_org_execution_turn_contexts ( session_id,turn_intent_id,org_run_id,participant_id,turn_kind, dispatch_member_id,member_dispatch_sequence,source_kind,source_id, root_authority_turn_id,actor_version,created_at @@ -621,7 +621,7 @@ fn seed_linked_user_directed_history( ) .expect("seed root UDW Turn context"); conn.execute( - "INSERT INTO agent_org_runtime_turn_contexts ( + "INSERT INTO agent_org_execution_turn_contexts ( session_id,turn_intent_id,org_run_id,participant_id,turn_kind, dispatch_member_id,member_dispatch_sequence,source_kind,source_id, root_authority_turn_id,actor_version,created_at @@ -638,7 +638,7 @@ fn seed_linked_user_directed_history( ) .expect("seed linked UDW Turn context"); conn.execute( - "INSERT INTO agent_org_runtime_turn_contexts ( + "INSERT INTO agent_org_execution_turn_contexts ( session_id,turn_intent_id,org_run_id,participant_id,turn_kind, source_kind,source_id,root_authority_turn_id,actor_version,created_at ) VALUES (?1,?2,?3,'coordinator','coordinator', @@ -654,7 +654,7 @@ fn seed_linked_user_directed_history( ) .expect("seed Coordinator side-quest Turn context"); conn.execute( - "INSERT INTO agent_org_runtime_user_directed_roots ( + "INSERT INTO agent_org_execution_user_directed_roots ( org_run_id,root_authority_turn_id,policy_version,max_deliveries, max_cascade_depth,next_delivery_ordinal,created_at ) VALUES (?1,?2,1,8,2,4,?3)", @@ -663,7 +663,7 @@ fn seed_linked_user_directed_history( .expect("seed UDW root authority"); let root_delivery_id = conn .query_row( - "INSERT INTO agent_org_runtime_user_directed_deliveries ( + "INSERT INTO agent_org_execution_user_directed_deliveries ( org_run_id,session_id,turn_intent_id,root_authority_turn_id, source_kind,source_inbox_id,dispatch_member_id, member_dispatch_sequence,depth,delivery_ordinal,request_digest, @@ -685,7 +685,7 @@ fn seed_linked_user_directed_history( .expect("seed root UDW delivery"); let linked_delivery_id = conn .query_row( - "INSERT INTO agent_org_runtime_user_directed_deliveries ( + "INSERT INTO agent_org_execution_user_directed_deliveries ( org_run_id,session_id,turn_intent_id,root_authority_turn_id, parent_delivery_id,parent_inbox_id,source_kind,source_inbox_id, dispatch_member_id,member_dispatch_sequence,depth,delivery_ordinal, @@ -710,7 +710,7 @@ fn seed_linked_user_directed_history( ) .expect("seed linked UDW delivery"); conn.execute( - "INSERT INTO agent_org_runtime_user_directed_coordinator_bindings ( + "INSERT INTO agent_org_execution_user_directed_coordinator_bindings ( org_run_id,session_id,turn_intent_id,root_authority_turn_id, parent_delivery_id,parent_inbox_id,source_inbox_id,depth, delivery_ordinal,request_digest,dispatch_content,display_content, @@ -833,29 +833,29 @@ fn session_hierarchy_delete_removes_all_rust_descendants_and_run_history() { )); } assert!(!row_exists( - "agent_org_runtime_runs", + "agent_org_execution_runs", "id", "hierarchy-delete-run" )); assert!(!row_exists( - "agent_org_runtime_inbox", + "agent_org_execution_inbox", "org_run_id", "hierarchy-delete-run" )); assert!(!row_exists( - "agent_org_runtime_tasks", + "agent_org_execution_tasks", "org_run_id", "hierarchy-delete-run" )); assert!(!row_exists( - "agent_org_runtime_task_execution_handoffs", + "agent_org_execution_task_execution_handoffs", "org_run_id", "hierarchy-delete-run" )); for table in [ - "agent_org_runtime_user_directed_coordinator_bindings", - "agent_org_runtime_user_directed_deliveries", - "agent_org_runtime_user_directed_roots", + "agent_org_execution_user_directed_coordinator_bindings", + "agent_org_execution_user_directed_deliveries", + "agent_org_execution_user_directed_roots", ] { assert!(!row_exists(table, "org_run_id", "hierarchy-delete-run")); } @@ -872,17 +872,17 @@ fn session_hierarchy_delete_removes_all_rust_descendants_and_run_history() { &format!("commit-link-{unrelated}") )); assert!(row_exists( - "agent_org_runtime_runs", + "agent_org_execution_runs", "id", "hierarchy-delete-other-run" )); assert!(row_exists( - "agent_org_runtime_inbox", + "agent_org_execution_inbox", "org_run_id", "hierarchy-delete-other-run" )); assert!(row_exists( - "agent_org_runtime_task_execution_handoffs", + "agent_org_execution_task_execution_handoffs", "org_run_id", "hierarchy-delete-other-run" )); @@ -916,12 +916,12 @@ fn team_ownership_resolver_maps_worker_to_root_and_run() { assert!(row_exists("agent_sessions", "session_id", worker)); assert!(row_exists("agent_sessions", "session_id", root)); assert!(row_exists( - "agent_org_runtime_runs", + "agent_org_execution_runs", "id", "hierarchy-worker-run" )); assert!(row_exists( - "agent_org_runtime_inbox", + "agent_org_execution_inbox", "org_run_id", "hierarchy-worker-run" )); @@ -949,7 +949,7 @@ fn session_hierarchy_delete_requires_archived_without_mutating_active_run() { get_connection() .expect("sandbox DB") .query_row( - "SELECT status FROM agent_org_runtime_runs WHERE id='hierarchy-active-run'", + "SELECT status FROM agent_org_execution_runs WHERE id='hierarchy-active-run'", [], |row| row.get::<_, String>(0) ) @@ -959,7 +959,7 @@ fn session_hierarchy_delete_requires_archived_without_mutating_active_run() { assert!(row_exists("agent_sessions", "session_id", root)); assert!(row_exists("agent_sessions", "session_id", worker)); assert!(row_exists( - "agent_org_runtime_runs", + "agent_org_execution_runs", "id", "hierarchy-active-run" )); @@ -975,7 +975,7 @@ fn session_hierarchy_delete_rejects_retained_runtime_receipt() { seed_run(run_id, root); let conn = get_connection().expect("sandbox DB"); conn.execute( - "UPDATE agent_org_runtime_archive_episodes + "UPDATE agent_org_execution_archive_episodes SET teardown_status='retained_runtime',teardown_attempt_count=3, retained_runtime_count=1,quiesced_at=NULL, last_error='archive_runtime_stop_timeout' @@ -990,7 +990,7 @@ fn session_hierarchy_delete_rejects_retained_runtime_receipt() { .expect_err("retained runtime must block Team Delete"); assert!(error.starts_with("team_runtime_not_quiesced:")); assert!(row_exists("agent_sessions", "session_id", root)); - assert!(row_exists("agent_org_runtime_runs", "id", run_id)); + assert!(row_exists("agent_org_execution_runs", "id", run_id)); } #[test] @@ -1072,7 +1072,7 @@ fn session_hierarchy_delete_blocks_resource_preflight_failures_before_database_c assert!(row_exists("agent_sessions", "session_id", root)); assert!(row_exists("agent_sessions", "session_id", worker)); assert!(row_exists( - "agent_org_runtime_runs", + "agent_org_execution_runs", "id", "hierarchy-replay-run" )); @@ -1104,7 +1104,7 @@ fn session_hierarchy_delete_blocks_resource_preflight_failures_before_database_c assert!(row_exists("agent_sessions", "session_id", root)); assert!(row_exists("agent_sessions", "session_id", worker)); assert!(row_exists( - "agent_org_runtime_runs", + "agent_org_execution_runs", "id", "hierarchy-replay-run" )); @@ -1134,12 +1134,12 @@ fn session_hierarchy_delete_rejects_nested_agent_org_without_mutation() { assert!(row_exists("agent_sessions", "session_id", session_id)); } assert!(row_exists( - "agent_org_runtime_runs", + "agent_org_execution_runs", "id", "hierarchy-nested-outer-run" )); assert!(row_exists( - "agent_org_runtime_runs", + "agent_org_execution_runs", "id", "hierarchy-nested-inner-run" )); @@ -1186,7 +1186,7 @@ fn session_hierarchy_delete_rejects_cycle_and_size_limit() { assert!(error.contains("exceeds")); assert!(row_exists("agent_sessions", "session_id", limit_root)); assert!(row_exists( - "agent_org_runtime_runs", + "agent_org_execution_runs", "id", "hierarchy-limit-run" )); @@ -1216,7 +1216,7 @@ fn session_hierarchy_delete_rechecks_concurrent_structure_changes() { assert!(row_exists("agent_sessions", "session_id", session_id)); } assert!(row_exists( - "agent_org_runtime_runs", + "agent_org_execution_runs", "id", "hierarchy-recheck-run" )); @@ -1291,17 +1291,17 @@ fn session_hierarchy_delete_rolls_back_on_midway_database_failure() { )); } assert!(row_exists( - "agent_org_runtime_runs", + "agent_org_execution_runs", "id", "hierarchy-rollback-run" )); assert!(row_exists( - "agent_org_runtime_inbox", + "agent_org_execution_inbox", "org_run_id", "hierarchy-rollback-run" )); assert!(row_exists( - "agent_org_runtime_tasks", + "agent_org_execution_tasks", "org_run_id", "hierarchy-rollback-run" )); @@ -1354,7 +1354,7 @@ fn session_hierarchy_delete_rolls_back_transaction_time_structure_changes() { assert!(row_exists("agent_sessions", "session_id", worker)); assert!(!row_exists("agent_sessions", "session_id", injected)); assert!(row_exists( - "agent_org_runtime_runs", + "agent_org_execution_runs", "id", "hierarchy-trigger-change-run" )); diff --git a/src-tauri/crates/agent-core/src/tests/lifecycle_tests.rs b/src-tauri/crates/agent-core/src/tests/lifecycle_tests.rs index c065f5ba4b..a023e9ae9b 100644 --- a/src-tauri/crates/agent-core/src/tests/lifecycle_tests.rs +++ b/src-tauri/crates/agent-core/src/tests/lifecycle_tests.rs @@ -76,6 +76,7 @@ impl MemberIdleHook for RecordingMemberIdleHook { fn ensure_runtime_schemas() { let conn = database::db::get_connection().expect("test sqlite connection"); crate::persistence::test_schema::ensure_agent_sessions_schema(&conn); + crate::persistence::test_schema::ensure_session_events_schema(&conn); crate::coordination::init_agent_org_schemas(&conn).expect("complete Agent Org runtime schema"); conn.execute_batch( "CREATE TABLE IF NOT EXISTS code_sessions ( @@ -211,7 +212,7 @@ fn seed_run(member_agent_id: &str) -> String { .expect("create run"); let conn = database::db::get_connection().expect("test sqlite connection"); conn.execute( - "INSERT INTO agent_org_runtime_member_materializations( + "INSERT INTO agent_org_execution_member_materializations( org_run_id,member_id,agent_id,generation,session_id, authority_class,status,created_at,updated_at ) VALUES (?1,'member-worker',?2,1,'member-session', @@ -258,7 +259,7 @@ fn seed_task_execution_turn(run_id: &str, task_id: &str, turn_id: &str) { let sequence: i64 = conn .query_row( "SELECT COALESCE(MAX(member_dispatch_sequence),0)+1 - FROM agent_org_runtime_turn_contexts + FROM agent_org_execution_turn_contexts WHERE org_run_id=?1 AND dispatch_member_id='member-worker'", [run_id], |row| row.get(0), @@ -272,7 +273,7 @@ fn seed_task_execution_turn(run_id: &str, task_id: &str, turn_id: &str) { ) .expect("seed failed base Turn"); conn.execute( - "INSERT INTO agent_org_runtime_turn_contexts( + "INSERT INTO agent_org_execution_turn_contexts( session_id,turn_intent_id,org_run_id,participant_id,turn_kind, task_id,owner_member_id,dispatch_member_id,member_dispatch_sequence, source_kind,source_id,activation_generation,created_at @@ -283,13 +284,13 @@ fn seed_task_execution_turn(run_id: &str, task_id: &str, turn_id: &str) { ) .expect("seed exact TaskExecution context"); conn.execute( - "INSERT INTO agent_org_runtime_task_events( + "INSERT INTO agent_org_execution_task_events( id,org_run_id,task_id,event_type,previous_owner,next_owner, previous_status,next_status,actor_member_id,actor_kind, source_turn_intent_id,created_at ) SELECT ?1,task.org_run_id,task.id,'updated',task.owner,task.owner, 'pending','in_progress','member-worker','owner_execution',?2,task.updated_at - FROM agent_org_runtime_tasks task + FROM agent_org_execution_tasks task WHERE task.org_run_id=?3 AND task.id=?4 AND task.status='in_progress'", rusqlite::params![uuid::Uuid::new_v4().to_string(), turn_id, run_id, task_id], ) @@ -385,7 +386,7 @@ async fn successful_member_finalize_keeps_in_progress_work_owned() { let conn = database::db::get_connection().expect("test sqlite connection"); let now = chrono::Utc::now().to_rfc3339(); conn.execute( - "INSERT INTO agent_org_runtime_recovery_attempts( + "INSERT INTO agent_org_execution_recovery_attempts( org_run_id,action_kind,target_key,reason_fingerprint,attempts, next_allowed_at,updated_at,reservation_token ) VALUES (?1,'task_failure_recovery','active-task','historical',2,?2,?2,NULL)", @@ -446,7 +447,7 @@ async fn successful_member_finalize_keeps_in_progress_work_owned() { assert!(release_events.is_empty()); let task_recovery_attempts: i64 = conn .query_row( - "SELECT attempts FROM agent_org_runtime_recovery_attempts + "SELECT attempts FROM agent_org_execution_recovery_attempts WHERE org_run_id=?1 AND action_kind='task_failure_recovery' AND target_key='active-task'", [&run_id], @@ -478,7 +479,7 @@ async fn user_directed_finalize_never_mutates_formal_task_lifecycle() { ) .expect("seed admitted direct Turn intent"); conn.execute( - "INSERT INTO agent_org_runtime_turn_contexts( + "INSERT INTO agent_org_execution_turn_contexts( session_id,turn_intent_id,org_run_id,participant_id,turn_kind, dispatch_member_id,member_dispatch_sequence,source_kind,source_id, root_authority_turn_id,actor_version,created_at @@ -530,7 +531,7 @@ fn successful_cancelled_turn_does_not_blanket_resolve_member_inbox() { let conn = database::db::get_connection().expect("test sqlite connection"); let now = chrono::Utc::now().to_rfc3339(); conn.execute( - r#"UPDATE agent_org_runtime_tasks + r#"UPDATE agent_org_execution_tasks SET status='cancelled', cancel_reason_json='{"code":"writer_cancelled","message":"replaced"}', updated_at=?3 @@ -588,11 +589,11 @@ fn successful_cancelled_turn_does_not_blanket_resolve_member_inbox() { let (unread_rows, resolutions): (i64, i64) = conn .query_row( "SELECT - (SELECT COUNT(*) FROM agent_org_runtime_inbox + (SELECT COUNT(*) FROM agent_org_execution_inbox WHERE org_run_id=?1 AND recipient_member_id='member-worker' AND read_at IS NULL), (SELECT COUNT(*) - FROM agent_org_runtime_inbox_delivery_resolutions + FROM agent_org_execution_inbox_delivery_resolutions WHERE org_run_id=?1 AND reason='member_turn_finished_without_owned_formal_work')", [&run_id], @@ -778,7 +779,7 @@ fn deterministic_sibling_terminal_failure_never_requeues_completed_task() { assert_eq!(loser_status, "failed"); let recovery_event_count: i64 = conn .query_row( - "SELECT COUNT(*) FROM agent_org_runtime_task_events + "SELECT COUNT(*) FROM agent_org_execution_task_events WHERE org_run_id=?1 AND task_id='sibling-terminal-task' AND previous_status='completed'", [&run_id], @@ -856,7 +857,7 @@ fn startup_recovery_requeues_only_the_uniquely_bound_task_and_is_idempotent() { let receipt: (String, String, String, String, String) = conn .query_row( "SELECT source_kind,task_id,owner_member_id,source_turn_intent_id,doorbell_status - FROM agent_org_runtime_formal_trigger_receipts WHERE receipt_id=?1", + FROM agent_org_execution_formal_trigger_receipts WHERE receipt_id=?1", [receipt_id], |row| { Ok(( @@ -881,7 +882,7 @@ fn startup_recovery_requeues_only_the_uniquely_bound_task_and_is_idempotent() { ); let recovery_inbox_count: i64 = conn .query_row( - "SELECT COUNT(*) FROM agent_org_runtime_inbox + "SELECT COUNT(*) FROM agent_org_execution_inbox WHERE org_run_id=?1 AND payload_kind='member_idle'", [&run_id], |row| row.get(0), @@ -914,7 +915,7 @@ fn startup_recovery_requeues_only_the_uniquely_bound_task_and_is_idempotent() { } let receipt_count: i64 = conn .query_row( - "SELECT COUNT(*) FROM agent_org_runtime_formal_trigger_receipts + "SELECT COUNT(*) FROM agent_org_execution_formal_trigger_receipts WHERE org_run_id=?1 AND source_kind='task_execution_recovery_required'", [&run_id], |row| row.get(0), @@ -942,7 +943,7 @@ fn startup_recovery_keyset_scan_is_not_capped_at_first_hundred_runs() { let root = format!("root-page-{index:03}"); let now = chrono::Utc::now().to_rfc3339(); tx.execute( - "INSERT INTO agent_org_runtime_runs( + "INSERT INTO agent_org_execution_runs( id,org_id,coordinator_agent_id,root_session_id,org_snapshot_json, entry_mode,status,activation_generation,created_at,updated_at ) VALUES (?1,'org-lifecycle','builtin:coord',?2,?3, @@ -1080,7 +1081,7 @@ async fn stale_generation_terminal_cannot_change_new_execution_or_notify() { seed_task_execution_turn(&run_id, "old-work", "old-intent"); let conn = database::db::get_connection().unwrap(); conn.execute( - "UPDATE agent_org_runtime_runs SET activation_generation=2 WHERE id=?1", + "UPDATE agent_org_execution_runs SET activation_generation=2 WHERE id=?1", [&run_id], ) .unwrap(); diff --git a/src-tauri/crates/session-persistence/src/crud.rs b/src-tauri/crates/session-persistence/src/crud.rs index 7aa166dddf..0af26f50b3 100644 --- a/src-tauri/crates/session-persistence/src/crud.rs +++ b/src-tauri/crates/session-persistence/src/crud.rs @@ -134,6 +134,12 @@ fn upsert_event_rows( seq, ])? > 0; } + let event_ids = events + .iter() + .filter(|event| !is_ts_placeholder_id(&event.id)) + .map(|event| event.id.as_str()) + .collect::>(); + agent_core::coordination::agent_org_history_store::mirror_events(conn, session_id, &event_ids)?; Ok(content_changed) } @@ -673,7 +679,7 @@ pub fn clear_old_sessions(max_age_hours: i64) -> SqliteResult { let _ = tx.execute("DELETE FROM agent_snapshots WHERE session_id = ?1", [sid]); let _ = tx.execute("DELETE FROM goal_loop_state WHERE session_id = ?1", [sid]); let _ = tx.execute( - "DELETE FROM agent_org_runtime_member_interventions WHERE session_id = ?1", + "DELETE FROM agent_org_execution_member_interventions WHERE session_id = ?1", [sid], ); } diff --git a/src-tauri/crates/session-persistence/src/crud_tests.rs b/src-tauri/crates/session-persistence/src/crud_tests.rs index 045c8c462c..7d64f44dbb 100644 --- a/src-tauri/crates/session-persistence/src/crud_tests.rs +++ b/src-tauri/crates/session-persistence/src/crud_tests.rs @@ -589,3 +589,6 @@ fn activity_probe_is_scoped_read_only_and_stops_at_first_match() { #[path = "execution_history_tests.rs"] mod execution_history_tests; + +#[path = "history_compatibility_tests.rs"] +mod history_compatibility_tests; diff --git a/src-tauri/crates/session-persistence/src/history_compatibility_tests.rs b/src-tauri/crates/session-persistence/src/history_compatibility_tests.rs new file mode 100644 index 0000000000..0e49bb9c76 --- /dev/null +++ b/src-tauri/crates/session-persistence/src/history_compatibility_tests.rs @@ -0,0 +1,132 @@ +//! Exercise the real shared transcript writer/reader, not only archive helpers. +use super::*; +use agent_core::coordination::{agent_org_history_store, init_agent_org_schemas}; + +fn seed_old_team(conn: &Connection) { + crate::schema::init_session_tables(conn).unwrap(); + agent_core::persistence::session_snapshots::ensure_tables_with(conn).unwrap(); + agent_core::session::persistence::init(conn).unwrap(); + conn.execute_batch(include_str!( + "../../agent-core/src/core/coordination/fixtures/official_v2_0_8_agent_org.sql" + )) + .unwrap(); + conn.execute_batch("INSERT INTO agent_sessions + (session_id,name,status,session_type,created_at,updated_at,org_member_id) + VALUES ('sde-history-root','Preserved team','running','sde','2026-09-24','2026-09-24','coordinator'); + INSERT INTO agent_org_runtime_runs + (id,org_id,coordinator_agent_id,root_session_id,entry_mode,status,created_at,updated_at) + VALUES ('old-run','old-org','coordinator','sde-history-root','standalone_session','running','2026-09-24','2026-09-24');").unwrap(); +} + +fn user_event(id: &str) -> CachedEvent { + let mut event = cached_event("sde-history-root", id, "2026-09-24T00:00:00Z"); + event.content = "Saved user request".into(); + event.result_json = serde_json::json!({ + "type":"user", "backendPersisted":true,"turnIntentId":"pending", + "syntheticUserInput":true,"agentOrgDirectSource":true, + "message":{"role":"user","content":"Saved user request"} + }) + .to_string(); + event +} + +fn copy_id(conn: &Connection) -> String { + conn.query_row( + "SELECT copy_session_id FROM org_history_copies WHERE source_session_id='sde-history-root'", + [], + |row| row.get(0), + ) + .unwrap() +} + +#[test] +fn ordinary_copy_opens_through_session_loader_and_survives_old_stale_intents() { + with_temp_orgii_home(|| { + let conn = get_connection().unwrap(); + seed_old_team(&conn); + save_events("sde-history-root", &[user_event("user-original")]).unwrap(); + conn.execute_batch( + "INSERT INTO session_turn_intents + (session_id,turn_intent_id,org_run_id,source,status,created_at,updated_at) + VALUES ('sde-history-root','pending','old-run','agent_org','queued','now','now');", + ) + .unwrap(); + init_agent_org_schemas(&conn).unwrap(); + let copy = copy_id(&conn); + assert!(copy.starts_with(agent_core::definitions::prefix_lookup::SDE_SESSION_PREFIX)); + let loaded = load_session(©) + .unwrap() + .expect("official ordinary loader requires metadata"); + assert_eq!(loaded.events.len(), 1); + assert_ne!(loaded.events[0].id, "user-original"); + let value: serde_json::Value = serde_json::from_str(&loaded.events[0].result_json).unwrap(); + assert!(value.get("turnIntentId").is_none()); + assert!(value.get("syntheticUserInput").is_none()); + assert_eq!( + value.pointer("/message/content").unwrap(), + "Saved user request" + ); + // v2.0.8 startup can stale shared queue entries. Stored body stays visible. + conn.execute("UPDATE session_turn_intents SET status='stale'", []) + .unwrap(); + init_agent_org_schemas(&conn).unwrap(); + let turns = crate::rebuild_turn_index("sde-history-root").unwrap(); + assert_eq!(turns.len(), 1); + assert_eq!(turns[0].user_preview, "Saved user request"); + assert_eq!(crate::rebuild_turn_index(©).unwrap().len(), 1); + assert_eq!(load_session(©).unwrap().unwrap().events.len(), 1); + assert_eq!(copy_id(&conn), copy); + }); +} + +#[test] +fn current_source_writer_updates_copy_once_and_rolls_back_on_projection_failure() { + with_temp_orgii_home(|| { + let conn = get_connection().unwrap(); + crate::schema::init_session_tables(&conn).unwrap(); + agent_core::persistence::session_snapshots::ensure_tables_with(&conn).unwrap(); + agent_core::session::persistence::init(&conn).unwrap(); + init_agent_org_schemas(&conn).unwrap(); + conn.execute_batch("INSERT INTO agent_sessions + (session_id,name,status,session_type,created_at,updated_at,org_member_id) + VALUES ('sde-history-root','Current team','running','sde','now','now','coordinator'); + INSERT INTO agent_org_execution_runs + (id,org_id,coordinator_agent_id,root_session_id,entry_mode,status,created_at,updated_at) + VALUES ('new-run','org','coordinator','sde-history-root','standalone_session','running','now','now');").unwrap(); + let event = user_event("current-user"); + save_events("sde-history-root", std::slice::from_ref(&event)).unwrap(); + let copy = copy_id(&conn); + let initial = get_session_metadata(©).unwrap().unwrap(); + save_events("sde-history-root", std::slice::from_ref(&event)).unwrap(); + assert_eq!( + get_session_metadata(©) + .unwrap() + .unwrap() + .content_revision, + initial.content_revision + ); + let mut changed = event; + changed.content = "Edited saved text".into(); + save_events("sde-history-root", &[changed]).unwrap(); + assert_eq!( + load_session(©).unwrap().unwrap().events[0].content, + "Edited saved text" + ); + let updated = get_session_metadata(©).unwrap().unwrap(); + assert_eq!(updated.event_count, 1); + assert_eq!(updated.content_revision, initial.content_revision + 1); + assert!(agent_org_history_store::require_writable(&conn, "sde-history-root").is_ok()); + assert!(agent_org_history_store::require_writable(&conn, ©).is_err()); + conn.execute_batch( + "CREATE TRIGGER reject_history_event BEFORE INSERT ON events + WHEN EXISTS(SELECT 1 FROM org_history_copies WHERE copy_session_id=NEW.session_id) + BEGIN SELECT RAISE(ABORT,'copy write failure'); END;", + ) + .unwrap(); + assert!(save_events("sde-history-root", &[user_event("must-rollback")]).is_err()); + assert!(get_event("sde-history-root", "must-rollback") + .unwrap() + .is_none()); + assert_eq!(load_session(©).unwrap().unwrap().events.len(), 1); + }); +} diff --git a/src-tauri/crates/session-persistence/src/turn_index.rs b/src-tauri/crates/session-persistence/src/turn_index.rs index 6b58056117..0aee9efa73 100644 --- a/src-tauri/crates/session-persistence/src/turn_index.rs +++ b/src-tauri/crates/session-persistence/src/turn_index.rs @@ -348,22 +348,17 @@ fn materialized_inbox_message_ids( conn: &Connection, session_id: &str, ) -> SqliteResult> { - let has_receipts: bool = conn.query_row( - "SELECT EXISTS(SELECT 1 FROM sqlite_master - WHERE type='table' AND name='agent_org_runtime_inbox_materializations')", - [], - |row| row.get(0), - )?; - if !has_receipts { - return Ok(std::collections::HashSet::new()); + let mut ids = std::collections::HashSet::new(); + for (table,sql) in [ + ("agent_org_execution_inbox_materializations", "SELECT transcript_message_id FROM agent_org_execution_inbox_materializations WHERE session_id=?1"), + ("org_history_inbox_messages", "SELECT message_id FROM org_history_inbox_messages WHERE session_id=?1"), + ] { + let exists: bool=conn.query_row("SELECT EXISTS(SELECT 1 FROM sqlite_master WHERE type='table' AND name=?1)",[table],|row|row.get(0))?; + if exists { + let mut stmt=conn.prepare_cached(sql)?; + for row in stmt.query_map([session_id],|row|row.get::<_,String>(0))? { ids.insert(row?); } + } } - let mut stmt = conn.prepare_cached( - "SELECT transcript_message_id FROM agent_org_runtime_inbox_materializations - WHERE session_id=?1", - )?; - let ids = stmt - .query_map([session_id], |row| row.get(0))? - .collect::>()?; Ok(ids) } @@ -776,7 +771,13 @@ fn rebuild_turn_index_inner(session_id: &str) -> SqliteResult SqliteResult Result<( let conn = get_connection().map_err(|err| err.to_string())?; let store = SqliteRecordStore::new(&conn); for record in records { + let compatibility_copy: bool = conn + .query_row( + "SELECT EXISTS(SELECT 1 FROM org_history_copies WHERE copy_session_id=?1)", + [&record.session_id], + |row| row.get(0), + ) + .map_err(|error| error.to_string())?; + if compatibility_copy { + continue; + } store.upsert_session(&aggregate_to_core_session(record))?; } Ok(()) @@ -117,6 +127,17 @@ pub fn upsert_cli_session(session_id: &str) -> Result<(), String> { /// changes (rename, model swap) land without waiting for the next /// artifact-persistence pass. pub fn upsert_rust_agent_session(session_id: &str) -> Result<(), String> { + let conn = get_connection().map_err(|err| err.to_string())?; + let compatibility_copy: bool = conn + .query_row( + "SELECT EXISTS(SELECT 1 FROM org_history_copies WHERE copy_session_id=?1)", + [session_id], + |row| row.get(0), + ) + .map_err(|error| error.to_string())?; + if compatibility_copy { + return Ok(()); + } let record = crate::agent_sessions::event_pipeline::commands::runtime_artifact_session_record( session_id, )?; diff --git a/src-tauri/src/agent_sessions/session_directory/sections/mod.rs b/src-tauri/src/agent_sessions/session_directory/sections/mod.rs index 2ec5e9fa10..8547342c9b 100644 --- a/src-tauri/src/agent_sessions/session_directory/sections/mod.rs +++ b/src-tauri/src/agent_sessions/session_directory/sections/mod.rs @@ -34,7 +34,14 @@ fn lookup( return Ok(Some(row)); } if let Some(record) = persistence::get_session(id).map_err(|e| e.to_string())? { - if record.parent_session_id.is_some() || record.status == "archived" { + let history = agent_core::coordination::agent_org_history_store::descriptor(conn, id) + .map_err(|error| error.to_string())?; + let historical_root = history.as_ref().is_some_and(|identity| { + identity.mode + == agent_core::coordination::agent_org_history_store::HistoryMode::HistoryOnly + && identity.root_session_id.as_deref() == Some(id) + }); + if record.parent_session_id.is_some() || (record.status == "archived" && !historical_root) { return Ok(None); } let mut resolver = AgentMetadataResolver::new(); @@ -46,7 +53,10 @@ fn lookup( }; if let Some(mut row) = row { super::aggregation::annotate_agent_org_root_rows(std::slice::from_mut(&mut row))?; - if row.org_member_id.is_some() && row.agent_org_id.is_none() { + if row.org_member_id.is_some() + && row.agent_org_id.is_none() + && row.agent_org_mode.is_none() + { return Ok(None); } return Ok(Some(row)); diff --git a/src-tauri/src/agent_sessions/session_directory/sections/tests.rs b/src-tauri/src/agent_sessions/session_directory/sections/tests.rs index fe60d4173c..c339970927 100644 --- a/src-tauri/src/agent_sessions/session_directory/sections/tests.rs +++ b/src-tauri/src/agent_sessions/session_directory/sections/tests.rs @@ -177,3 +177,25 @@ fn section_count_is_bounded_at_the_write_boundary() { .is_err()); assert_eq!(snapshot(&c).unwrap().sections.len(), MAX_SECTIONS); } + +#[test] +fn archived_history_root_can_be_resolved_inside_a_custom_section() { + let _sandbox = crate::test_utils::test_env::sandbox(); + let conn = database::db::get_connection().unwrap(); + conn.execute_batch("INSERT INTO agent_sessions + (session_id,name,status,session_type,created_at,updated_at,org_member_id) + VALUES ('sdeagent-retired-section','Preserved team','archived','sde','now','now','coordinator'); + INSERT INTO org_history_sessions(session_id,root_session_id,title,source_table) + VALUES ('sdeagent-retired-section','sdeagent-retired-section','Preserved team','fixture');").unwrap(); + let row = super::lookup( + &conn, + "sdeagent-retired-section", + &std::collections::HashSet::new(), + ) + .unwrap() + .unwrap(); + assert_eq!( + row.agent_org_mode, + Some(agent_core::coordination::agent_org_history_store::HistoryMode::HistoryOnly) + ); +} diff --git a/src-tauri/src/agent_sessions/session_directory/tests/session_filter_tests.rs b/src-tauri/src/agent_sessions/session_directory/tests/session_filter_tests.rs index 30d54b61b2..f873dd56aa 100644 --- a/src-tauri/src/agent_sessions/session_directory/tests/session_filter_tests.rs +++ b/src-tauri/src/agent_sessions/session_directory/tests/session_filter_tests.rs @@ -71,6 +71,7 @@ fn make_session( parent_session_id: None, org_member_id: None, agent_org_id: None, + agent_org_mode: None, agent_org_name: None, agent_definition_id: None, agent_icon_id: None, diff --git a/src-tauri/src/agent_sessions/session_directory/types.rs b/src-tauri/src/agent_sessions/session_directory/types.rs index 295d28b3a8..622f0390a9 100644 --- a/src-tauri/src/agent_sessions/session_directory/types.rs +++ b/src-tauri/src/agent_sessions/session_directory/types.rs @@ -127,6 +127,9 @@ pub struct SessionAggregateRecord { /// Agent Org definition id for root/coordinator rows launched from an org. #[serde(skip_serializing_if = "Option::is_none")] pub agent_org_id: Option, + /// Read identity remains available when execution records have been retired. + #[serde(skip_serializing_if = "Option::is_none")] + pub agent_org_mode: Option, /// Agent Org display name for root/coordinator rows launched from an org. #[serde(skip_serializing_if = "Option::is_none")] pub agent_org_name: Option, diff --git a/src-tauri/src/api/agent/test/agent_org.rs b/src-tauri/src/api/agent/test/agent_org.rs index c2df6f9989..dc6af205ce 100644 --- a/src-tauri/src/api/agent/test/agent_org.rs +++ b/src-tauri/src/api/agent/test/agent_org.rs @@ -1532,7 +1532,7 @@ pub async fn test_agent_org_durable_invariants( let conn = database::db::get_connection().map_err(|err| err.to_string())?; let run_row: Option<(String, Option)> = conn .query_row( - "SELECT status, root_session_id FROM agent_org_runtime_runs WHERE id = ?1", + "SELECT status, root_session_id FROM agent_org_execution_runs WHERE id = ?1", params![org_run_id], |row| Ok((row.get(0)?, row.get(1)?)), ) @@ -1544,7 +1544,7 @@ pub async fn test_agent_org_durable_invariants( let open_task_count: i64 = conn .query_row( - "SELECT COUNT(*) FROM agent_org_runtime_tasks + "SELECT COUNT(*) FROM agent_org_execution_tasks WHERE org_run_id = ?1 AND status IN ('pending', 'in_progress')", params![org_run_id], |row| row.get(0), @@ -1552,7 +1552,7 @@ pub async fn test_agent_org_durable_invariants( .map_err(|err| err.to_string())?; let ownerless_in_progress_count: i64 = conn .query_row( - "SELECT COUNT(*) FROM agent_org_runtime_tasks + "SELECT COUNT(*) FROM agent_org_execution_tasks WHERE org_run_id = ?1 AND status = 'in_progress' AND (owner IS NULL OR TRIM(owner) = '')", @@ -1562,7 +1562,7 @@ pub async fn test_agent_org_durable_invariants( .map_err(|err| err.to_string())?; let unread_inbox_count: i64 = conn .query_row( - "SELECT COUNT(*) FROM agent_org_runtime_inbox + "SELECT COUNT(*) FROM agent_org_execution_inbox WHERE org_run_id = ?1 AND read_at IS NULL", params![org_run_id], |row| row.get(0), @@ -1920,7 +1920,7 @@ pub async fn test_agent_org_session_delete_snapshot( for run_id in run_ids { let exists = conn .query_row( - "SELECT EXISTS(SELECT 1 FROM agent_org_runtime_runs WHERE id=?1)", + "SELECT EXISTS(SELECT 1 FROM agent_org_execution_runs WHERE id=?1)", [&run_id], |row| row.get::<_, bool>(0), ) @@ -1931,8 +1931,8 @@ pub async fn test_agent_org_session_delete_snapshot( "SELECT run.status,run.activation_generation,run.archived_at, run.archive_receipt_id,archive.teardown_status, archive.teardown_attempt_count,archive.retained_runtime_count - FROM agent_org_runtime_runs run - LEFT JOIN agent_org_runtime_archive_episodes archive + FROM agent_org_execution_runs run + LEFT JOIN agent_org_execution_archive_episodes archive ON archive.org_run_id=run.id WHERE run.id=?1", [&run_id], @@ -2653,7 +2653,7 @@ pub async fn test_agent_org_run_cleanup( let mut stmt = conn .prepare( "SELECT id - FROM agent_org_runtime_runs + FROM agent_org_execution_runs WHERE org_id LIKE ?1 AND (?2 IS NULL OR id = ?2)", ) @@ -3035,7 +3035,7 @@ pub async fn test_agent_org_seed_crashed_task_execution( routine_fire_id: None, })?; conn.execute( - "INSERT INTO agent_org_runtime_member_materializations( + "INSERT INTO agent_org_execution_member_materializations( org_run_id,member_id,agent_id,generation,session_id, authority_class,status,created_at,updated_at ) VALUES (?1,?2,?3,1,?4,'formal','succeeded',?5,?5)", @@ -3052,7 +3052,7 @@ pub async fn test_agent_org_seed_crashed_task_execution( ) .map_err(|error| error.to_string())?; conn.execute( - "INSERT INTO agent_org_runtime_turn_contexts( + "INSERT INTO agent_org_execution_turn_contexts( session_id,turn_intent_id,org_run_id,participant_id,turn_kind, source_kind,source_id,activation_generation,created_at ) VALUES (?1,?2,?3,'coordinator','coordinator','root_turn',?2,1,?4)", @@ -3089,7 +3089,7 @@ pub async fn test_agent_org_seed_crashed_task_execution( ) .map_err(|error| error.to_string())?; conn.execute( - "INSERT INTO agent_org_runtime_turn_contexts( + "INSERT INTO agent_org_execution_turn_contexts( session_id,turn_intent_id,org_run_id,participant_id,turn_kind, task_id,owner_member_id,dispatch_member_id,member_dispatch_sequence, source_kind,source_id,activation_generation,created_at @@ -3299,7 +3299,7 @@ pub async fn test_agent_org_simulate_app_restart() -> Json { .map_err(|err| format!("open sessions DB for recovery inspection failed: {err}"))?; let interventions_preserved: i64 = conn .query_row( - "SELECT COUNT(*) FROM agent_org_runtime_member_interventions + "SELECT COUNT(*) FROM agent_org_execution_member_interventions WHERE status IN ('yield_requested','active','return_requested')", [], |row| row.get(0), @@ -3522,7 +3522,7 @@ pub async fn test_agent_org_pause_evidence( let conn = database::db::get_connection().map_err(|error| error.to_string())?; let (run_status, activation_generation): (String, i64) = conn .query_row( - "SELECT status,activation_generation FROM agent_org_runtime_runs WHERE id=?1", + "SELECT status,activation_generation FROM agent_org_execution_runs WHERE id=?1", [&query_run_id], |row| Ok((row.get(0)?, row.get(1)?)), ) @@ -3530,7 +3530,7 @@ pub async fn test_agent_org_pause_evidence( let episode: Option<(String, String, i64, Option)> = conn .query_row( "SELECT episode_id,status,pause_generation,resume_generation - FROM agent_org_runtime_pause_episodes + FROM agent_org_execution_pause_episodes WHERE org_run_id=?1 ORDER BY created_at DESC LIMIT 1", [&query_run_id], |row| Ok((row.get(0)?, row.get(1)?, row.get(2)?, row.get(3)?)), @@ -3548,8 +3548,8 @@ pub async fn test_agent_org_pause_evidence( handoff.dialog_turn_generation,handoff.drain_timeout_at, handoff.continuation_turn_intent_id,handoff.continuation_status, handoff.skip_reason,context.member_dispatch_sequence - FROM agent_org_runtime_pause_handoffs handoff - LEFT JOIN agent_org_runtime_turn_contexts context + FROM agent_org_execution_pause_handoffs handoff + LEFT JOIN agent_org_execution_turn_contexts context ON context.session_id=handoff.session_id AND context.turn_intent_id=handoff.continuation_turn_intent_id WHERE handoff.episode_id=?1 @@ -3586,7 +3586,7 @@ pub async fn test_agent_org_pause_evidence( if session_ids.is_empty() { let mut statement = conn .prepare( - "SELECT session_id FROM agent_org_runtime_member_materializations + "SELECT session_id FROM agent_org_execution_member_materializations WHERE org_run_id=?1 AND status='succeeded' ORDER BY member_id", ) .map_err(|error| error.to_string())?; @@ -3600,7 +3600,7 @@ pub async fn test_agent_org_pause_evidence( session_ids.dedup(); let mut task_statement = conn .prepare( - "SELECT id,status,owner,updated_at FROM agent_org_runtime_tasks + "SELECT id,status,owner,updated_at FROM agent_org_execution_tasks WHERE org_run_id=?1 ORDER BY id", ) .map_err(|error| error.to_string())?; @@ -3618,7 +3618,7 @@ pub async fn test_agent_org_pause_evidence( .map_err(|error| error.to_string())?; let inbox_count: i64 = conn .query_row( - "SELECT COUNT(*) FROM agent_org_runtime_inbox WHERE org_run_id=?1", + "SELECT COUNT(*) FROM agent_org_execution_inbox WHERE org_run_id=?1", [&query_run_id], |row| row.get(0), ) diff --git a/src-tauri/src/api/agent/test/agent_org_user_directed.rs b/src-tauri/src/api/agent/test/agent_org_user_directed.rs index f96455ea05..6c9a50d85b 100644 --- a/src-tauri/src/api/agent/test/agent_org_user_directed.rs +++ b/src-tauri/src/api/agent/test/agent_org_user_directed.rs @@ -56,7 +56,7 @@ fn load_evidence(org_run_id: &str) -> Result { "SELECT delivery_id,session_id,turn_intent_id,root_authority_turn_id, parent_delivery_id,parent_inbox_id,source_kind,source_inbox_id, dispatch_member_id,member_dispatch_sequence,depth,delivery_ordinal,status - FROM agent_org_runtime_user_directed_deliveries + FROM agent_org_execution_user_directed_deliveries WHERE org_run_id=?1 ORDER BY delivery_id LIMIT 200", @@ -89,7 +89,7 @@ fn load_evidence(org_run_id: &str) -> Result { "SELECT binding_id,session_id,turn_intent_id,root_authority_turn_id, parent_delivery_id,parent_inbox_id,source_inbox_id,depth, delivery_ordinal,status - FROM agent_org_runtime_user_directed_coordinator_bindings + FROM agent_org_execution_user_directed_coordinator_bindings WHERE org_run_id=?1 ORDER BY binding_id LIMIT 200", @@ -117,7 +117,7 @@ fn load_evidence(org_run_id: &str) -> Result { let mut inbox_statement = conn .prepare( "SELECT id,recipient_member_id,sender_member_id,read_at - FROM agent_org_runtime_inbox + FROM agent_org_execution_inbox WHERE org_run_id=?1 AND delivery_class='user_directed' ORDER BY id LIMIT 200", @@ -140,7 +140,7 @@ fn load_evidence(org_run_id: &str) -> Result { .prepare( "SELECT session_id,turn_intent_id,member_id,reservation_id, runtime_lease_id,status,reason_code - FROM agent_org_member_turn_admissions + FROM agent_org_execution_member_turn_admissions WHERE org_run_id=?1 ORDER BY prepared_at,session_id,turn_intent_id LIMIT 200", @@ -165,15 +165,15 @@ fn load_evidence(org_run_id: &str) -> Result { let (root_count, context_count, intent_count, tool_receipt_count): (i64, i64, i64, i64) = conn .query_row( "SELECT - (SELECT COUNT(*) FROM agent_org_runtime_user_directed_roots + (SELECT COUNT(*) FROM agent_org_execution_user_directed_roots WHERE org_run_id=?1), - (SELECT COUNT(*) FROM agent_org_runtime_turn_contexts + (SELECT COUNT(*) FROM agent_org_execution_turn_contexts WHERE org_run_id=?1 AND ( turn_kind='user_directed_work' OR (turn_kind='coordinator' AND source_kind='member_inbox') )), (SELECT COUNT(*) FROM session_turn_intents WHERE org_run_id=?1), - (SELECT COUNT(*) FROM agent_org_runtime_tool_call_receipts + (SELECT COUNT(*) FROM agent_org_execution_tool_call_receipts WHERE org_run_id=?1)", params![org_run_id], |row| Ok((row.get(0)?, row.get(1)?, row.get(2)?, row.get(3)?)), diff --git a/src-tauri/src/commands/handler_list.inc b/src-tauri/src/commands/handler_list.inc index a4f526a7fb..8bf462bfb6 100644 --- a/src-tauri/src/commands/handler_list.inc +++ b/src-tauri/src/commands/handler_list.inc @@ -835,6 +835,8 @@ agent_core::state::commands::session::debug::org_runtime::debug_agent_org_emit_m agent_core::state::commands::session::debug::org_runtime::debug_agent_org_inbox_list, agent_core::state::commands::session::debug::org_runtime::debug_agent_org_tasks_list, agent_core::state::commands::session::org_tasks::agent_org_session_run_view, +agent_core::state::commands::session::org_tasks::agent_org_history_descriptor, +agent_core::state::commands::session::org_tasks::agent_org_history_page, agent_core::state::commands::session::org_tasks::agent_org_session_task_page, agent_core::state::commands::session::org_tasks::agent_org_session_task_detail, agent_core::state::commands::session::org_tasks::agent_org_session_task_annotation_page, diff --git a/src-tauri/src/test_utils/test_env.rs b/src-tauri/src/test_utils/test_env.rs index 5be4fd693b..67db0773bf 100644 --- a/src-tauri/src/test_utils/test_env.rs +++ b/src-tauri/src/test_utils/test_env.rs @@ -98,27 +98,27 @@ mod tests { assert!(schema_object_exists( &conn, "table", - "agent_org_runtime_run_progress" + "agent_org_execution_run_progress" )); assert!(column_exists( &conn, - "agent_org_runtime_run_progress", + "agent_org_execution_run_progress", "work_revision" )); assert!(schema_object_exists( &conn, "table", - "agent_org_runtime_recovery_attempts" + "agent_org_execution_recovery_attempts" )); assert!(column_exists( &conn, - "agent_org_runtime_inbox", + "agent_org_execution_inbox", "causation_inbox_id" )); assert!(schema_object_exists( &conn, "index", - "idx_agent_org_runtime_inbox_causation_recipient_once" + "idx_agent_org_execution_inbox_causation_recipient_once" )); } } diff --git a/src/api/tauri/agent/orgTasks/errors.ts b/src/api/tauri/agent/orgTasks/errors.ts index 9b29b368bd..eac3abca05 100644 --- a/src/api/tauri/agent/orgTasks/errors.ts +++ b/src/api/tauri/agent/orgTasks/errors.ts @@ -1,5 +1,6 @@ export const AGENT_ORG_FINALIZING_INPUT_NOT_ACCEPTED = "agent_org_finalizing_input_not_accepted"; +export const AGENT_ORG_HISTORY_READ_ONLY = "agent_org_history_read_only"; export function isAgentOrgFinalizingInputError(error: unknown): boolean { const message = error instanceof Error ? error.message : String(error); diff --git a/src/api/tauri/agent/orgTasks/history.test.ts b/src/api/tauri/agent/orgTasks/history.test.ts new file mode 100644 index 0000000000..59a62fd957 --- /dev/null +++ b/src/api/tauri/agent/orgTasks/history.test.ts @@ -0,0 +1,60 @@ +import { afterEach, describe, expect, it, vi } from "vitest"; + +import { invokeTauri } from "@src/util/platform/tauri/init"; + +import { getAgentOrgHistoryDescriptor } from "./history"; + +vi.mock("@src/util/platform/tauri/init", () => ({ invokeTauri: vi.fn() })); +const invoke = vi.mocked(invokeTauri); + +afterEach(() => vi.clearAllMocks()); + +describe("history descriptor request ownership", () => { + it("shares pending lookups but drops completed results", async () => { + let resolve!: (value: null) => void; + invoke.mockImplementation( + () => + new Promise((done) => { + resolve = done; + }) + ); + const first = getAgentOrgHistoryDescriptor("session"); + expect(getAgentOrgHistoryDescriptor("session")).toBe(first); + expect(invoke).toHaveBeenCalledTimes(1); + resolve(null); + await first; + invoke.mockResolvedValue(null); + await getAgentOrgHistoryDescriptor("session"); + expect(invoke).toHaveBeenCalledTimes(2); + }); + + it("allows explicit retry after failure", async () => { + invoke.mockRejectedValueOnce(new Error("offline")); + await expect(getAgentOrgHistoryDescriptor("retry")).rejects.toThrow( + "offline" + ); + invoke.mockResolvedValueOnce(null); + await expect(getAgentOrgHistoryDescriptor("retry")).resolves.toBeNull(); + expect(invoke).toHaveBeenCalledTimes(2); + }); + + it("bounds retained pending identities without blocking new lookups", async () => { + const resolvers: ((value: null) => void)[] = []; + invoke.mockImplementation( + () => + new Promise((done) => { + resolvers.push(done); + }) + ); + const requests = Array.from({ length: 128 }, (_, index) => + getAgentOrgHistoryDescriptor(`session-${index}`) + ); + expect(getAgentOrgHistoryDescriptor("session-0")).toBe(requests[0]); + const overflow = getAgentOrgHistoryDescriptor("overflow"); + const overflowAgain = getAgentOrgHistoryDescriptor("overflow"); + expect(overflow).not.toBe(overflowAgain); + expect(invoke).toHaveBeenCalledTimes(130); + resolvers.forEach((resolve) => resolve(null)); + await Promise.all([...requests, overflow, overflowAgain]); + }); +}); diff --git a/src/api/tauri/agent/orgTasks/history.ts b/src/api/tauri/agent/orgTasks/history.ts new file mode 100644 index 0000000000..2020f69b55 --- /dev/null +++ b/src/api/tauri/agent/orgTasks/history.ts @@ -0,0 +1,61 @@ +import { invokeTauri } from "@src/util/platform/tauri/init"; + +export interface AgentOrgHistoryDescriptor { + mode: "current" | "history_only"; + rootSessionId: string | null; + title: string | null; + members: { + sessionId: string; + memberId: string | null; + name: string | null; + }[]; +} + +export interface AgentOrgHistoryItem { + id: string; + sourceSessionId: string | null; + kind: string; + content: string; + createdAt: string; +} + +export interface AgentOrgHistoryPage { + items: AgentOrgHistoryItem[]; + nextCursor: string | null; +} + +// Only pending requests are retained; opening two surfaces shares their lookup. +// Completed lookups leave no app-lifetime session cache to invalidate. +const pendingDescriptors = new Map< + string, + Promise +>(); + +export function getAgentOrgHistoryDescriptor(sessionId: string) { + const existing = pendingDescriptors.get(sessionId); + if (existing) return existing; + const request = invokeTauri( + "agent_org_history_descriptor", + { sessionId } + ); + if (pendingDescriptors.size < 128) { + const pending = request.finally(() => { + if (pendingDescriptors.get(sessionId) === pending) + pendingDescriptors.delete(sessionId); + }); + pendingDescriptors.set(sessionId, pending); + return pending; + } + return request; +} + +export function getAgentOrgHistoryPage( + sessionId: string, + cursor: string | null +) { + return invokeTauri("agent_org_history_page", { + sessionId, + cursor, + limit: 50, + }); +} diff --git a/src/api/tauri/rpc/schemas/sessionAggregate.ts b/src/api/tauri/rpc/schemas/sessionAggregate.ts index 34d37d534c..6c650646a6 100644 --- a/src/api/tauri/rpc/schemas/sessionAggregate.ts +++ b/src/api/tauri/rpc/schemas/sessionAggregate.ts @@ -234,6 +234,7 @@ export const SessionAggregateRecordSchema = z.object({ parentSessionId: z.string().optional(), orgMemberId: z.string().optional(), agentOrgId: z.string().optional(), + agentOrgMode: z.enum(["current", "history_only"]).optional(), agentOrgName: z.string().optional(), agentDefinitionId: z.string().optional(), agentIconId: z.string().optional(), diff --git a/src/api/tauri/session/index.ts b/src/api/tauri/session/index.ts index b8800a4161..97a511cf07 100644 --- a/src/api/tauri/session/index.ts +++ b/src/api/tauri/session/index.ts @@ -163,6 +163,7 @@ export function toFrontendSession(record: SessionAggregateRecord): Session { parentSessionId: record.parentSessionId, orgMemberId: record.orgMemberId, agentOrgId: record.agentOrgId, + agentOrgMode: record.agentOrgMode, agentOrgName: record.agentOrgName, agentDefinitionId: record.agentDefinitionId, agentIconId: importedSource?.iconId ?? record.agentIconId, diff --git a/src/engines/ChatPanel/AgentOrgHistoryBoundary.test.ts b/src/engines/ChatPanel/AgentOrgHistoryBoundary.test.ts new file mode 100644 index 0000000000..552a60345d --- /dev/null +++ b/src/engines/ChatPanel/AgentOrgHistoryBoundary.test.ts @@ -0,0 +1,178 @@ +// @vitest-environment jsdom +import { act, createElement } from "react"; +import { type Root, createRoot } from "react-dom/client"; +import { afterEach, beforeEach, describe, expect, it, vi } from "vitest"; + +import { + getAgentOrgHistoryDescriptor, + getAgentOrgHistoryPage, +} from "@src/api/tauri/agent/orgTasks/history"; +import type { AgentOrgHistoryDescriptor } from "@src/api/tauri/agent/orgTasks/history"; +import { useTestTranslation } from "@src/test/i18nTestTranslate"; + +import AgentOrgHistoryBoundary from "./AgentOrgHistoryBoundary"; + +vi.mock("@src/api/tauri/agent/orgTasks/history", () => ({ + getAgentOrgHistoryDescriptor: vi.fn(), + getAgentOrgHistoryPage: vi.fn(), +})); +vi.mock("react-i18next", () => ({ + useTranslation: (...args: Parameters) => + useTestTranslation(...args), +})); +vi.mock("@src/components/MarkDown", () => ({ + default: ({ textContent }: { textContent: string }) => + createElement("div", null, textContent), +})); +vi.mock("./InputArea/components/SessionReadOnlyBar", () => ({ + default: ({ label }: { label: string }) => + createElement("div", { "data-read-only": true }, label), +})); + +const history: AgentOrgHistoryDescriptor = { + mode: "history_only", + rootSessionId: "sdeagent-root", + title: "Old team", + members: [ + { sessionId: "sdeagent-root", memberId: null, name: "Team" }, + { sessionId: "sdeagent-member", memberId: "alice", name: "Alice" }, + ], +}; +const descriptor = vi.mocked(getAgentOrgHistoryDescriptor); +const page = vi.mocked(getAgentOrgHistoryPage); +const environment = globalThis as typeof globalThis & { + IS_REACT_ACT_ENVIRONMENT?: boolean; +}; + +describe("AgentOrgHistoryBoundary", () => { + let container: HTMLDivElement; + let root: Root; + const renderTranscript = vi.fn((sessionId: string, readOnly: boolean) => + createElement("div", { + "data-transcript": sessionId, + "data-readonly": String(readOnly), + }) + ); + beforeEach(() => { + vi.clearAllMocks(); + environment.IS_REACT_ACT_ENVIRONMENT = true; + container = document.createElement("div"); + document.body.appendChild(container); + root = createRoot(container); + descriptor.mockResolvedValue(history); + page.mockResolvedValue({ items: [], nextCursor: null }); + }); + afterEach(() => { + act(() => root.unmount()); + container.remove(); + Reflect.deleteProperty(environment, "IS_REACT_ACT_ENVIRONMENT"); + }); + async function open(sessionId = "sdeagent-root") { + await act(async () => { + root.render( + createElement(AgentOrgHistoryBoundary, { + sessionId, + renderTranscript, + }) + ); + }); + } + async function click(text: string) { + const target = [...container.querySelectorAll("button")].find((button) => + button.textContent?.includes(text) + ); + expect(target, `button ${text}`).toBeDefined(); + await act(async () => target?.click()); + } + it("resolves persisted identity before mounting any writable transcript", async () => { + let resolve!: (value: AgentOrgHistoryDescriptor | null) => void; + descriptor.mockImplementation( + () => + new Promise((done) => { + resolve = done; + }) + ); + await open(); + expect(renderTranscript).not.toHaveBeenCalled(); + await act(async () => resolve(history)); + expect(renderTranscript).toHaveBeenLastCalledWith("sdeagent-root", true); + expect(container.textContent).toContain( + "Older-version conversation, view only" + ); + await click("Alice"); + expect(renderTranscript).toHaveBeenLastCalledWith("sdeagent-member", true); + expect(descriptor).toHaveBeenCalledOnce(); + }); + it("keeps ordinary sessions writable", async () => { + descriptor.mockResolvedValue(null); + await open("sdeagent-ordinary"); + expect(renderTranscript).toHaveBeenLastCalledWith( + "sdeagent-ordinary", + false + ); + expect(container.querySelector("[data-read-only]")).toBeNull(); + }); + it("ignores a late identity result after switching sessions", async () => { + let resolve!: (value: AgentOrgHistoryDescriptor | null) => void; + descriptor + .mockImplementationOnce( + () => + new Promise((done) => { + resolve = done; + }) + ) + .mockResolvedValue(null); + await open(); + await open("sdeagent-ordinary"); + await act(async () => resolve(history)); + expect(renderTranscript).toHaveBeenLastCalledWith( + "sdeagent-ordinary", + false + ); + }); + it("loads saved content only when opened and retains a bounded page", async () => { + page + .mockResolvedValueOnce({ + items: [ + { + id: "one", + sourceSessionId: null, + kind: "output", + content: "First saved output", + createdAt: "2026-09-24", + }, + ], + nextCursor: "next", + }) + .mockResolvedValueOnce({ + items: [ + { + id: "two", + sourceSessionId: null, + kind: "output", + content: "Second saved output", + createdAt: "2026-09-25", + }, + ], + nextCursor: null, + }); + await open(); + expect(page).not.toHaveBeenCalled(); + await click("Saved group messages"); + expect(container.textContent).toContain("First saved output"); + await click("Next page"); + expect(page).toHaveBeenLastCalledWith("sdeagent-root", "next"); + expect(container.textContent).toContain("Second saved output"); + expect(container.textContent).not.toContain("First saved output"); + }); + it("fails closed on lookup failure and retries only on user action", async () => { + descriptor + .mockRejectedValueOnce(new Error("offline")) + .mockResolvedValueOnce(history); + await open(); + expect(renderTranscript).not.toHaveBeenCalled(); + expect(descriptor).toHaveBeenCalledOnce(); + await click("Retry"); + expect(renderTranscript).toHaveBeenLastCalledWith("sdeagent-root", true); + }); +}); diff --git a/src/engines/ChatPanel/AgentOrgHistoryBoundary.tsx b/src/engines/ChatPanel/AgentOrgHistoryBoundary.tsx new file mode 100644 index 0000000000..fc95a200e3 --- /dev/null +++ b/src/engines/ChatPanel/AgentOrgHistoryBoundary.tsx @@ -0,0 +1,229 @@ +import React, { useEffect, useState } from "react"; +import { useTranslation } from "react-i18next"; + +import { + getAgentOrgHistoryDescriptor, + getAgentOrgHistoryPage, +} from "@src/api/tauri/agent/orgTasks/history"; +import type { + AgentOrgHistoryDescriptor, + AgentOrgHistoryPage, +} from "@src/api/tauri/agent/orgTasks/history"; +import Button from "@src/components/Button"; +import Markdown from "@src/components/MarkDown"; +import { + isCliSession, + isImportedHistorySession, +} from "@src/util/session/sessionDispatch"; + +import SessionReadOnlyBar from "./InputArea/components/SessionReadOnlyBar"; + +interface Props { + sessionId: string; + renderTranscript: ( + sessionId: string, + historyOnly: boolean + ) => React.ReactNode; +} + +/** Resolves identity once per open; history never subscribes to live run polling. */ +export default function AgentOrgHistoryBoundary({ + sessionId, + renderTranscript, +}: Props) { + const { t } = useTranslation("sessions"); + const [resolved, setResolved] = useState<{ + key: string; + value: AgentOrgHistoryDescriptor | null; + error: string | null; + } | null>(null); + const [attempt, setAttempt] = useState(0); + const requestKey = JSON.stringify([sessionId, attempt]); + const native = + !isCliSession(sessionId) && !isImportedHistorySession(sessionId); + useEffect(() => { + if (!native) return; + let cancelled = false; + void getAgentOrgHistoryDescriptor(sessionId) + .then((value) => { + if (!cancelled) setResolved({ key: requestKey, value, error: null }); + }) + .catch((reason) => { + if (!cancelled) + setResolved({ key: requestKey, value: null, error: String(reason) }); + }); + return () => { + cancelled = true; + }; + }, [sessionId, requestKey, native]); + if (!native) return renderTranscript(sessionId, false); + const current = resolved?.key === requestKey ? resolved : null; + if (!current || current.error) { + return ( +
+ {current?.error ? ( +
+ {current.error} + +
+ ) : ( + t("agentOrgHistory.loading") + )} +
+ ); + } + if (current.value?.mode !== "history_only") + return renderTranscript(sessionId, false); + return ( + + ); +} + +function HistoricalSession({ + sessionId, + descriptor, + renderTranscript, +}: Props & { descriptor: AgentOrgHistoryDescriptor }) { + const { t } = useTranslation("sessions"); + const [selected, setSelected] = useState(sessionId); + const [showSaved, setShowSaved] = useState(false); + return ( +
+
+ {descriptor.members.map((member) => ( + + ))} + +
+
+ {showSaved ? ( + + ) : ( + renderTranscript(selected, true) + )} +
+
+ +
+
+ ); +} + +function SavedContent({ sessionId }: { sessionId: string }) { + const { t } = useTranslation("sessions"); + const [cursor, setCursor] = useState(null); + const [result, setResult] = useState<{ + key: string; + page: AgentOrgHistoryPage | null; + error: string | null; + } | null>(null); + const [attempt, setAttempt] = useState(0); + const requestKey = JSON.stringify([sessionId, cursor, attempt]); + const current = result?.key === requestKey ? result : null; + const page = current?.page; + const error = current?.error; + const loading = !current; + useEffect(() => { + let cancelled = false; + void getAgentOrgHistoryPage(sessionId, cursor) + .then((value) => { + if (!cancelled) + setResult({ key: requestKey, page: value, error: null }); + }) + .catch((reason) => { + if (!cancelled) + setResult({ key: requestKey, page: null, error: String(reason) }); + }); + return () => { + cancelled = true; + }; + }, [sessionId, cursor, requestKey]); + return ( +
+ {error && ( +
+ {error} + +
+ )} + {!loading && page?.items.length === 0 && ( +

{t("agentOrgHistory.empty")}

+ )} + {page?.items.map((item) => ( +
+ + +
+ ))} + {page?.nextCursor && ( + + )} + {cursor && ( + + )} +
+ ); +} diff --git a/src/engines/ChatPanel/ChatView.tsx b/src/engines/ChatPanel/ChatView.tsx index 2ae3989084..716eacd558 100644 --- a/src/engines/ChatPanel/ChatView.tsx +++ b/src/engines/ChatPanel/ChatView.tsx @@ -57,6 +57,7 @@ import { } from "@src/util/session/sessionDispatch"; import AgentOrgArchivedComposer from "./AgentOrgArchivedComposer"; +import AgentOrgHistoryBoundary from "./AgentOrgHistoryBoundary"; import { ChatSessionContext } from "./ChatSessionContext"; import { ChatViewComposerSection } from "./ChatViewComposerSection"; import type { ChatViewComposerSectionProps } from "./ChatViewComposerSection.types"; @@ -316,6 +317,7 @@ const ResolvedChatView: React.FC = memo( agentOrgInterventionSlot, } = useChatViewAgentOrgSurface({ sessionId, + readOnly, showCurrentPlanSurface, conversationRoot: conversationTargetBinding?.root ?? null, onBeforeMessageDispatch: handleBeforeMessageDispatch, @@ -664,15 +666,28 @@ const ChatViewWithLoadedBinding: React.FC< ChatViewWithLoadedBinding.displayName = "ChatViewWithLoadedBinding"; const ChatView: React.FC = memo( - ({ conversationTargetBinding, ...props }) => - conversationTargetBinding === undefined ? ( - - ) : ( - - ) + ({ conversationTargetBinding, ...props }) => ( + + historyOnly ? ( + + ) : conversationTargetBinding === undefined ? ( + + ) : ( + + ) + } + /> + ) ); ChatView.displayName = "ChatView"; diff --git a/src/engines/ChatPanel/InputArea/components/agentOrgRunViewStore.test.ts b/src/engines/ChatPanel/InputArea/components/agentOrgRunViewStore.test.ts index c96fd1cb68..3c2e821aff 100644 --- a/src/engines/ChatPanel/InputArea/components/agentOrgRunViewStore.test.ts +++ b/src/engines/ChatPanel/InputArea/components/agentOrgRunViewStore.test.ts @@ -123,6 +123,65 @@ afterEach(() => { }); describe("Agent Org run-view store", () => { + it("stops history discovery across shared surfaces and reconnects", async () => { + vi.useFakeTimers(); + let reconnect: (() => void) | undefined; + mocks.websocketOn.mockImplementation( + (event: string, handler: () => void) => { + if (event === "connected") reconnect = handler; + return mocks.unsubscribeBackendChanges; + } + ); + mocks.getAgentOrgSessionRunView.mockRejectedValue( + "agent_org_history_read_only" + ); + const closeChat = subscribeAgentOrgRunView("history-root", vi.fn()); + const closeStation = subscribeAgentOrgRunView("history-root", vi.fn()); + await flushPromises(); + expect(getAgentOrgRunViewSnapshot("history-root")).toEqual({ + view: null, + error: null, + }); + expect(agentOrgRunViewStoreTestApi.hasPollingTimer()).toBe(false); + reconnect?.(); + await vi.advanceTimersByTimeAsync(AGENT_ORG_RUN_VIEW_FALLBACK_MS * 5); + expect(mocks.getAgentOrgSessionRunView).toHaveBeenCalledTimes(1); + closeChat(); + closeStation(); + }); + + it("discards a retired projection while continuing to poll a current team", async () => { + vi.useFakeTimers(); + mocks.getAgentOrgSessionRunView.mockImplementation((sessionId: string) => + Promise.resolve(runViewForRoot("running", sessionId, sessionId)) + ); + const closeHistory = subscribeAgentOrgRunView("history-root", vi.fn()); + await flushPromises(); + const closeCurrent = subscribeAgentOrgRunView("current-root", vi.fn()); + await flushPromises(); + mocks.getAgentOrgSessionRunView.mockImplementation((sessionId: string) => + sessionId === "history-root" + ? Promise.reject(new Error("agent_org_history_read_only")) + : Promise.resolve(runViewForRoot("running", sessionId, sessionId)) + ); + await agentOrgRunViewStoreTestApi.refresh("history-root"); + expect(getAgentOrgRunViewSnapshot("history-root").view).toBeNull(); + const historyCalls = () => + mocks.getAgentOrgSessionRunView.mock.calls.filter( + ([sessionId]) => sessionId === "history-root" + ).length; + const before = historyCalls(); + await vi.advanceTimersByTimeAsync(AGENT_ORG_RUN_VIEW_FALLBACK_MS * 2); + expect(historyCalls()).toBe(before); + expect(agentOrgRunViewStoreTestApi.hasPollingTimer()).toBe(true); + expect(getAgentOrgRunViewSnapshot("current-root").view?.runStatus).toBe( + "running" + ); + closeHistory(); + closeCurrent(); + expect(agentOrgRunViewStoreTestApi.hasPollingTimer()).toBe(false); + }); + it("shares one fallback per run, coalesces pushes, and stops immediately on Idle", async () => { vi.useFakeTimers(); let stateChangeHandler: ((sessionId: string) => void) | undefined; diff --git a/src/engines/ChatPanel/InputArea/components/agentOrgRunViewStore.ts b/src/engines/ChatPanel/InputArea/components/agentOrgRunViewStore.ts index 5ba0202e3d..cfdfbb0b23 100644 --- a/src/engines/ChatPanel/InputArea/components/agentOrgRunViewStore.ts +++ b/src/engines/ChatPanel/InputArea/components/agentOrgRunViewStore.ts @@ -5,6 +5,7 @@ import { getAgentOrgSessionRunView, subscribeAgentOrgStateChanges, } from "@src/api/tauri/agent/orgTasks"; +import { AGENT_ORG_HISTORY_READ_ONLY } from "@src/api/tauri/agent/orgTasks/errors"; export const AGENT_ORG_RUN_VIEW_FALLBACK_MS = 60_000; export const AGENT_ORG_RUN_VIEW_PUSH_DEBOUNCE_MS = 50; @@ -362,6 +363,14 @@ function refreshAgentOrgRunViewInternal( .catch((error: unknown) => { if (!isCurrentEntry(entry)) return; const message = error instanceof Error ? error.message : String(error); + if (message === AGENT_ORG_HISTORY_READ_ONLY) { + // Other surfaces can discover history without mounting ChatView. + // Retirement is authoritative: stop discovery and discard live views. + missingRunReplacement = publishMissingRun(entry, requestId); + // Discovery changed even when the empty snapshot stayed identical. + reconcilePollingTimer(); + return; + } publishEntry(entry, entry.snapshot.view, message, requestId); }) .finally(() => { diff --git a/src/engines/ChatPanel/hooks/useChatViewAgentOrgSurface.tsx b/src/engines/ChatPanel/hooks/useChatViewAgentOrgSurface.tsx index bba5a77dca..f753f537f1 100644 --- a/src/engines/ChatPanel/hooks/useChatViewAgentOrgSurface.tsx +++ b/src/engines/ChatPanel/hooks/useChatViewAgentOrgSurface.tsx @@ -29,11 +29,13 @@ import { useChatViewMessageQueue } from "./useChatViewMessageQueue"; export function useChatViewAgentOrgSurface({ sessionId, + readOnly = false, showCurrentPlanSurface, conversationRoot, onBeforeMessageDispatch, }: { sessionId: string; + readOnly?: boolean; showCurrentPlanSurface: boolean; conversationRoot: ConversationRootLocator | null; onBeforeMessageDispatch?: () => void; @@ -42,7 +44,7 @@ export function useChatViewAgentOrgSurface({ view: agentOrgRunView, error: agentOrgRunViewError, refresh: refreshAgentOrgRunView, - } = useAgentOrgRunView(sessionId); + } = useAgentOrgRunView(readOnly ? null : sessionId); // The dropdown's "current member" highlight should follow the // pipeline session, not the backend's `currentMemberId`. The // member selector now flips only the pipeline atom (via diff --git a/src/i18n/locales/de/sessions.json b/src/i18n/locales/de/sessions.json index 844abb7101..a3254ec33e 100644 --- a/src/i18n/locales/de/sessions.json +++ b/src/i18n/locales/de/sessions.json @@ -1,4 +1,14 @@ { + "agentOrgHistory": { + "readOnly": "Unterhaltung einer älteren Version, nur lesbar", + "savedContent": "Gespeicherte Gruppennachrichten und Ausgaben", + "unknownMember": "Unbekanntes Mitglied", + "loading": "Verlauf wird geladen…", + "retry": "Erneut versuchen", + "empty": "Keine gespeicherten Gruppeninhalte", + "nextPage": "Nächste Seite", + "firstPage": "Erste Seite" + }, "agentOrgExecution": { "sources": { "user_input": "Benutzeranfrage", diff --git a/src/i18n/locales/en/sessions.json b/src/i18n/locales/en/sessions.json index 79880353a4..be721d9d2e 100644 --- a/src/i18n/locales/en/sessions.json +++ b/src/i18n/locales/en/sessions.json @@ -1,4 +1,14 @@ { + "agentOrgHistory": { + "readOnly": "Older-version conversation, view only", + "savedContent": "Saved group messages and outputs", + "unknownMember": "Unknown member", + "loading": "Loading history…", + "retry": "Retry", + "empty": "No saved group content", + "nextPage": "Next page", + "firstPage": "First page" + }, "agentOrgExecution": { "sources": { "user_input": "User request", diff --git a/src/i18n/locales/es/sessions.json b/src/i18n/locales/es/sessions.json index fa7f93f927..e06f427df4 100644 --- a/src/i18n/locales/es/sessions.json +++ b/src/i18n/locales/es/sessions.json @@ -1,4 +1,14 @@ { + "agentOrgHistory": { + "readOnly": "Conversación de una versión anterior, solo lectura", + "savedContent": "Mensajes y resultados del grupo guardados", + "unknownMember": "Miembro desconocido", + "loading": "Cargando historial…", + "retry": "Reintentar", + "empty": "No hay contenido de grupo guardado", + "nextPage": "Página siguiente", + "firstPage": "Primera página" + }, "agentOrgExecution": { "sources": { "user_input": "Solicitud del usuario", diff --git a/src/i18n/locales/fr/sessions.json b/src/i18n/locales/fr/sessions.json index 1d6bc41dab..b123578bf1 100644 --- a/src/i18n/locales/fr/sessions.json +++ b/src/i18n/locales/fr/sessions.json @@ -1,4 +1,14 @@ { + "agentOrgHistory": { + "readOnly": "Conversation d’une ancienne version, lecture seule", + "savedContent": "Messages et résultats de groupe enregistrés", + "unknownMember": "Membre inconnu", + "loading": "Chargement de l’historique…", + "retry": "Réessayer", + "empty": "Aucun contenu de groupe enregistré", + "nextPage": "Page suivante", + "firstPage": "Première page" + }, "agentOrgExecution": { "sources": { "user_input": "Demande utilisateur", diff --git a/src/i18n/locales/hi/sessions.json b/src/i18n/locales/hi/sessions.json index 354635546f..c976238e80 100644 --- a/src/i18n/locales/hi/sessions.json +++ b/src/i18n/locales/hi/sessions.json @@ -1,4 +1,14 @@ { + "agentOrgHistory": { + "readOnly": "पुराने संस्करण की बातचीत, केवल देखने के लिए", + "savedContent": "सहेजे गए समूह संदेश और परिणाम", + "unknownMember": "अज्ञात सदस्य", + "loading": "इतिहास लोड हो रहा है…", + "retry": "फिर कोशिश करें", + "empty": "कोई समूह सामग्री सहेजी नहीं गई", + "nextPage": "अगला पृष्ठ", + "firstPage": "पहला पृष्ठ" + }, "agentOrgExecution": { "sources": { "user_input": "उपयोगकर्ता का अनुरोध", diff --git a/src/i18n/locales/id/sessions.json b/src/i18n/locales/id/sessions.json index d0da88b8c7..cfb0e41d4b 100644 --- a/src/i18n/locales/id/sessions.json +++ b/src/i18n/locales/id/sessions.json @@ -1,4 +1,14 @@ { + "agentOrgHistory": { + "readOnly": "Percakapan versi lama, hanya lihat", + "savedContent": "Pesan grup dan keluaran tersimpan", + "unknownMember": "Anggota tidak dikenal", + "loading": "Memuat riwayat…", + "retry": "Coba lagi", + "empty": "Tidak ada konten grup tersimpan", + "nextPage": "Halaman berikutnya", + "firstPage": "Halaman pertama" + }, "agentOrgExecution": { "sources": { "user_input": "Permintaan pengguna", diff --git a/src/i18n/locales/ja/sessions.json b/src/i18n/locales/ja/sessions.json index dae6a6be1e..72620a812d 100644 --- a/src/i18n/locales/ja/sessions.json +++ b/src/i18n/locales/ja/sessions.json @@ -1,4 +1,14 @@ { + "agentOrgHistory": { + "readOnly": "旧バージョンの会話(閲覧のみ)", + "savedContent": "保存済みのグループ会話と出力", + "unknownMember": "不明なメンバー", + "loading": "履歴を読み込み中…", + "retry": "再試行", + "empty": "保存済みのグループ内容はありません", + "nextPage": "次のページ", + "firstPage": "最初のページ" + }, "agentOrgExecution": { "sources": { "user_input": "ユーザーの依頼", diff --git a/src/i18n/locales/ko/sessions.json b/src/i18n/locales/ko/sessions.json index c1e4e7cde1..500bdd2c35 100644 --- a/src/i18n/locales/ko/sessions.json +++ b/src/i18n/locales/ko/sessions.json @@ -1,4 +1,14 @@ { + "agentOrgHistory": { + "readOnly": "이전 버전 대화, 보기 전용", + "savedContent": "저장된 그룹 대화 및 출력", + "unknownMember": "알 수 없는 멤버", + "loading": "기록 불러오는 중…", + "retry": "다시 시도", + "empty": "저장된 그룹 내용 없음", + "nextPage": "다음 페이지", + "firstPage": "첫 페이지" + }, "agentOrgExecution": { "sources": { "user_input": "사용자 요청", diff --git a/src/i18n/locales/pl/sessions.json b/src/i18n/locales/pl/sessions.json index c1cadb8c53..b5f1d3d71d 100644 --- a/src/i18n/locales/pl/sessions.json +++ b/src/i18n/locales/pl/sessions.json @@ -1,4 +1,14 @@ { + "agentOrgHistory": { + "readOnly": "Rozmowa ze starszej wersji, tylko do odczytu", + "savedContent": "Zapisane wiadomości i wyniki grupy", + "unknownMember": "Nieznany członek", + "loading": "Ładowanie historii…", + "retry": "Ponów", + "empty": "Brak zapisanej zawartości grupy", + "nextPage": "Następna strona", + "firstPage": "Pierwsza strona" + }, "agentOrgExecution": { "sources": { "user_input": "Prośba użytkownika", diff --git a/src/i18n/locales/pt/sessions.json b/src/i18n/locales/pt/sessions.json index 97458cdc58..6df0f53da5 100644 --- a/src/i18n/locales/pt/sessions.json +++ b/src/i18n/locales/pt/sessions.json @@ -1,4 +1,14 @@ { + "agentOrgHistory": { + "readOnly": "Conversa de versão anterior, somente leitura", + "savedContent": "Mensagens e resultados do grupo salvos", + "unknownMember": "Membro desconhecido", + "loading": "Carregando histórico…", + "retry": "Tentar novamente", + "empty": "Nenhum conteúdo de grupo salvo", + "nextPage": "Próxima página", + "firstPage": "Primeira página" + }, "agentOrgExecution": { "sources": { "user_input": "Pedido do usuário", diff --git a/src/i18n/locales/ru/sessions.json b/src/i18n/locales/ru/sessions.json index 459fed5bf1..4e4ac447bd 100644 --- a/src/i18n/locales/ru/sessions.json +++ b/src/i18n/locales/ru/sessions.json @@ -1,4 +1,14 @@ { + "agentOrgHistory": { + "readOnly": "Разговор из прежней версии, только просмотр", + "savedContent": "Сохранённые сообщения и результаты группы", + "unknownMember": "Неизвестный участник", + "loading": "Загрузка истории…", + "retry": "Повторить", + "empty": "Нет сохранённого содержимого группы", + "nextPage": "Следующая страница", + "firstPage": "Первая страница" + }, "agentOrgExecution": { "sources": { "user_input": "Запрос пользователя", diff --git a/src/i18n/locales/tr/sessions.json b/src/i18n/locales/tr/sessions.json index d2bd003234..a6e103f5d5 100644 --- a/src/i18n/locales/tr/sessions.json +++ b/src/i18n/locales/tr/sessions.json @@ -1,4 +1,14 @@ { + "agentOrgHistory": { + "readOnly": "Eski sürüm konuşması, yalnızca görüntüleme", + "savedContent": "Kaydedilmiş grup mesajları ve çıktılar", + "unknownMember": "Bilinmeyen üye", + "loading": "Geçmiş yükleniyor…", + "retry": "Yeniden dene", + "empty": "Kaydedilmiş grup içeriği yok", + "nextPage": "Sonraki sayfa", + "firstPage": "İlk sayfa" + }, "agentOrgExecution": { "sources": { "user_input": "Kullanıcı isteği", diff --git a/src/i18n/locales/vi/sessions.json b/src/i18n/locales/vi/sessions.json index fb60154a71..01a21b1495 100644 --- a/src/i18n/locales/vi/sessions.json +++ b/src/i18n/locales/vi/sessions.json @@ -1,4 +1,14 @@ { + "agentOrgHistory": { + "readOnly": "Cuộc trò chuyện phiên bản cũ, chỉ xem", + "savedContent": "Tin nhắn nhóm và kết quả đã lưu", + "unknownMember": "Thành viên không xác định", + "loading": "Đang tải lịch sử…", + "retry": "Thử lại", + "empty": "Không có nội dung nhóm đã lưu", + "nextPage": "Trang tiếp theo", + "firstPage": "Trang đầu" + }, "agentOrgExecution": { "sources": { "user_input": "Yêu cầu của người dùng", diff --git a/src/i18n/locales/zh-Hant/sessions.json b/src/i18n/locales/zh-Hant/sessions.json index 895066d349..24a48eb4b5 100644 --- a/src/i18n/locales/zh-Hant/sessions.json +++ b/src/i18n/locales/zh-Hant/sessions.json @@ -1,4 +1,14 @@ { + "agentOrgHistory": { + "readOnly": "舊版本對話,僅供查看", + "savedContent": "已儲存的群聊和輸出", + "unknownMember": "未知成員", + "loading": "正在載入歷史…", + "retry": "重試", + "empty": "暫無已儲存的群聊內容", + "nextPage": "下一頁", + "firstPage": "第一頁" + }, "agentOrgExecution": { "sources": { "user_input": "使用者請求", diff --git a/src/i18n/locales/zh/sessions.json b/src/i18n/locales/zh/sessions.json index 4d61701528..97389860e9 100644 --- a/src/i18n/locales/zh/sessions.json +++ b/src/i18n/locales/zh/sessions.json @@ -1,4 +1,14 @@ { + "agentOrgHistory": { + "readOnly": "旧版本会话,仅供查看", + "savedContent": "已保存的群聊和输出", + "unknownMember": "未知成员", + "loading": "正在加载历史…", + "retry": "重试", + "empty": "暂无已保存的群聊内容", + "nextPage": "下一页", + "firstPage": "第一页" + }, "agentOrgExecution": { "sources": { "user_input": "用户请求", diff --git a/src/store/session/sessionAtom/mutations.ts b/src/store/session/sessionAtom/mutations.ts index f81862eb96..686e31a556 100644 --- a/src/store/session/sessionAtom/mutations.ts +++ b/src/store/session/sessionAtom/mutations.ts @@ -86,6 +86,7 @@ export const upsertSession = (session: Session) => { parentSessionId: session.parentSessionId ?? existing.parentSessionId, orgMemberId: session.orgMemberId ?? existing.orgMemberId, agentOrgId: session.agentOrgId ?? existing.agentOrgId, + agentOrgMode: session.agentOrgMode ?? existing.agentOrgMode, agentOrgName: session.agentOrgName ?? existing.agentOrgName, agentDefinitionId: session.agentDefinitionId ?? existing.agentDefinitionId, diff --git a/src/store/session/sessionAtom/sidebarRoster.ts b/src/store/session/sessionAtom/sidebarRoster.ts index 05d6021c63..4f31060352 100644 --- a/src/store/session/sessionAtom/sidebarRoster.ts +++ b/src/store/session/sessionAtom/sidebarRoster.ts @@ -26,7 +26,8 @@ export function sidebarCategoryForSession( ); if (importedSource) return importedSource.listCategory; if (session.pinned) return "pinned_native"; - if (session.agentOrgId) return "agent_org_root"; + if (session.agentOrgId || session.agentOrgMode === "history_only") + return "agent_org_root"; if (session.category === "cli_agent") return "cli_agent"; if (session.category === "human_session") return "human_session"; if (getRustAgentType(session.session_id) === RUST_AGENT_TYPE.OS) { diff --git a/src/store/session/sessionAtom/types.ts b/src/store/session/sessionAtom/types.ts index 0a1f0fa70a..5dff90299d 100644 --- a/src/store/session/sessionAtom/types.ts +++ b/src/store/session/sessionAtom/types.ts @@ -214,6 +214,7 @@ export interface Session { orgMemberId?: string; /** Agent Team definition id for root/coordinator rows launched from a team. */ agentOrgId?: string; + agentOrgMode?: "current" | "history_only"; /** Agent Team display name for root/coordinator rows launched from a team. */ agentOrgName?: string; /** Rust-native agent definition ID returned by the backend. */ diff --git a/src/util/session/sessionVisibility.ts b/src/util/session/sessionVisibility.ts index cdcb5bd8f4..e740e28f38 100644 --- a/src/util/session/sessionVisibility.ts +++ b/src/util/session/sessionVisibility.ts @@ -6,6 +6,7 @@ interface SessionVisibilityInput { parentSessionId?: string; parent_session_id?: string | null; agentOrgId?: string; + agentOrgMode?: "current" | "history_only"; /** * Imported-history rows are read-only. The helper does not consult this * field — a child session stays hidden regardless — but the interface @@ -35,5 +36,9 @@ export function isPrimarySessionListSession( hasParentSessionId || session.session_id.includes(SUBAGENT_SESSION_ID_SEGMENT); if (isChildSession) return false; - return !session.orgMemberId || Boolean(session.agentOrgId); + return ( + !session.orgMemberId || + Boolean(session.agentOrgId) || + session.agentOrgMode === "history_only" + ); } diff --git a/tests/e2e/specs/core/agent-org-pause-resume-live.spec.mjs b/tests/e2e/specs/core/agent-org-pause-resume-live.spec.mjs index f88f5a48df..713a8bad6d 100644 --- a/tests/e2e/specs/core/agent-org-pause-resume-live.spec.mjs +++ b/tests/e2e/specs/core/agent-org-pause-resume-live.spec.mjs @@ -149,7 +149,7 @@ function durableRunIdForRootSession(sessionId) { "sqlite3", [ join(ORGII_HOME, "sessions.db"), - `SELECT id FROM agent_org_runtime_runs WHERE root_session_id='${sessionId.replaceAll("'", "''")}' ORDER BY created_at DESC LIMIT 1;`, + `SELECT id FROM agent_org_execution_runs WHERE root_session_id='${sessionId.replaceAll("'", "''")}' ORDER BY created_at DESC LIMIT 1;`, ], { encoding: "utf8" } ).trim(); @@ -185,8 +185,8 @@ function convergenceSnapshot({ const finalityMarker = sqlLiteral(`%${FINALITY_MARKER}%`); return sqliteRow(` SELECT - (SELECT status FROM agent_org_runtime_runs WHERE id=${run}) AS run_status, - (SELECT status FROM agent_org_runtime_tasks + (SELECT status FROM agent_org_execution_runs WHERE id=${run}) AS run_status, + (SELECT status FROM agent_org_execution_tasks WHERE org_run_id=${run} AND id=${task}) AS task_status, (SELECT status FROM session_turn_intents WHERE session_id=${session} AND turn_intent_id=${continuation}) AS continuation_status, @@ -194,20 +194,20 @@ function convergenceSnapshot({ WHERE org_run_id=${run} AND status IN ('queued','running')) AS active_intent_count, (SELECT COUNT(*) FROM session_turn_intents WHERE org_run_id=${run}) AS intent_count, - (SELECT COUNT(*) FROM agent_org_runtime_turn_contexts + (SELECT COUNT(*) FROM agent_org_execution_turn_contexts WHERE org_run_id=${run}) AS context_count, - (SELECT COUNT(*) FROM agent_org_runtime_inbox inbox + (SELECT COUNT(*) FROM agent_org_execution_inbox inbox WHERE inbox.org_run_id=${run} AND inbox.payload_kind='task_assigned' AND json_extract(inbox.payload_json,'$.task_id')=${task} AND inbox.read_at IS NULL AND NOT EXISTS ( - SELECT 1 FROM agent_org_runtime_inbox_delivery_resolutions resolution + SELECT 1 FROM agent_org_execution_inbox_delivery_resolutions resolution WHERE resolution.inbox_id=inbox.id )) AS unresolved_assignment_count, (SELECT COUNT(*) - FROM agent_org_runtime_inbox_materializations materialization - JOIN agent_org_runtime_inbox inbox ON inbox.id=materialization.inbox_id + FROM agent_org_execution_inbox_materializations materialization + JOIN agent_org_execution_inbox inbox ON inbox.id=materialization.inbox_id WHERE inbox.org_run_id=${run} AND inbox.payload_kind='task_assigned' AND json_extract(inbox.payload_json,'$.task_id')=${task}) AS assignment_materialization_count, @@ -261,28 +261,28 @@ function archiveConvergenceSnapshot(runId) { const run = sqlLiteral(runId); return sqliteRow(` SELECT - (SELECT status FROM agent_org_runtime_runs WHERE id=${run}) AS run_status, - (SELECT teardown_status FROM agent_org_runtime_archive_episodes + (SELECT status FROM agent_org_execution_runs WHERE id=${run}) AS run_status, + (SELECT teardown_status FROM agent_org_execution_archive_episodes WHERE org_run_id=${run}) AS teardown_status, - (SELECT teardown_attempt_count FROM agent_org_runtime_archive_episodes + (SELECT teardown_attempt_count FROM agent_org_execution_archive_episodes WHERE org_run_id=${run}) AS teardown_attempt_count, - (SELECT retained_runtime_count FROM agent_org_runtime_archive_episodes + (SELECT retained_runtime_count FROM agent_org_execution_archive_episodes WHERE org_run_id=${run}) AS retained_runtime_count, - (SELECT COUNT(*) FROM agent_org_runtime_tasks + (SELECT COUNT(*) FROM agent_org_execution_tasks WHERE org_run_id=${run}) AS task_count, - (SELECT COUNT(*) FROM agent_org_runtime_tasks + (SELECT COUNT(*) FROM agent_org_execution_tasks WHERE org_run_id=${run} AND status NOT IN ('completed','failed','cancelled')) AS open_task_count, (SELECT COUNT(*) FROM session_turn_intents WHERE org_run_id=${run} AND status IN ('queued','running')) AS active_intent_count, - (SELECT COUNT(*) FROM agent_org_runtime_turn_contexts + (SELECT COUNT(*) FROM agent_org_execution_turn_contexts WHERE org_run_id=${run}) AS context_count, - (SELECT COUNT(*) FROM agent_org_runtime_inbox + (SELECT COUNT(*) FROM agent_org_execution_inbox WHERE org_run_id=${run}) AS inbox_count, (SELECT COUNT(*) FROM agent_messages message - JOIN agent_org_runtime_member_materializations member + JOIN agent_org_execution_member_materializations member ON member.session_id=message.session_id WHERE member.org_run_id=${run}) AS member_message_count, - (SELECT MAX(updated_at) FROM agent_org_runtime_tasks + (SELECT MAX(updated_at) FROM agent_org_execution_tasks WHERE org_run_id=${run}) AS latest_task_updated_at `); } diff --git a/tests/e2e/support/core/agentOrgCompletionDriver.mjs b/tests/e2e/support/core/agentOrgCompletionDriver.mjs index dfe547ead7..04f4be1cff 100644 --- a/tests/e2e/support/core/agentOrgCompletionDriver.mjs +++ b/tests/e2e/support/core/agentOrgCompletionDriver.mjs @@ -78,7 +78,7 @@ export async function runCompletionWaitScenario({ await browser.waitUntil( async () => { const raw = rows( - `SELECT completion_candidate_json FROM agent_org_runtime_run_progress WHERE org_run_id=${literal(runId)}` + `SELECT completion_candidate_json FROM agent_org_execution_run_progress WHERE org_run_id=${literal(runId)}` )[0]?.completion_candidate_json; candidate = raw ? JSON.parse(raw) : null; return Boolean( @@ -100,10 +100,10 @@ export async function runCompletionWaitScenario({ await browser.waitUntil( async () => { const tasks = rows( - `SELECT status,activation_generation FROM agent_org_runtime_tasks WHERE org_run_id=${literal(runId)}` + `SELECT status,activation_generation FROM agent_org_execution_tasks WHERE org_run_id=${literal(runId)}` ); const turns = rows( - `SELECT intent.status FROM agent_org_runtime_turn_contexts context JOIN session_turn_intents intent USING(session_id,turn_intent_id) WHERE context.org_run_id=${literal(runId)} AND context.turn_kind='task_execution'` + `SELECT intent.status FROM agent_org_execution_turn_contexts context JOIN session_turn_intents intent USING(session_id,turn_intent_id) WHERE context.org_run_id=${literal(runId)} AND context.turn_kind='task_execution'` ); return ( tasks.length === 1 && @@ -122,13 +122,13 @@ export async function runCompletionWaitScenario({ await waitForCandidate(); } let during = rows( - `SELECT context.turn_intent_id,intent.status FROM agent_org_runtime_turn_contexts context JOIN session_turn_intents intent USING(session_id,turn_intent_id) WHERE context.org_run_id=${literal(runId)} AND context.turn_kind='task_execution'` + `SELECT context.turn_intent_id,intent.status FROM agent_org_execution_turn_contexts context JOIN session_turn_intents intent USING(session_id,turn_intent_id) WHERE context.org_run_id=${literal(runId)} AND context.turn_kind='task_execution'` ); if (!during.some((turn) => turn.status === "running")) throw new Error("Member-end race window was not actually exercised"); if ( rows( - `SELECT id FROM agent_org_runtime_run_completion_certificates WHERE org_run_id=${literal(runId)}` + `SELECT id FROM agent_org_execution_run_completion_certificates WHERE org_run_id=${literal(runId)}` ).length ) throw new Error("Candidate certified before member end"); @@ -193,7 +193,7 @@ export async function runCompletionWaitScenario({ ); pauseResumeEvidence = { beforePause, paused, resumed }; during = rows( - `SELECT context.turn_intent_id,intent.status FROM agent_org_runtime_turn_contexts context JOIN session_turn_intents intent USING(session_id,turn_intent_id) WHERE context.org_run_id=${literal(runId)} AND context.turn_kind='task_execution'` + `SELECT context.turn_intent_id,intent.status FROM agent_org_execution_turn_contexts context JOIN session_turn_intents intent USING(session_id,turn_intent_id) WHERE context.org_run_id=${literal(runId)} AND context.turn_kind='task_execution'` ); } if (!pauseResumeBeforeMemberExit) @@ -213,7 +213,7 @@ export async function runCompletionWaitScenario({ "event-driven completion and persisted report" ); const dispositions = rows( - `SELECT inbox.id,inbox.payload_kind,inbox.read_at,resolution.resolution_kind,resolution.reason FROM agent_org_runtime_inbox inbox LEFT JOIN agent_org_runtime_inbox_delivery_resolutions resolution ON resolution.inbox_id=inbox.id WHERE inbox.org_run_id=${literal(runId)}` + `SELECT inbox.id,inbox.payload_kind,inbox.read_at,resolution.resolution_kind,resolution.reason FROM agent_org_execution_inbox inbox LEFT JOIN agent_org_execution_inbox_delivery_resolutions resolution ON resolution.inbox_id=inbox.id WHERE inbox.org_run_id=${literal(runId)}` ); const idle = dispositions.filter((row) => row.payload_kind === "member_idle"); const idleHandled = pauseResumeBeforeMemberExit @@ -229,20 +229,20 @@ export async function runCompletionWaitScenario({ `Idle notifications were left unresolved or handled by the wrong path: ${JSON.stringify(idle)}` ); const certificateOwner = rows( - `SELECT coordinator_session_id AS session_id,coordinator_turn_intent_id AS turn_intent_id FROM agent_org_runtime_run_completion_certificates WHERE org_run_id=${literal(runId)} ORDER BY created_at DESC,id DESC LIMIT 1` + `SELECT coordinator_session_id AS session_id,coordinator_turn_intent_id AS turn_intent_id FROM agent_org_execution_run_completion_certificates WHERE org_run_id=${literal(runId)} ORDER BY created_at DESC,id DESC LIMIT 1` )[0]; candidate ??= certificateOwner; if (!candidate?.session_id || !candidate?.turn_intent_id) throw new Error("Persisted completion has no exact coordinator owner"); const later = rows( - `SELECT context.*,intent.status FROM agent_org_runtime_turn_contexts context JOIN session_turn_intents intent USING(session_id,turn_intent_id) WHERE context.org_run_id=${literal(runId)} AND context.turn_kind='coordinator' AND NOT EXISTS(SELECT 1 FROM agent_org_runtime_final_summary_receipts summary WHERE summary.coordinator_session_id=context.session_id AND summary.turn_intent_id=context.turn_intent_id) AND context.context_id>(SELECT context_id FROM agent_org_runtime_turn_contexts WHERE session_id=${literal(candidate.session_id)} AND turn_intent_id=${literal(candidate.turn_intent_id)})` + `SELECT context.*,intent.status FROM agent_org_execution_turn_contexts context JOIN session_turn_intents intent USING(session_id,turn_intent_id) WHERE context.org_run_id=${literal(runId)} AND context.turn_kind='coordinator' AND NOT EXISTS(SELECT 1 FROM agent_org_execution_final_summary_receipts summary WHERE summary.coordinator_session_id=context.session_id AND summary.turn_intent_id=context.turn_intent_id) AND context.context_id>(SELECT context_id FROM agent_org_execution_turn_contexts WHERE session_id=${literal(candidate.session_id)} AND turn_intent_id=${literal(candidate.turn_intent_id)})` ); if (later.some((turn) => !["cancelled", "coalesced"].includes(turn.status))) throw new Error( `Unexpected coordinator turns after saved authorization: ${JSON.stringify(later)}` ); const summaries = rows( - `SELECT status,attempt,event_id FROM agent_org_runtime_final_summary_receipts WHERE org_run_id=${literal(runId)}` + `SELECT status,attempt,event_id FROM agent_org_execution_final_summary_receipts WHERE org_run_id=${literal(runId)}` ); if (summaries.length !== 1 || summaries[0].status !== "persisted") throw new Error( @@ -326,7 +326,7 @@ export async function runReworkScenario() { ); const runId = finalView.context.runId; const tasks = rows( - `SELECT * FROM agent_org_runtime_tasks WHERE org_run_id=${literal(runId)}` + `SELECT * FROM agent_org_execution_tasks WHERE org_run_id=${literal(runId)}` ); const task = (suffix) => tasks.find((row) => row.subject === `E2E_AGENT_ORG_REWORK:${suffix}`); @@ -360,14 +360,14 @@ export async function runReworkScenario() { "Old defect evidence was rewritten or replacement verification is missing" ); const deliveries = rows( - `SELECT * FROM agent_org_runtime_inbox WHERE org_run_id=${literal(runId)} AND payload_kind='task_assigned'` + `SELECT * FROM agent_org_execution_inbox WHERE org_run_id=${literal(runId)} AND payload_kind='task_assigned'` ).filter((row) => JSON.parse(row.payload_json).task_id === delivery.id); if (deliveries.length !== 1 || deliveries[0].created_at < retest.updated_at) throw new Error( `Final consumer woke before replacement verification: ${JSON.stringify(deliveries)}` ); const reports = rows( - `SELECT * FROM agent_org_runtime_final_summary_receipts WHERE org_run_id=${literal(runId)}` + `SELECT * FROM agent_org_execution_final_summary_receipts WHERE org_run_id=${literal(runId)}` ); if (reports.length !== 1 || reports[0].status !== "persisted") throw new Error( diff --git a/tests/e2e/support/core/agentOrgSummaryDriver.mjs b/tests/e2e/support/core/agentOrgSummaryDriver.mjs index 5549dd5da0..095c8b7bf3 100644 --- a/tests/e2e/support/core/agentOrgSummaryDriver.mjs +++ b/tests/e2e/support/core/agentOrgSummaryDriver.mjs @@ -127,7 +127,7 @@ export async function runSummaryStopScenario(window, { postJson }) { const runId = started.context.runId; const first = started.finalSummary; const certificates = rows( - `SELECT id FROM agent_org_runtime_run_completion_certificates WHERE org_run_id=${literal(runId)} AND id=${literal(first.certificateId)}` + `SELECT id FROM agent_org_execution_run_completion_certificates WHERE org_run_id=${literal(runId)} AND id=${literal(first.certificateId)}` ); if (certificates.length !== 1) throw new Error("Running report has no durable work certificate"); @@ -157,10 +157,10 @@ export async function runSummaryStopScenario(window, { postJson }) { action: "disarm", }); const tasksBefore = rows( - `SELECT id,status,output_json FROM agent_org_runtime_tasks WHERE org_run_id=${literal(runId)} ORDER BY id` + `SELECT id,status,output_json FROM agent_org_execution_tasks WHERE org_run_id=${literal(runId)} ORDER BY id` ); const executionsBefore = rows( - `SELECT session_id,turn_intent_id FROM agent_org_runtime_turn_contexts WHERE org_run_id=${literal(runId)} AND turn_kind='task_execution' ORDER BY context_id` + `SELECT session_id,turn_intent_id FROM agent_org_execution_turn_contexts WHERE org_run_id=${literal(runId)} AND turn_kind='task_execution' ORDER BY context_id` ); if (window === "before") await probeObsoleteAssignmentWake(runId, { postJson }); @@ -310,7 +310,7 @@ export async function runSummaryStopScenario(window, { postJson }) { 90000 ); const attempts = rows( - `SELECT status,attempt,event_id,typed_error,certificate_id FROM agent_org_runtime_final_summary_receipts WHERE org_run_id=${literal(runId)} ORDER BY attempt` + `SELECT status,attempt,event_id,typed_error,certificate_id FROM agent_org_execution_final_summary_receipts WHERE org_run_id=${literal(runId)} ORDER BY attempt` ); if ( attempts.length !== 2 || @@ -321,10 +321,10 @@ export async function runSummaryStopScenario(window, { postJson }) { `Unexpected report retry attempts: ${JSON.stringify(attempts)}` ); const tasksAfter = rows( - `SELECT id,status,output_json FROM agent_org_runtime_tasks WHERE org_run_id=${literal(runId)} ORDER BY id` + `SELECT id,status,output_json FROM agent_org_execution_tasks WHERE org_run_id=${literal(runId)} ORDER BY id` ); const executionsAfter = rows( - `SELECT session_id,turn_intent_id FROM agent_org_runtime_turn_contexts WHERE org_run_id=${literal(runId)} AND turn_kind='task_execution' ORDER BY context_id` + `SELECT session_id,turn_intent_id FROM agent_org_execution_turn_contexts WHERE org_run_id=${literal(runId)} AND turn_kind='task_execution' ORDER BY context_id` ); if ( JSON.stringify(tasksBefore) !== JSON.stringify(tasksAfter) || @@ -332,7 +332,7 @@ export async function runSummaryStopScenario(window, { postJson }) { ) throw new Error("Retry changed certified work or reran a member"); const events = rows( - `SELECT event.id,event.result_json FROM events event JOIN agent_org_runtime_final_summary_receipts receipt ON receipt.event_id=event.id AND receipt.coordinator_session_id=event.session_id WHERE receipt.org_run_id=${literal(runId)}` + `SELECT event.id,event.result_json FROM events event JOIN agent_org_execution_final_summary_receipts receipt ON receipt.event_id=event.id AND receipt.coordinator_session_id=event.session_id WHERE receipt.org_run_id=${literal(runId)}` ); if ( events.length !== 1 || diff --git a/tests/e2e/support/core/agentOrgTerminalDriver.mjs b/tests/e2e/support/core/agentOrgTerminalDriver.mjs index a2784f2865..7d72909cf0 100644 --- a/tests/e2e/support/core/agentOrgTerminalDriver.mjs +++ b/tests/e2e/support/core/agentOrgTerminalDriver.mjs @@ -82,7 +82,7 @@ export async function runFormalTerminalScenario(kind) { async () => { execution = rows(`SELECT context.session_id,context.turn_intent_id,intent.status - FROM agent_org_runtime_turn_contexts context JOIN session_turn_intents intent + FROM agent_org_execution_turn_contexts context JOIN session_turn_intents intent ON intent.session_id=context.session_id AND intent.turn_intent_id=context.turn_intent_id WHERE context.org_run_id=${literal(runId)} AND context.task_id=${literal(task.id)} AND context.turn_kind='task_execution' ORDER BY context.created_at LIMIT 1`)[0]; @@ -173,7 +173,7 @@ export async function runFormalTerminalScenario(kind) { } ); const recovery = - rows(`SELECT attempts FROM agent_org_runtime_recovery_attempts + rows(`SELECT attempts FROM agent_org_execution_recovery_attempts WHERE org_run_id=${literal(runId)} AND action_kind='task_failure_recovery' AND target_key=${literal(task.id)}`); if (!failed && recovery.length) throw new Error( @@ -181,7 +181,7 @@ export async function runFormalTerminalScenario(kind) { ); if (failed) { const boundTask = rows( - `SELECT status,owner FROM agent_org_runtime_tasks WHERE org_run_id=${literal(runId)} AND id=${literal(task.id)}` + `SELECT status,owner FROM agent_org_execution_tasks WHERE org_run_id=${literal(runId)} AND id=${literal(task.id)}` )[0]; if (boundTask?.status !== "pending" || boundTask?.owner !== null) throw new Error( diff --git a/tests/e2e/support/core/agentOrgWakeDriver.mjs b/tests/e2e/support/core/agentOrgWakeDriver.mjs index 7cae447b1d..34da987253 100644 --- a/tests/e2e/support/core/agentOrgWakeDriver.mjs +++ b/tests/e2e/support/core/agentOrgWakeDriver.mjs @@ -59,7 +59,7 @@ function save(name, evidence) { export async function probeObsoleteAssignmentWake(runId, { postJson }) { const task = rows(`SELECT task.id,task.owner,session.session_id,session.agent_definition_id - FROM agent_org_runtime_tasks task JOIN agent_org_runtime_member_materializations member + FROM agent_org_execution_tasks task JOIN agent_org_execution_member_materializations member ON member.org_run_id=task.org_run_id AND member.member_id=task.owner AND member.status='succeeded' JOIN agent_sessions session ON session.session_id=member.session_id WHERE task.org_run_id=${literal(runId)} AND task.status='completed' LIMIT 1`)[0]; @@ -74,7 +74,7 @@ export async function probeObsoleteAssignmentWake(runId, { postJson }) { const before = intents(); const budget = () => rows( - `SELECT * FROM agent_org_runtime_recovery_attempts WHERE org_run_id=${literal(runId)} AND target_key=${literal(task.owner)}` + `SELECT * FROM agent_org_execution_recovery_attempts WHERE org_run_id=${literal(runId)} AND target_key=${literal(task.owner)}` ); const budgetBefore = budget(); const inboxIds = []; @@ -122,8 +122,8 @@ export async function probeObsoleteAssignmentWake(runId, { postJson }) { throw new Error("Empty wake spent a recovery reservation"); const inbox = rows( `SELECT inbox.id,inbox.read_at,resolution.resolution_kind,resolution.reason, - (SELECT COUNT(*) FROM agent_org_runtime_inbox observer WHERE observer.causation_inbox_id=inbox.id) AS observers - FROM agent_org_runtime_inbox inbox LEFT JOIN agent_org_runtime_inbox_delivery_resolutions resolution + (SELECT COUNT(*) FROM agent_org_execution_inbox observer WHERE observer.causation_inbox_id=inbox.id) AS observers + FROM agent_org_execution_inbox inbox LEFT JOIN agent_org_execution_inbox_delivery_resolutions resolution ON resolution.inbox_id=inbox.id WHERE inbox.id IN (${inboxIds.join(",")})` ); if (inbox.length !== 2 || inbox.some((row) => row.read_at !== null)) @@ -154,7 +154,7 @@ export async function probeObsoleteAssignmentWake(runId, { postJson }) { export async function sendNewWorkAfterObsoleteWake(root, runId) { const before = rows( - `SELECT task_id,turn_intent_id FROM agent_org_runtime_turn_contexts WHERE org_run_id=${literal(runId)} AND turn_kind='task_execution' ORDER BY context_id` + `SELECT task_id,turn_intent_id FROM agent_org_execution_turn_contexts WHERE org_run_id=${literal(runId)} AND turn_kind='task_execution' ORDER BY context_id` ); const marker = `member_end_wait_new_input_${RUN_ID}`; await openRenderedGroupChatView(); @@ -162,7 +162,7 @@ export async function sendNewWorkAfterObsoleteWake(root, runId) { const view = await waitForAgentOrgRunView( root, (view) => - rows(`SELECT id FROM agent_org_runtime_tasks WHERE org_run_id=${literal(runId)} + rows(`SELECT id FROM agent_org_execution_tasks WHERE org_run_id=${literal(runId)} AND status='completed' AND instr(subject,${literal(marker)})>0`) .length === 1 && view?.finalSummary?.status === "persisted" && @@ -171,7 +171,7 @@ export async function sendNewWorkAfterObsoleteWake(root, runId) { 90000 ); const after = rows( - `SELECT task_id,turn_intent_id FROM agent_org_runtime_turn_contexts WHERE org_run_id=${literal(runId)} AND turn_kind='task_execution' ORDER BY context_id` + `SELECT task_id,turn_intent_id FROM agent_org_execution_turn_contexts WHERE org_run_id=${literal(runId)} AND turn_kind='task_execution' ORDER BY context_id` ); if ( after.length !== before.length + 1 ||