Context
Discovered while diagnosing #12166 (PR #12179): a direct query of a live deployment's Chroma (2026-05-29) found 1,263 orphan test-memory-* / test-session-* collections out of 1,269 total — only ~6 are real (neo-knowledge-base, neo-agent-memory, neo-agent-sessions, neo-native-graph). They sit in default_tenant / default_database, the SAME tenant/db as production collections.
The Problem
#10867 (merged PR #10868) deliberately gave unit tests process-isolated collection names — test-memory-${Date.now()}-… / test-session-${Date.now()}-… (see ai/mcp/server/memory-core/config.template.mjs under UNIT_TEST_MODE, plus per-spec beforeAll blocks) — so cleanupChromaManager() deletes the test collections instead of wiping neo-agent-memory / neo-agent-sessions. That P0-wipe fix holds: production is protected.
The flip side was never closed. Those uniquely-named test collections are created in whatever Chroma the suite points at (localhost:8000 in single-host deployments = the live store), and the cleanup side is incomplete: any spec that creates them without an afterAll cleanupChromaManager(), plus every interrupted/killed run (CI cancel, local Ctrl-C), leaves its collections behind. Because names are unique per run, orphans accumulate monotonically → 1,263 and counting. This bloats every listCollections call (a hot path for ChromaManager + KB ops) and consumes disk.
The Architectural Reality
ai/mcp/server/memory-core/config.template.mjs — collections.memory / collections.session resolve to test-memory-${Date.now()}-… under UNIT_TEST_MODE.
test/playwright/unit/ai/.../util.mjs cleanupChromaManager() — the teardown primitive #10867 relies on; effective only when a spec actually calls it in afterAll AND the run reaches teardown.
- Tests connect to the configured Chroma host:port; in a single-host deployment that is the operator's live store (
default_tenant/default_database), so test collections land beside production.
The Fix (directions — choose at intake)
- Robust teardown — audit every spec that creates
test-* collections; ensure each has an afterAll cleanup. Necessary but insufficient (interrupted runs still orphan).
- Wholesale isolation — point unit tests at an ephemeral / namespaced Chroma (separate
tenant/database, or a throwaway persist dir) so they never touch the live store and the whole namespace is purgeable. Strongest option.
- Orphan purge utility — a maintenance script under
ai/scripts/maintenance/ that deletes test-memory-* / test-session-* collections (optionally older than N), runnable on demand + optionally at suite start. Covers interrupted-run residue and the existing backlog.
Acceptance Criteria
Out of Scope
- #10867's production-protection (done —
test-* naming + cleanupChromaManager failsafe).
- One-time cleanup of the existing 1,263 orphans in a specific deployment (an operator action; the §3 purge utility serves it).
Related
- #10867 — introduced the
test-* isolation naming; this ticket closes its un-addressed cleanup flip-side.
- #10845 — destructive-op guard (parent of #10867).
- #12166 / PR #12179 — discovery context (orthogonal aiConfig parent-chain work).
Origin Session ID: 653970c8-8466-4609-8a15-28350234af10
Retrieval Hint: "orphan test-memory test-session Chroma collections accumulate unit test isolation cleanup #10867"
Context
Discovered while diagnosing #12166 (PR #12179): a direct query of a live deployment's Chroma (2026-05-29) found 1,263 orphan
test-memory-*/test-session-*collections out of 1,269 total — only ~6 are real (neo-knowledge-base,neo-agent-memory,neo-agent-sessions,neo-native-graph). They sit indefault_tenant/default_database, the SAME tenant/db as production collections.The Problem
#10867 (merged PR #10868) deliberately gave unit tests process-isolated collection names —
test-memory-${Date.now()}-…/test-session-${Date.now()}-…(seeai/mcp/server/memory-core/config.template.mjsunderUNIT_TEST_MODE, plus per-specbeforeAllblocks) — socleanupChromaManager()deletes the test collections instead of wipingneo-agent-memory/neo-agent-sessions. That P0-wipe fix holds: production is protected.The flip side was never closed. Those uniquely-named test collections are created in whatever Chroma the suite points at (
localhost:8000in single-host deployments = the live store), and the cleanup side is incomplete: any spec that creates them without anafterAllcleanupChromaManager(), plus every interrupted/killed run (CI cancel, local Ctrl-C), leaves its collections behind. Because names are unique per run, orphans accumulate monotonically → 1,263 and counting. This bloats everylistCollectionscall (a hot path for ChromaManager + KB ops) and consumes disk.The Architectural Reality
ai/mcp/server/memory-core/config.template.mjs—collections.memory/collections.sessionresolve totest-memory-${Date.now()}-…underUNIT_TEST_MODE.test/playwright/unit/ai/.../util.mjscleanupChromaManager()— the teardown primitive #10867 relies on; effective only when a spec actually calls it inafterAllAND the run reaches teardown.default_tenant/default_database), so test collections land beside production.The Fix (directions — choose at intake)
test-*collections; ensure each has anafterAllcleanup. Necessary but insufficient (interrupted runs still orphan).tenant/database, or a throwaway persist dir) so they never touch the live store and the whole namespace is purgeable. Strongest option.ai/scripts/maintenance/that deletestest-memory-*/test-session-*collections (optionally older than N), runnable on demand + optionally at suite start. Covers interrupted-run residue and the existing backlog.Acceptance Criteria
test-*collections in a production Chroma tenant/database (via isolation and/or guaranteed teardown).test-*orphan collections (covers interrupted-run residue).test-*collections in the live store (or only inside an auto-purged isolated namespace).Out of Scope
test-*naming +cleanupChromaManagerfailsafe).Related
test-*isolation naming; this ticket closes its un-addressed cleanup flip-side.Origin Session ID: 653970c8-8466-4609-8a15-28350234af10
Retrieval Hint: "orphan test-memory test-session Chroma collections accumulate unit test isolation cleanup #10867"