Context
PR #14935 is the first new Knowledge Base domain slice under parent epic #12456. It correctly targets two ADR-0019 cleanup classes: the Knowledge Base OpenAPI path is re-derived in toolService.mjs, and two one-shot migration CLIs re-derive Chroma host/port defaults.
Exact-head review at f9ee826134d41e716bc2012efcfef3bd33881d7f found that the intended SSOT refactor has no coherent leaf close-target and regresses both actual standalone commands before argument parsing:
node ai/scripts/migrations/backfillChromaSharedUserId.mjs --help
node ai/scripts/migrations/renameAgentIdentities.mjs --help
Both exit 1 with ReferenceError: Neo is not defined at src/core/Compare.mjs:166. The 65 migration specs and 42 KB/list-tools specs pass because their Playwright process has already loaded setup.mjs, src/Neo.mjs, and src/core/_export.mjs; that is not fresh-process CLI evidence.
Live latest-open sweep: checked the latest 20 open issues at 2026-07-10T06:24:12.785Z; no equivalent ticket found. Recent A2A claim sweep: checked the latest 30 messages across read states; no competing claim found. Knowledge Base and local issue/discussion sweeps found historical no-Neo-bootstrap constraints in #12434 / #12518, but no ticket for this exact KB SSOT + current-head CLI-bootstrap delivery leaf.
The Problem
The change needs to satisfy both sides of one coherent boundary:
- ADR 0019 requires config defaults and env bindings to be owned by the Provider SSOT and read at the use site.
- The two migration files are real Node entrypoints. Importing
ai/mcp/server/knowledge-base/config.mjs pulls in ConfigProvider and core modules, so the CLI must establish the same Neo/core bootstrap ordering used by other genuine Agent OS entrypoints before resolving kbConfig.
Import-only unit coverage masks this boundary. A green in-process suite therefore currently coexists with two broken user-facing commands, including --help, which should require neither Chroma nor SQLite.
The template change adds another runtime contract: active clones load the gitignored ai/mcp/server/knowledge-base/config.mjs, not the tracked template. A new openApiPath leaf requires overlay migration and restart coordination or the boot-time freshness guard intentionally rejects the stale clone.
The Architectural Reality
- ADR 0019 §2/§5 makes
AiConfig plus child providers the reactive SSOT. Genuine entrypoints may import and read it at the use site; hidden env/default cascades are forbidden.
ai/mcp/server/knowledge-base/mcp-server.mjs demonstrates the established bootstrap order: src/Neo.mjs + src/core/_export.mjs, then server config and services.
ai/scripts/migrations/backfillChromaSharedUserId.mjs and renameAgentIdentities.mjs are executable entrypoints, not Playwright-only helper modules.
test/playwright/unit/ai/scripts/migrations/renameAgentIdentities.spec.mjs imports setup.mjs, Neo, and core before importing the migration module, so it cannot falsify a fresh Node-process bootstrap failure.
ai/scripts/setup/initServerConfigs.mjs#assertConfigFresh deliberately fails stale active overlays and names npm run prepare -- --migrate-config plus restart as the recovery path.
- Structure-map ownership is unchanged: config shape stays in
ai/mcp/server/knowledge-base/; migration execution stays in ai/scripts/migrations/. No new file or service boundary is needed.
The Fix
Converge the existing PR in place:
- Add
openApiPath to the KB config template and consume kbConfig.openApiPath directly in toolService.mjs.
- Consume
kbConfig.host / kbConfig.port as the migration defaults while retaining explicit --host / --port precedence.
- Repair both standalone entrypoints with the established Neo/core bootstrap before the KB config dependency is evaluated.
- Add fresh-process regression coverage for both
--help commands. The test must spawn Node without Playwright's preloaded Neo globals and assert exit 0 plus usage output.
- Document the
openApiPath active-overlay rollout: run npm run prepare -- --migrate-config in each active clone, restart the KB MCP server/harness, and notify active peers because live MCP behavior changes.
Contract Ledger
| Target Surface |
Source of Authority |
Proposed Behavior |
Fallback |
Docs |
Evidence |
kbConfig.openApiPath |
ADR 0019; KB config.template.mjs |
Default to the server's shipped openapi.yaml; allow NEO_AI_MCP_KB_OPENAPI_PATH as the test-isolation override; consumer reads the resolved leaf |
Stale active overlay fails fast with the existing config-freshness instruction |
Leaf JSDoc + PR rollout note |
Config/template spec, KB list-tools smoke, active-overlay migration probe |
| Migration default Chroma endpoint |
ADR 0019; kbConfig.host / kbConfig.port |
Canonical NEO_CHROMA_HOST / NEO_CHROMA_PORT resolution comes from the Provider; explicit CLI flags still win |
Provider defaults remain localhost:8000; undocumented NEO_KB_CHROMA_* aliases are intentionally retired |
Script usage + PR named behavior change |
Focused parse/CLI probes |
backfillChromaSharedUserId.mjs --help |
Script CLI contract |
Fresh Node process exits 0 and prints usage before external-infrastructure access |
None; bootstrap failure is fatal |
Existing usage block |
Spawn-equivalent regression |
renameAgentIdentities.mjs --help |
Script CLI contract |
Fresh Node process exits 0 and prints usage before external-infrastructure access |
None; bootstrap failure is fatal |
Existing usage block |
Spawn-equivalent regression |
| Active KB config overlay |
Config-template change guide; assertConfigFresh |
Every active clone understands openApiPath before KB restart |
npm run prepare -- --migrate-config, then restart |
PR Post-Merge Validation + A2A notification |
One stale-overlay detection/migration receipt |
Decision Record impact
aligned-with ADR 0019 — this leaf applies the existing SSOT and entrypoint-boundary rules; it does not amend or supersede the ADR.
Acceptance Criteria
Out of Scope
- Other ADR-0019 census batches under #12456.
- Broad changes to Chroma lifecycle, migration data semantics, or shared identity constants.
- Reintroducing undocumented
NEO_KB_CHROMA_* aliases.
- Committing any gitignored
config.mjs overlay.
Avoided Traps
- Treating Playwright import success as standalone CLI proof.
- Reading the Provider before Neo/core bootstrap exists.
- Re-deriving env/default values in each script to avoid bootstrap.
- Closing the epic from a single batch.
- Shipping a tracked template key without coordinating the active gitignored overlays.
Related
Parent: #12456
Implementation: #14935
Related prevention work: #14500
Historical lightweight-runner context: #12434, #12518
Origin Session ID
be72c069-8cdc-46f6-8624-54f041a43f24
Handoff Retrieval Hints
query_raw_memories("PR 14935 AiConfig migration CLI bootstrap crash")
- Exact head:
f9ee826134d41e716bc2012efcfef3bd33881d7f
- Falsifiers: the two direct
node ... --help commands above.
Context
PR #14935 is the first new Knowledge Base domain slice under parent epic #12456. It correctly targets two ADR-0019 cleanup classes: the Knowledge Base OpenAPI path is re-derived in
toolService.mjs, and two one-shot migration CLIs re-derive Chroma host/port defaults.Exact-head review at
f9ee826134d41e716bc2012efcfef3bd33881d7ffound that the intended SSOT refactor has no coherent leaf close-target and regresses both actual standalone commands before argument parsing:Both exit 1 with
ReferenceError: Neo is not definedatsrc/core/Compare.mjs:166. The 65 migration specs and 42 KB/list-tools specs pass because their Playwright process has already loadedsetup.mjs,src/Neo.mjs, andsrc/core/_export.mjs; that is not fresh-process CLI evidence.Live latest-open sweep: checked the latest 20 open issues at 2026-07-10T06:24:12.785Z; no equivalent ticket found. Recent A2A claim sweep: checked the latest 30 messages across read states; no competing claim found. Knowledge Base and local issue/discussion sweeps found historical no-Neo-bootstrap constraints in
#12434/#12518, but no ticket for this exact KB SSOT + current-head CLI-bootstrap delivery leaf.The Problem
The change needs to satisfy both sides of one coherent boundary:
ai/mcp/server/knowledge-base/config.mjspulls inConfigProviderand core modules, so the CLI must establish the same Neo/core bootstrap ordering used by other genuine Agent OS entrypoints before resolvingkbConfig.Import-only unit coverage masks this boundary. A green in-process suite therefore currently coexists with two broken user-facing commands, including
--help, which should require neither Chroma nor SQLite.The template change adds another runtime contract: active clones load the gitignored
ai/mcp/server/knowledge-base/config.mjs, not the tracked template. A newopenApiPathleaf requires overlay migration and restart coordination or the boot-time freshness guard intentionally rejects the stale clone.The Architectural Reality
AiConfigplus child providers the reactive SSOT. Genuine entrypoints may import and read it at the use site; hidden env/default cascades are forbidden.ai/mcp/server/knowledge-base/mcp-server.mjsdemonstrates the established bootstrap order:src/Neo.mjs+src/core/_export.mjs, then server config and services.ai/scripts/migrations/backfillChromaSharedUserId.mjsandrenameAgentIdentities.mjsare executable entrypoints, not Playwright-only helper modules.test/playwright/unit/ai/scripts/migrations/renameAgentIdentities.spec.mjsimportssetup.mjs, Neo, and core before importing the migration module, so it cannot falsify a fresh Node-process bootstrap failure.ai/scripts/setup/initServerConfigs.mjs#assertConfigFreshdeliberately fails stale active overlays and namesnpm run prepare -- --migrate-configplus restart as the recovery path.ai/mcp/server/knowledge-base/; migration execution stays inai/scripts/migrations/. No new file or service boundary is needed.The Fix
Converge the existing PR in place:
openApiPathto the KB config template and consumekbConfig.openApiPathdirectly intoolService.mjs.kbConfig.host/kbConfig.portas the migration defaults while retaining explicit--host/--portprecedence.--helpcommands. The test must spawn Node without Playwright's preloaded Neo globals and assert exit 0 plus usage output.openApiPathactive-overlay rollout: runnpm run prepare -- --migrate-configin each active clone, restart the KB MCP server/harness, and notify active peers because live MCP behavior changes.Contract Ledger
kbConfig.openApiPathconfig.template.mjsopenapi.yaml; allowNEO_AI_MCP_KB_OPENAPI_PATHas the test-isolation override; consumer reads the resolved leafkbConfig.host/kbConfig.portNEO_CHROMA_HOST/NEO_CHROMA_PORTresolution comes from the Provider; explicit CLI flags still winlocalhost:8000; undocumentedNEO_KB_CHROMA_*aliases are intentionally retiredbackfillChromaSharedUserId.mjs --helprenameAgentIdentities.mjs --helpassertConfigFreshopenApiPathbefore KB restartnpm run prepare -- --migrate-config, then restartDecision Record impact
aligned-with ADR 0019 — this leaf applies the existing SSOT and entrypoint-boundary rules; it does not amend or supersede the ADR.
Acceptance Criteria
Resolvestarget; parent epic #12456 remains a non-closing related node.toolService.mjsreadskbConfig.openApiPathwithout its own env/default/path derivation.--host/--portprecedence, and document the intentional retirement ofNEO_KB_CHROMA_HOST/NEO_KB_CHROMA_PORT.--helpcommands exit 0 in fresh Node processes and print their usage text without touching ChromaDB or SQLite.f9ee826134d41e716bc2012efcfef3bd33881d7fwith the reproducedNeo is not definederror and pass after the bootstrap repair.openApiPath, the active-clone overlay migration command, restart requirement, and peer notification.Out of Scope
NEO_KB_CHROMA_*aliases.config.mjsoverlay.Avoided Traps
Related
Parent: #12456
Implementation: #14935
Related prevention work: #14500
Historical lightweight-runner context:
#12434,#12518Origin Session ID
be72c069-8cdc-46f6-8624-54f041a43f24Handoff Retrieval Hints
query_raw_memories("PR 14935 AiConfig migration CLI bootstrap crash")f9ee826134d41e716bc2012efcfef3bd33881d7fnode ... --helpcommands above.