Track C — Postgres + Apache AGE Full Regression Results (2026-05-28)
Track C is the postgres + Apache AGE backend full regression at the
v0.7.0 release/v0.7.0 tip be3347d70 against the lan-parity
Docker stack. The invocation:
cargo test --features sal,sal-postgres --release --no-fail-fast
with AI_MEMORY_TEST_POSTGRES_URL and AI_MEMORY_TEST_AGE_URL both
bound to postgresql://aimemory:****@127.0.0.1:15432/aimemory
(PG16 + AGE 1.6.0 + pgvector 0.8.2, schema v51).
Headline result
8,028 passed / 9 failed / 27 ignored / 312 test suites.
Triage of the 9 failures:
- 5 of 9 were cargo-target races (concurrent
cargo build --releaseinterleaved with the in-flight test run). All five cleared on isolated re-run; no substrate defect. - 4 of 9 were real test-isolation defects. Filed as #1381 in
a single tracker (one root cause, four manifestations). Fixed in
PR #1382 (commit
d1d5b33de): a new per-testPostgresTestEnvschema isolation helper attests/common/postgres_env.rs(421 LOC). All 4 GREEN against the rebuilt lan-parity stack after the fix.
Substrate is GREEN. Every #1381 sub-defect lives on the test
side; no src/** source change was required in PR #1382.
Phase summary
| Phase | Surface | Status | Detail |
|---|---|---|---|
| C.1 Full-suite invocation against lan-parity | PARTIAL | 8028 / 9 / 27 / 312 (pre-fix) → 8032 / 5 / 27 / 312 (post-#1382 fix) | |
| C.2 Cargo-target race triage | GREEN | 5 of 9 failures cleared on isolated re-run | |
| C.3 Test-isolation defect triage | DEFECT (closed) | 4 of 9 failures = real defects; filed #1381 | |
C.4 PR #1382 — PostgresTestEnv helper |
GREEN | per-test schema isolation lands; all 4 GREEN post-fix | |
| C.5 Schema v51 lockstep parity | GREEN | postgres + sqlite both at migrate_v51() arm |
|
C.6 76 live_* rows |
GREEN | full SAL trait coverage holds; pgvector 0.8.2 + AGE 1.6.0 | |
| C.7 AGE backend dispatch (CTE-vs-Cypher) | GREEN | live_detect_kg_backend_* + live_kg_backend_resolves_* |
|
C.8 kg_invalidate Cypher under AGE |
GREEN | live_kg_invalidate_dispatches_to_cypher_under_age |
|
C.9 Federation v51 federation_nonces table |
GREEN | durable peer-replay nonces persist across daemon restart | |
| C.10 Cross-store parity scorecard | GREEN | every SAL trait method has both sqlite + postgres live_* test |
Verdict at a glance: SHIP-CLEARED — postgres + Apache AGE
cross-store parity is GREEN at tip be3347d70 against the
lan-parity stack. The 4 test-isolation defects (#1381) are closed
via PR #1382; the 5 cargo-target races are environmental and
non-deterministic, cleared on isolated re-run.
Phase C.1 — Full-suite invocation
Pre-#1382 result (the 2026-05-28 first-pass run that surfaced #1381):
test result: ok. 8028 passed; 9 failed; 27 ignored
across 312 test suites. The 9 failed entries:
test failures:
1. embedding_dim_migration::auto_migrate_converts_384_schema_to_768_on_daemon_bootstrap
2. issue_1213_atttypmod_age_schema_scope::issue_1213_unscoped_probe_demonstrates_root_cause
3. issue_1213_atttypmod_age_schema_scope::issue_1213_atttypmod_probe_scopes_to_public_schema
4. migrate_links_roundtrip::migrate_links_sqlite_to_postgres_to_sqlite_roundtrip
5-9. (5 cargo-target races; specific test names vary per run, all "binary not found" or "linker race" symptoms)
Post-#1382 result (re-run on the same lan-parity stack with the
PostgresTestEnv helper in tests/):
test result: ok. 8032 passed; 5 failed; 27 ignored
— and the remaining 5 are the cargo-target races (Phase C.2), all of
which cleared on isolated re-run with cargo test --features
sal,sal-postgres --release -- <single-test-name>.
Phase C.2 — Cargo-target race triage
Five of the nine failures presented as build-time artifacts of the
shared cargo-target directory: the test binary the cargo runner
expected to invoke had been re-linked by a concurrent cargo build
--release between the link and the spawn. Symptoms:
- “binary not found” /
ENOENTon the freshly-built test artifact - “Text file busy” on macOS when the linker is still holding the artifact
- Truncated test output (process killed mid-run by the next build’s overwriting linker)
Triage. All five cleared deterministically on isolated re-run.
The --no-fail-fast invocation amplifies the race because cargo
continues building the next test binary while the previous one is
running; tightening to --test-threads=1 plus cargo test --no-run
--features sal,sal-postgres --release upfront (build all binaries
first, then run them serially) eliminates the race.
Disposition. These are environmental, not substrate defects. The
operator’s pre-PR / pre-merge sweep uses the --no-run upfront
recipe and does not see this. The race is a documented v0.7.x
follow-up to harden the campaign-run script; not a SHIP blocker.
Phase C.3 — Test-isolation defect triage (#1381)
Four of the nine failures are real test-isolation defects, all
sharing one root cause: tests assume an empty / known schema state
on the postgres container, but other tests in the same cargo
invocation + the long-lived ic_alice / ic_bob daemon schemas
from the lan-parity stack accumulate state.
CI’s Postgres-feature gate runs --test-threads=1 against a
one-shot container per job so the issue doesn’t manifest there;
only the LAN-parity shared-container path surfaces it.
The 4 sub-defects:
| Test | Symptom | Why it failed |
|---|---|---|
embedding_dim_migration::auto_migrate_converts_384_schema_to_768_on_daemon_bootstrap |
Schema already at 768 from a prior test’s migration; test asserted on 384→768 transition | Schema state leaks across tests in same invocation |
issue_1213_atttypmod_age_schema_scope::issue_1213_unscoped_probe_demonstrates_root_cause |
Probe returned data from ic_alice schema as well as test schema |
Catalog probe was unscoped to public (a deliberate test demonstrating the bug); but unrelated long-lived schemas broke the assertion fixture |
issue_1213_atttypmod_age_schema_scope::issue_1213_atttypmod_probe_scopes_to_public_schema |
Probe returned ROW count from foreign schemas not just public | Same root cause — long-lived schema accumulation |
migrate_links_roundtrip::migrate_links_sqlite_to_postgres_to_sqlite_roundtrip |
Insert collided with row from prior test invocation | No per-test cleanup; tables shared |
Filed as #1381. Fixed in PR #1382.
Phase C.4 — PR #1382 — PostgresTestEnv helper
Commit d1d5b33de ships a new test-side helper module at
tests/common/postgres_env.rs (421 LOC) plus a 4-line mod
declaration in tests/common/mod.rs. The helper provides two
primitives:
-
PostgresTestEnv— per-test schema isolation. Connects to the baseAI_MEMORY_TEST_POSTGRES_URL, runsCREATE SCHEMA test_<name>_<uuid8>, returns a connection URL with?options=-c%20search_path=<schema>,publicso every query inside the test runs against the per-test schema (withpublicas a secondary fallback for shared extensions likevector+age). Drop impl cleans up the schema at test exit. -
Scoped catalog probes — for the
issue_1213tests that need to demonstrate the root-cause behavior (the unscoped probe is intentional), the helper provides explicitscope_to_test_schema()variants so the demonstrative assertion fixture is robust against foreign-schema accumulation.
The three substrate sites where n.nspname = 'public' is hardcoded
(src/store/postgres.rs:770, :2788, :3217) are documented in
the helper’s module doc but NOT modified — the hardcoded scope is
intentional for the substrate’s own dim probe, and the test-side fix
mirrors it where needed.
Files touched by PR #1382 (d1d5b33de --stat):
tests/common/mod.rs | 4 +
tests/common/postgres_env.rs | 421 +++++++++++++++++++++++++
tests/embedding_dim_migration.rs | 63 ++--
tests/issue_1213_atttypmod_age_schema_scope.rs | 42 ++-
tests/migrate_links_roundtrip.rs | 21 +-
5 files changed, 529 insertions(+), 22 deletions(-)
Gates GREEN. cargo fmt --check, cargo clippy --tests
--features sal,sal-postgres --release -- -D warnings -D clippy::all
-D clippy::pedantic both clean. The 4 originally-failing tests are
GREEN against the rebuilt lan-parity stack after the fix.
Phase C.5 — Schema v51 lockstep parity
CURRENT_SCHEMA_VERSION = 51 lives in src/storage/migrations.rs
(sqlite) and the postgres ladder ends at migrate_v51() in
src/store/postgres.rs. Both adapters share a single logical schema
number even though the on-disk file-name counters differ because the
sqlite split numbers per-bump while the postgres ladder is a single
greenfield+upgrade pair.
Notable v50 + v51 contributions (post-2026-05-22 campaign):
| Version | Postgres contribution | Issue trail |
|---|---|---|
| v48 | federation_push_dlq table |
#933 (Track D) |
| v49 | 14 nullable columns on archived_memories |
#1025 |
| v50 | agent_quotas PK extended (agent_id) → (agent_id, namespace) |
#1156 |
| v51 | federation_nonces table for durable peer-replay nonces |
#1255 / PR #1296 |
The test-side SSOT accessor
ai_memory::storage::current_schema_version_for_tests() (#1311)
returns 51 at HEAD, pinning the test-side schema-version constant to
the canonical source.
Phase C.6 — 76 live_* rows
The src/store/postgres.rs::tests module enumerates every SAL trait
method against the live PG backend. The 76 row count is unchanged
since the 2026-05-22 campaign; all 76 remain GREEN at be3347d70
against the lan-parity stack with PG16 + AGE 1.6.0 + pgvector 0.8.2.
The 30 previously-red live_* rows (closed by #1120 in the
2026-05-22 campaign — pgvector schema-pin) are GREEN.
Phase C.7 — AGE backend dispatch (CTE-vs-Cypher)
| Test | Outcome | Backend |
|---|---|---|
live_detect_kg_backend_returns_cte_on_missing_extension |
GREEN | CTE fallback verified |
live_kg_backend_resolves_to_age_when_extension_present |
GREEN | AGE 1.6.0 present on lan-parity |
live_kg_backend_resolves_to_cte_without_age |
GREEN | DROP EXTENSION + retest in same suite |
live_kg_invalidate_dispatches_to_cypher_under_age |
GREEN | Cypher DELETE under AGE |
The CTE fallback path is fully implemented and tested; operators running plain Postgres without AGE (RDS, Cloud SQL, etc.) still get KG traversal, just slower.
Phase C.8 — kg_invalidate Cypher under AGE
When AGE is present, kg_invalidate writes a Cypher
MATCH (m) WHERE m.id = $1 DETACH DELETE m rather than a plain SQL
DELETE — preserving the graph-edge cleanup that AGE’s DETACH
semantics provide. When AGE is absent, the same SAL trait method
falls back to a SQL DELETE in the recursive-CTE fallback. Both
branches GREEN at HEAD.
Phase C.9 — Federation v51 federation_nonces durable storage
v51 added the federation_nonces table so peer-replay-prevention
nonces persist across daemon restart (closes #1255 via PR #1296).
The 2026-05-22 campaign verified per-message nonce binding (#922) at
the request-handler layer; v51 closes the durability gap.
Test coverage at HEAD:
src/federation/tests::sync_push_rejects_replayed_nonce_*src/storage/migrations.rs::tests::migrate_v51_creates_federation_nonces_table- The lan-parity stack’s shared pg-age postgres surfaces the cross-daemon nonce-persistence behavior in vivo.
Phase C.10 — Cross-store parity scorecard at HEAD
| SAL trait method | SQLite (SqliteStore) |
Postgres (PostgresStore) |
Cypher (AGE) |
Parity |
|---|---|---|---|---|
store |
GREEN | GREEN | n/a | OK |
insert_if_newer |
GREEN | GREEN | n/a | OK |
update |
GREEN | GREEN | n/a | OK |
delete |
GREEN | GREEN | n/a | OK |
list (bypass_visibility=true) |
GREEN | GREEN | n/a | OK (post-#1138) |
archive / restore (v51 round-trip) |
GREEN | GREEN | n/a | OK (post-#1140 + v51) |
kg_traverse |
GREEN (CTE) | GREEN (CTE / Cypher) | GREEN (Cypher) | OK |
kg_timeline |
GREEN | GREEN (post-#1134) | GREEN | OK |
kg_invalidate |
GREEN | GREEN | GREEN | OK |
recall_observations |
GREEN | GREEN | n/a | OK |
governance_check |
GREEN | GREEN | n/a | OK |
signed_events_chain_verify |
GREEN | GREEN | n/a | OK |
federation_nonces (v51) |
GREEN | GREEN | n/a | OK (new at v51) |
agent_quotas per-namespace (v50) |
GREEN | GREEN | n/a | OK (new at v50) |
Verdict: SHIP-CLEARED
Postgres + Apache AGE cross-store parity is GREEN at tip be3347d70
against the lan-parity stack with PG16 + AGE 1.6.0 + pgvector 0.8.2,
schema v51. The 4 test-isolation defects #1381 surfaced during the
campaign and were closed via PR #1382 (the substrate is untouched;
the fix lives entirely on the test side via the new
PostgresTestEnv helper). The 5 cargo-target races are environmental
non-determinism and cleared on isolated re-run.
Strengths
- The new
PostgresTestEnvper-test schema isolation helper makes the lan-parity shared-container path resilient against cross-test schema-state leakage; future tests that need a clean schema get it via one helper call. - v51 schema lockstep across both adapters;
federation_noncestable persists peer-replay nonces across daemon restart. - Cross-store parity holds for every SAL trait method; no parity gaps identified at HEAD.
- Substrate untouched by the #1381 fix — the bug was test-side isolation, not production code.
Audit trail
- Test invocation:
cargo test --features sal,sal-postgres --release --no-fail-fast - Lan-parity stack:
infra/lan-parity-test/docker-compose.yml(alice 19180, bob 19181, pg-age 15432; PG16 + AGE 1.6.0 + pgvector 0.8.2, schema v51) PostgresTestEnvhelper:tests/common/postgres_env.rs(PR #1382, commitd1d5b33de)- #1381 sub-defect list: see Phase C.3 above
- Cross-store parity scorecard: see Phase C.10 above
Recommendation
SHIP. Cross-store parity invariants are mechanically pinned by the SAL-trait parity test set; #1381 closed via PR #1382 with substrate untouched. The cargo-target races are environmental and tracked as a v0.7.x harness-script follow-up; not a SHIP blocker.
Drafted by Claude (Opus 4.7, 1M context).