LearnNewsExamplesServices
Frontmatter
id12499
titleconfig.template collection-names leaf: declarative via toggle+formula with per-worker-unique test names (memory-core)
stateClosed
labels
enhancementai
assigneesneo-opus-grace
createdAtJun 4, 2026, 2:53 PM
updatedAtJun 4, 2026, 8:15 PM
githubUrlhttps://github.com/neomjs/neo/issues/12499
authorneo-opus-grace
commentsCount1
parentIssuenull
subIssues[]
subIssuesCompleted0
subIssuesTotal0
blockedBy[]
blocking[]
closedAtJun 4, 2026, 8:15 PM

config.template collection-names leaf: declarative via toggle+formula with per-worker-unique test names (memory-core)

neo-opus-grace
neo-opus-grace commented on Jun 4, 2026, 2:53 PM

Context

ai/mcp/server/memory-core/config.template.mjs collections.memory + collections.session are inline-process.env leaf defaults (ADR 0019 §3 A4) — the 2 remaining baselined by the SSOT lint (#12474):

memory : leaf(process.env.UNIT_TEST_MODE === 'true' ? `test-memory-${Date.now()}-${Math.random()...}`  : 'neo-agent-memory',   'NEO_MEMORY_COLLECTION_NAME',  'string'),
session: leaf(process.env.UNIT_TEST_MODE === 'true' ? `test-session-${Date.now()}-${Math.random()...}` : 'neo-agent-sessions', 'NEO_SESSION_COLLECTION_NAME', 'string')

The dynamic sub-case of #12451 (chroma was #12480/#12481; graph was #12491/#12494). The test values are per-worker-unique (${Date.now()}-${Math.random()}) so parallel playwright workers (fullyParallel: true, multi-worker locally) don't collide on a shared collection.

The Fix — the #12494 formula pattern + a module-const per-worker-unique test name

The per-worker uniqueness is preserved by a module-const generated at config-load (per worker process); only the inline process.env.UNIT_TEST_MODE check (the A4 antipattern) is removed — not the generation:

// module-level (config-load, per worker process — no process.env CHECK; like the existing neoRootDir/cwd consts):
const testMemoryCollection  = `test-memory-${Date.now()}-${Math.random().toString(36).slice(2)}`;
const testSessionCollection = `test-session-${Date.now()}-${Math.random().toString(36).slice(2)}`;

collections: {
    memory     : leaf('neo-agent-memory',    'NEO_MEMORY_COLLECTION_NAME',       'string'), // prod, static
    memoryTest : leaf(testMemoryCollection,  'NEO_MEMORY_COLLECTION_NAME_TEST',  'string'), // per-worker-unique
    session    : leaf('neo-agent-sessions',  'NEO_SESSION_COLLECTION_NAME',      'string'),
    sessionTest: leaf(testSessionCollection, 'NEO_SESSION_COLLECTION_NAME_TEST', 'string'),
    useTestDatabase: leaf(false, 'UNIT_TEST_MODE', 'boolean'),                               // toggle (env-arg)
    graph      : leaf('neo-native-graph',    'NEO_GRAPH_COLLECTION_NAME',        'string')   // unchanged (static)
}
formulas: {
    'collections.memory' : data => data.collections.useTestDatabase ? data.collections.memoryTest  : data.collections.memory,
    'collections.session': data => data.collections.useTestDatabase ? data.collections.sessionTest : data.collections.session
}

The ~3 consumers (HealthService, ChromaManager, defragChromaDB) read collections.memory/session unchanged (the formula resolves them). A4-clean (no inline process.env in any leaf default — the generation is a module const, the selection is the toggle+formula). Per-worker uniqueness preserved (the module const generates per config-load = per worker process). Maintenance (defragChromaDB, no UNIT_TEST_MODE) → prod names. This is the #12494 formula precedent — NOT the env-relocation the #12451 umbrella note suggests (superseded; see #12451 comment).

Contract Ledger

Surface Type Contract
collections.memory / .session config leaf Prod names (static literals); env NEO_MEMORY_COLLECTION_NAME / NEO_SESSION_COLLECTION_NAME.
collections.memoryTest / .sessionTest config leaf Per-worker-unique test names (module-const default); env …_TEST.
collections.useTestDatabase config leaf Toggle. Default false; env UNIT_TEST_MODE.
collections.memory / .session formula useTestDatabase ? *Test : * (prod). Consumers read unchanged.
testMemoryCollection / testSessionCollection module const Generated at config-load (per worker process) for per-worker uniqueness.

Acceptance Criteria

  • collections.memory / session declarative (no inline process.env); selected by-construction via the toggle+formula.
  • Per-worker uniqueness preserved — parallel workers resolve distinct test collections (verify under fullyParallel).
  • NEO_MEMORY_COLLECTION_NAME + NEO_SESSION_COLLECTION_NAME rows removed from the SSOT-lint BASELINEBASELINE empties → the lint flips to fully-enforcing (no grandfathered instances).
  • Consumers (HealthService / ChromaManager / defragChromaDB) unchanged; maintenance resolves prod names.
  • config.template.spec proves the formula resolves the per-worker-unique test name under the toggle.

Scope — completes #12451

The 2 dynamic collection-names (memory + session). This is the last #12451 reshape: chroma (#12481) + graph (#12494) + this = all instances declarative → the SSOT lint baseline empties → fully-enforcing. (The lint's lintConfigTemplateSsot.spec baselined-fixture already derives from BASELINE[0] per #12494, but an empty BASELINE needs the suppression test guarded/revisited — flag during impl.)

Refs #12451 (reshape umbrella). Part of Epic #12456 (AiConfig reactive Provider SSOT cleanup). Design per the #12494 precedent + ADR 0019 §3 (A4) / §5.

Authored by Claude Opus 4.8 (Claude Code), /lead-role. MC session f5432f03-d2b6-4bc0-a7b5-9fbdafe4b7b9.

tobiu referenced in commit 7cf3f26 - "refactor(ai): resolve memory-core collection-names declaratively via toggle+formula (#12499) (#12500) on Jun 4, 2026, 8:15 PM
tobiu closed this issue on Jun 4, 2026, 8:15 PM