fix(agent-org): isolate runtime persistence namespace - #799
Closed
ShiboSheng wants to merge 11 commits into
Closed
Conversation
Move the redesigned Agent Org runtime into the canonical agent_org_runtime_* tables and retire the exact legacy table set atomically on startup. Isolate flat Team definitions at agent-org-definitions.json while preserving ordinary Rust and CLI session data across downgrade and re-upgrade. Pre-commit hook ran. Total eslint: 0, total circular: 0
ShiboSheng
marked this pull request as ready for review
August 14, 2026 03:29
Collaborator
Author
|
orgii://cloud/session/ref?v=1&org=bfa7b134-2486-45fa-81ad-a369441fafb4&owner=776dbd69-ac1d-4f72-a0d4-69cb4f2667dd&session=codexapp-rollout-2026-08-14T00-42-45-019ffc01-371f-7523-8301-13d20a728a28 |
A failed Agent Org runtime namespace previously ?-propagated out of the sessions.db init dispatcher, so one dropped canonical table made every sessions.db connection fail forever and took ordinary chat down. - new coordination::availability: process-global unavailable state (thread-local under cfg(test)), structured "agent-org runtime unavailable: <reason>" error, and a gated runtime_connection() used by every Agent Org store entry. - coordination::init_agent_org_schemas_scoped logs the full diagnostic at error level, records the reason, and never fails DB init; the setup hook now calls it instead of ?-propagating. - all coordination stores (runs/tasks/inbox/plan approvals/ interventions/watchdog) acquire connections through the gate. - test: corrupted namespace leaves the connection usable for ordinary DDL, records the reason, gates store entries, and recovers after a healthy re-init.
Legacy retirement dropped up to 13 tables without recording what was in them. Count rows per existing table first and log agent_org_destructive_table_drop(context, table, rows) at warn level. The counting only runs when legacy tables actually exist, so canonical steady-state boots pay nothing. The same helper backs the upcoming epoch retire-and-recreate path.
The manifest verifier could only fail closed on any DDL drift, leaving future schema changes no sanctioned path and (pre-scoping) bricking sessions.db. Add agent_org_runtime_meta(key, value) inside the canonical namespace carrying schema_epoch = SCHEMA_EPOCH (a const, currently 1), included in the manifest. Decision on a non-empty namespace, epoch first: - epoch < binary (incl. pre-epoch namespaces without the meta table): deliberate retire-and-recreate — drop the runtime tables + meta with per-table row-count logging, recreate fresh. Destructive by design; bumping the const is the sanctioned path for future DDL changes. - epoch > binary: fail closed with a created-by-a-newer-version diagnostic (scoped by availability, so chat keeps working after a rollback). - epoch == binary or unreadable: manifest mismatch is corruption, fail closed (scoped). Tests: epoch upgrade (explicit older epoch + pre-epoch), downgrade fail-closed with data intact, unreadable-epoch corruption; existing manifest tests updated for the 14-table registry.
The watchdog test module resolves the connection helper through 'use super::*'; update it for the runtime_connection rename from the scoped-degradation commit.
retire_legacy_definitions_file deleted the pre-rename agent-orgs.json unparsed even though old and new files share the same schema_version=2 envelope — destroying user-defined Teams on the rename cutover. Now: if the canonical agent-org-definitions.json does not exist and the old file parses as a valid v2 envelope, rename (or copy+delete) it into place, preserving user Teams. An invalid or legacy-shaped old file is retired as before; an old file next to an existing canonical file is retired without touching the canonical bytes. I/O failure during adoption leaves the old file in place for a later retry rather than destroying it. Tests: valid-v2 adoption preserves custom Teams across restart; invalid old file still retired; both-exist keeps the canonical file and deletes the old one.
normalize_legacy_dependency_rows scanned every agent_org_runtime_tasks row on every boot to discover unmigrated runs, and re-warned about permanently-unsafe runs forever. - discovery now anti-joins agent_org_runtime_runs (one row per run) against the per-run markers; a canonical no-op boot costs exactly one SELECT regardless of task volume. - a run whose historical rows cannot be normalized safely is marked canonical_blocked_by_v1_skipped once, with a single warn; later boots neither rescan nor re-warn. Repair goes through the runtime repair surfaces, which normalize on write. Tests updated for run-driven discovery; new test proves marked runs are never rescanned and the terminal skip holds after row repair.
measures_constant_scale_startup_paths printed timing medians and asserted nothing. Replace it with a real guard for the per-boot O(data) fixes: seed 20 runs / 2000 unread inbox rows / 2000 materialization receipts / 2000 tasks in a canonical DB and count every SQL statement during a no-op boot via rusqlite's trace hook (workspace rusqlite gains the 'trace' feature). The count must equal the empty-DB no-op count — exact statement-count equality is robust where time thresholds are not. Directly guards the repair gating and run-driven normalization discovery.
Dependency-normalization discovery is now driven from agent_org_runtime_runs, so the two assignment-snapshot tests that initialized only the task schema need the runs table first — matching the dependency order the namespace coordinator guarantees in production.
- drop the three ghost DROP INDEX statements in the inbox DDL (…run_task_assignment_v2/_v3 and …causation_once): those names never existed in the runtime namespace, and the schema manifest owns versioning now. sqlite_master is unchanged, so the expected manifest regenerates identically. - include 'view' in the coordinator's three sqlite_master type filters (manifest query, legacy-object count, unknown-object report) so a view in the namespace can no longer hide from verification. - fix stale docs naming retired tables: agent_inbox/schema.rs module and init docs, agent_org_tasks module and init docs, core_types::tool_names ORG_SEND_MESSAGE, e2e-test member-idle probe. - doc-comment every module-level pub fn init_schema as tests-only — production initialization goes through the namespace coordinator.
orgs.rs resolved to keep both fix sets: PR 786's per-definition quarantine machinery (struct LoadOutcome::Loaded, quarantine loop in load_from_disk, save round-trip, guard fallback) plus PR 799's namespace cutover and legacy-file adoption (strict parse_definitions_content retained as the all-or-nothing adoption gate); the legacy hierarchy sniff (contains_legacy_hierarchy, backup_legacy_file, LoadOutcome::LegacyReset) is fully removed. 786-side hunks in watchdog/runs modules re-pointed at the renamed agent_org_runtime_* tables and runtime_connection().
Collaborator
Author
|
The replacement was rebuilt cleanly as the third layer in #824 → #825 → #828. It keeps the original namespace cutover and Neonforge's d3035ef namespace hygiene sweep, excludes the commits rejected in the review notes, and leaves c4190d9 out because its runtime_connection API exists only in the excluded 497ddc1 change. The old branch is intentionally retained. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
Fixes #791.
The redesigned Agent Org runtime and published pre-redesign builds shared the same 13 private SQLite table names even though their schemas and lifecycle semantics are incompatible. A downgrade and re-upgrade could therefore make either generation query columns owned by the other generation (
completed_atversusactivation_generation), causing startup/sidebar retries and preventing ordinary Rust and CLI Sessions from being used safely.The same collision existed at
agent-orgs.json: old recursive definitions and the redesigned versioned flat envelope both treated that path as authoritative. The approved clean-cutover plan supersedes the earlier compatibility-table proposal because isolating only the run envelope would still leave Task, Inbox, approval, intervention, and recovery tables shared across generations.Solution
agent_org_runtime_*namespace.ALTER TABLEpaths. Unit-test, sandbox, production, and HTTP fixture entry points use the same complete coordinator where full application initialization is required.agent-org-definitions.json. The redesigned store deletes the exact old live file without parsing or migrating it, never falls back to it, and keeps unknown canonical files fail-closed and byte-preserving.Potential risks
agent-orgs.jsonfile are permanently discarded without backup. Ordinary Rust/CLI Sessions and shared product data are outside the cleanup registry.Starting,Working,Paused, or crash-recovery downgrade/re-upgrade is unsupported.ORGII_HOMEremain unsupported. Same-version initializers are serialized by SQLite and covered by a concurrency test.fix/issue-757-flat-team-capabilities), which is itself stacked on PR feat(agent-org): add authoritative team lifecycle #781. It must be reviewed and merged in stack order, then retargeted/reverified as earlier layers land.Verification
Automated checks:
cargo test -p agent_core core::coordination::schema::tests -- --nocapture --test-threads=1— 7 passed, covering historical 5/9/11/13-table retirement, shared-data sentinels, repeated downgrade cleanup, manifest fail-closed behavior, rollback, unknown-object preservation, concurrent initialization, and startup measurements.cargo test -p agent_core core::definitions::orgs::tests -- --nocapture --test-threads=1— 13 passed, including old/new path isolation, byte-preserving restart, cleanup failure isolation, unknown canonical file fail-closed behavior, stable IDs/grants/links, and the 50-member capability fixture.cargo test -p agent_core agent_org -- --nocapture --test-threads=1— 224 passed. One earlier parallel aggregate attempt exposed process-globalORGII_HOME/SQLite fixture interference; this required serial rerun passed cleanly.cargo check --workspace --all-targets— passed.cargo clippy -p agent_core -p org2 --all-targets -- -D warnings— passed; the commit hook also passed scoped clippy foragent_core,app_paths,org2, andsession_persistence.pnpm run lint— passed.pnpm run check:circular— passed; 6,350 modules checked.pnpm exec vitest run src/util/session/__tests__/sessionDispatch.test.ts— 25 passed for the acceptance fixture's CLI identity path.src-tauri:cargo fmt --all -- --check— passed.git diff --check— passed.Packaged compatibility and acceptance:
185ade293; packaged binary SHA-256:e85d079bfa098e3c2917516a7719bb8492dd75972dd83ad093f529084395dcca.v1.0.1.11,v1.1.24,v1.2.0,v1.2.5, and8aa187a70. Each old build recreated its legacy schema/file; the redesigned build removed them again, preserved the canonical Team/runtime and ordinary Session sentinels, avoided schema-column errors, and remained idempotent after another redesigned restart.~/.orgiidirectory. SQLite integrity remained OK; ordinary counts remainedagent_sessions=453,code_sessions=224, andagent_messages=72485; the legacy table count changed from 3 to 0; all 13 canonical tables were present; old related indexes/triggers were absent; the old definitions file was removed; and the canonical definitions envelope remained valid.Architecture audit
All 10 applicable layers were reviewed: compilation; removal of the old fingerprint/incremental migration code; canonical table/index/path naming; durable-runtime ownership; fail-closed default branches; shared Session/CLI boundary isolation; one documented registry/manifest; unchanged RPC/wire shapes; production/sandbox/HTTP initialization parity; and canonical definitions resolution across Settings, launch, prompt, Work Item, Routine, and debug paths. The source-level invariant is that redesigned production SQL owns only
agent_org_runtime_*; old names occur only in the exact retirement registry and historical fixtures.Performance audit
In the latest 25-sample owning-boundary run, fresh initialization had median
4.23 ms/ max6.21 ms, canonical no-op had median2.59 ms/ max2.87 ms, and 13-table cleanup had median3.04 ms/ max3.68 ms.Performance verdict: pass.