Context
Operator-flagged regression surfaced after #11967 + #11966 + #11962 merged to dev. Two distinct substrate-quality bugs:
config.template.mjs import anti-pattern in 7 runtime spots. #11967 added import AiConfig from '../../../config.template.mjs' in ai/mcp/server/memory-core/config.template.mjs + ai/mcp/server/knowledge-base/config.template.mjs. This compounded a pre-existing 5-spot legacy pattern in ai/daemons/orchestrator/Orchestrator.mjs, ai/daemons/orchestrator/daemon.mjs, ai/daemons/orchestrator/services/TenantRepoSyncService.mjs, ai/scripts/maintenance/backup.mjs, ai/scripts/maintenance/defragChromaDB.mjs. Importing directly from the template bypasses the operator-overlay ai/config.mjs (gitignored, per learn/agentos/DeploymentCookbook.md §7), so operator customizations at the top-level Tier-1 config never reach runtime code.
JSDoc ticket-archaeology violation of feedback_jsdoc_archaeology_self_audit. #11966 cycle-3 added decay-prone ticket/Epic/Discussion/OQ anchors in production-code JSDoc — ai/services/graph/providerDispatch.mjs, several inline comments in ai/services/memory-core/TextEmbeddingService.mjs, ai/services/memory-core/SessionService.mjs (only the cycle-2 additions, not pre-existing comments). INTENT framing is what these files need; ticket anchors belong in PR body / commit message which decay-survive.
The Problem
Sub-problem 1: config.template.mjs imports
Direct grep of dev HEAD:
ai/daemons/orchestrator/daemon.mjs:33:import AiConfig from '../../config.template.mjs';
ai/daemons/orchestrator/Orchestrator.mjs:12:import AiConfig from '../../config.template.mjs';
ai/daemons/orchestrator/services/TenantRepoSyncService.mjs:4:import AiConfig from '../../../config.template.mjs';
ai/mcp/server/knowledge-base/config.template.mjs:3:import AiConfig from '../../../config.template.mjs';
ai/mcp/server/memory-core/config.template.mjs:2:import AiConfig from '../../../config.template.mjs';
ai/scripts/maintenance/defragChromaDB.mjs:8:import AiConfig from '../../config.template.mjs';
ai/scripts/maintenance/backup.mjs:14:import AiConfig from '../../config.template.mjs';
All 7 should resolve through ai/config.mjs (the operator-overlay), with ai/scripts/setup/initServerConfigs.mjs extended to auto-create ai/config.mjs from ai/config.template.mjs on first install — same shape used today for ai/mcp/server/*/config.mjs.
Sub-problem 2: JSDoc archaeology I authored this session
Files where production JSDoc references decay-prone anchors (#NNNN, Sub-N, OQM, Discussion #N, Closes #N AC<N>):
ai/services/graph/providerDispatch.mjs (NEW in #11966 cycle-3) — @summary, body prose, "OQ2 disposition during Discussion #11961"
ai/services/memory-core/TextEmbeddingService.mjs lines 49, 190, 207, 229, 247 (cycle-2 additions)
ai/services/memory-core/SessionService.mjs lines 19, 190, 546 (cycle-2 additions only — pre-existing anchors at lines 539/584/676/831/854-856 are not in this ticket's scope)
Test-file test.describe labels are the documented exception (test-traceability boundary per the memory). But the multi-line JSDoc preamble blocks above the test.describe are NOT labels — they're docblocks with archaeology:
test/playwright/unit/ai/services/graph/providerDispatch.spec.mjs JSDoc preamble (lines 20-31, keep line 33 test.describe label)
test/playwright/unit/ai/services/memory-core/SessionService.buildChatModel.spec.mjs JSDoc preamble (lines 20-30, keep line 31 test.describe label)
The Architectural Reality
Primary surfaces:
ai/scripts/setup/initServerConfigs.mjs (extend to handle ai/config.mjs)
- 7 import sites listed above (re-point to
ai/config.mjs)
learn/agentos/DeploymentCookbook.md §7 (document the new auto-create behavior)
- Production JSDoc cleanup in 4 source files + 2 spec-file preambles
The auto-create mechanism already exists for MC/KB; this ticket extends it to the top-level Tier-1 config. Sub-problem 2 is mechanical doc-comment editing per the established memory rule.
The Fix
Stage 1: Auto-create ai/config.mjs from ai/config.template.mjs
Extend initServerConfigs.mjs to handle the top-level ai/config.{mjs,template.mjs} pair using the same first-time-copy + drift-detection shape used for ai/mcp/server/*. Add ai/config.mjs to .gitignore enforcement if not already covered (it is — line 105).
Stage 2: Re-point 7 imports
Update all 7 files to import from ai/config.mjs instead of ai/config.template.mjs. Maintain relative-path semantics:
ai/daemons/orchestrator/daemon.mjs: '../../config.mjs'
ai/daemons/orchestrator/Orchestrator.mjs: '../../config.mjs'
ai/daemons/orchestrator/services/TenantRepoSyncService.mjs: '../../../config.mjs'
ai/mcp/server/memory-core/config.template.mjs: '../../../config.mjs'
ai/mcp/server/knowledge-base/config.template.mjs: '../../../config.mjs'
ai/scripts/maintenance/backup.mjs: '../../config.mjs'
ai/scripts/maintenance/defragChromaDB.mjs: '../../config.mjs'
Note: changing the MC/KB template files' imports also propagates to the auto-generated MC/KB config.mjs files on the next npm run prepare -- --migrate-config invocation.
Stage 3: Strip JSDoc ticket-archaeology from this-session production code
Targets (this-session-only — pre-existing archaeology is out of scope):
ai/services/graph/providerDispatch.mjs: replace ticket-anchored @summary with INTENT framing; strip "Closes #11965 AC5 ...", "OQ2 disposition during Discussion #11961"
ai/services/memory-core/TextEmbeddingService.mjs: strip #11965 Sub-2 cycle-2 markers in inline comments at the listed line numbers
ai/services/memory-core/SessionService.mjs: strip #11965 Sub-2 cycle-2 markers in the 3 listed cycle-2-added comments
ai/services/graph/providerDispatch.spec.mjs: strip preamble JSDoc (keep test.describe label)
ai/services/memory-core/SessionService.buildChatModel.spec.mjs: strip preamble JSDoc (keep test.describe label)
Stage 4: Operator-facing documentation
Update learn/agentos/DeploymentCookbook.md §7 to document that ai/config.mjs is now auto-created on first install (operators can edit in place rather than create from scratch).
Acceptance Criteria
Out of Scope
- Pre-existing JSDoc archaeology in files I did not introduce this session (e.g., SessionService.mjs:539-540, :584, :676, :831, :854-856 — those are pre-#11966 anchors).
- Refactoring the AiConfig overlay-merge mechanism itself (it's already env-var-first per
feedback_neo_native_integration_check semantics).
- Other tickets' lanes.
Avoided Traps
- Do NOT replace ticket anchors with INTENT framing AND keep the ticket reference at the bottom. The memory says STOP authoring decay-prone anchors; partial deletion is incoherent.
- Do NOT touch pre-existing archaeology in scope of this fix — file separate tickets if operator wants a broader cleanup.
- Do NOT add
ai/config.mjs to git tracking; it's correctly gitignored per the existing operator-overlay model.
Related
- feedback_jsdoc_archaeology_self_audit — self-audit memory I violated mid-session
- #11967 (Sub-1 Tier-1 lift) — introduced the 2 new bad imports
- #11966 (Sub-2 Ollama wire-up cycle-3) — introduced the JSDoc archaeology
learn/agentos/DeploymentCookbook.md §7 — operator overlay model
Handoff Retrieval Hint: "post-#11967 config.template.mjs import anti-pattern + #11966 JSDoc archaeology cleanup".
Context
Operator-flagged regression surfaced after #11967 + #11966 + #11962 merged to dev. Two distinct substrate-quality bugs:
config.template.mjsimport anti-pattern in 7 runtime spots.#11967addedimport AiConfig from '../../../config.template.mjs'inai/mcp/server/memory-core/config.template.mjs+ai/mcp/server/knowledge-base/config.template.mjs. This compounded a pre-existing 5-spot legacy pattern inai/daemons/orchestrator/Orchestrator.mjs,ai/daemons/orchestrator/daemon.mjs,ai/daemons/orchestrator/services/TenantRepoSyncService.mjs,ai/scripts/maintenance/backup.mjs,ai/scripts/maintenance/defragChromaDB.mjs. Importing directly from the template bypasses the operator-overlayai/config.mjs(gitignored, perlearn/agentos/DeploymentCookbook.md§7), so operator customizations at the top-level Tier-1 config never reach runtime code.JSDoc ticket-archaeology violation of feedback_jsdoc_archaeology_self_audit.
#11966cycle-3 added decay-prone ticket/Epic/Discussion/OQ anchors in production-code JSDoc —ai/services/graph/providerDispatch.mjs, several inline comments inai/services/memory-core/TextEmbeddingService.mjs,ai/services/memory-core/SessionService.mjs(only the cycle-2 additions, not pre-existing comments). INTENT framing is what these files need; ticket anchors belong in PR body / commit message which decay-survive.The Problem
Sub-problem 1: config.template.mjs imports
Direct grep of dev HEAD:
All 7 should resolve through
ai/config.mjs(the operator-overlay), withai/scripts/setup/initServerConfigs.mjsextended to auto-createai/config.mjsfromai/config.template.mjson first install — same shape used today forai/mcp/server/*/config.mjs.Sub-problem 2: JSDoc archaeology I authored this session
Files where production JSDoc references decay-prone anchors (
#NNNN,Sub-N,OQM,Discussion #N,Closes #N AC<N>):ai/services/graph/providerDispatch.mjs(NEW in #11966 cycle-3) —@summary, body prose, "OQ2 disposition during Discussion #11961"ai/services/memory-core/TextEmbeddingService.mjslines49, 190, 207, 229, 247(cycle-2 additions)ai/services/memory-core/SessionService.mjslines19, 190, 546(cycle-2 additions only — pre-existing anchors at lines 539/584/676/831/854-856 are not in this ticket's scope)Test-file
test.describelabels are the documented exception (test-traceability boundary per the memory). But the multi-line JSDoc preamble blocks above thetest.describeare NOT labels — they're docblocks with archaeology:test/playwright/unit/ai/services/graph/providerDispatch.spec.mjsJSDoc preamble (lines 20-31, keep line 33test.describelabel)test/playwright/unit/ai/services/memory-core/SessionService.buildChatModel.spec.mjsJSDoc preamble (lines 20-30, keep line 31test.describelabel)The Architectural Reality
Primary surfaces:
ai/scripts/setup/initServerConfigs.mjs(extend to handleai/config.mjs)ai/config.mjs)learn/agentos/DeploymentCookbook.md§7 (document the new auto-create behavior)The auto-create mechanism already exists for MC/KB; this ticket extends it to the top-level Tier-1 config. Sub-problem 2 is mechanical doc-comment editing per the established memory rule.
The Fix
Stage 1: Auto-create
ai/config.mjsfromai/config.template.mjsExtend
initServerConfigs.mjsto handle the top-levelai/config.{mjs,template.mjs}pair using the same first-time-copy + drift-detection shape used forai/mcp/server/*. Addai/config.mjsto.gitignoreenforcement if not already covered (it is — line 105).Stage 2: Re-point 7 imports
Update all 7 files to import from
ai/config.mjsinstead ofai/config.template.mjs. Maintain relative-path semantics:ai/daemons/orchestrator/daemon.mjs:'../../config.mjs'ai/daemons/orchestrator/Orchestrator.mjs:'../../config.mjs'ai/daemons/orchestrator/services/TenantRepoSyncService.mjs:'../../../config.mjs'ai/mcp/server/memory-core/config.template.mjs:'../../../config.mjs'ai/mcp/server/knowledge-base/config.template.mjs:'../../../config.mjs'ai/scripts/maintenance/backup.mjs:'../../config.mjs'ai/scripts/maintenance/defragChromaDB.mjs:'../../config.mjs'Note: changing the MC/KB template files' imports also propagates to the auto-generated MC/KB config.mjs files on the next
npm run prepare -- --migrate-configinvocation.Stage 3: Strip JSDoc ticket-archaeology from this-session production code
Targets (this-session-only — pre-existing archaeology is out of scope):
ai/services/graph/providerDispatch.mjs: replace ticket-anchored@summarywith INTENT framing; strip "Closes #11965 AC5 ...", "OQ2 disposition during Discussion #11961"ai/services/memory-core/TextEmbeddingService.mjs: strip#11965 Sub-2 cycle-2markers in inline comments at the listed line numbersai/services/memory-core/SessionService.mjs: strip#11965 Sub-2 cycle-2markers in the 3 listed cycle-2-added commentsai/services/graph/providerDispatch.spec.mjs: strip preamble JSDoc (keep test.describe label)ai/services/memory-core/SessionService.buildChatModel.spec.mjs: strip preamble JSDoc (keep test.describe label)Stage 4: Operator-facing documentation
Update
learn/agentos/DeploymentCookbook.md§7 to document thatai/config.mjsis now auto-created on first install (operators can edit in place rather than create from scratch).Acceptance Criteria
npm run prepareon a fresh clone createsai/config.mjsfromai/config.template.mjsif missing.npm run prepare -- --migrate-configoverwritesai/config.mjsfrom the template (matching MC/KB behavior).grep -rn "from.*config\.template\.mjs" ai/ --include="*.mjs"returns ZERO matches outside ofai/config.template.mjsitself andai/scripts/setup/initServerConfigs.mjs(which legitimately references the template path string).test.describelabels with ticket anchors are kept; only the multi-line JSDoc preambles above them are stripped.npm run test-unit -- test/playwright/unit/ai/runs clean (no regressions from the import re-pointing).Out of Scope
feedback_neo_native_integration_checksemantics).Avoided Traps
ai/config.mjsto git tracking; it's correctly gitignored per the existing operator-overlay model.Related
learn/agentos/DeploymentCookbook.md§7 — operator overlay modelHandoff Retrieval Hint: "post-#11967 config.template.mjs import anti-pattern + #11966 JSDoc archaeology cleanup".