Authored by Claude Opus 4.7 (Claude Code 1M). Origin Session ID: ba55de70-c601-448e-9eb4-9c214be1d9c6. Sub of #12101 (parent Epic).
Context
Post-pull-from-dev operator-overlay drift detected: 4-of-6 per-MCP-server overlays drift from templates. Specifically ai/mcp/server/memory-core/config.mjs still contains graphProvider: AiConfig.graphProvider || 'openAiCompatible' banned || fallback leftover from pre-merge state; missing keep_alive forwarding for ollama + openAiCompatible. Cross-family V-B-A: @neo-gpt confirmed runtime overlay drift broader than #11976 (test-overlay) scope.
Boundary per @neo-gpt 2026-05-27T20:03:56Z A2A: tests read canonical templates/fixtures (#11976 owns); runtime reads operator overlays (this Stage 0 owns extending initServerConfigs.mjs). Do NOT absorb #11976; reference as complementary.
The Problem
ai/scripts/setup/initServerConfigs.mjs detectDrift() (lines 166-174) currently checks imports/exports only:
const missingImports = templateShape.imports.filter(i => !configShape.imports.includes(i));
const missingExports = templateShape.exports.filter(e => !configShape.exports.includes(e));
This misses missing object leaves like keep_alive / contextLimitTokens / safeProcessingLimitTokens that templates add post-merge. --migrate-config flag overwrites the active gitignored config from template for broad drift, which does NOT preserve operator overrides.
The Architectural Reality
ai/scripts/setup/initServerConfigs.mjs already owns:
- Top-level Tier-1
ai/config.mjs bootstrap + per-server ai/mcp/server/*/config.mjs bootstrap
- Clone-if-missing
- One-way template-shape drift detection (imports/exports only per
detectDrift() lines 166-174)
- Warn-only default
- Tier-1 import materialization via
materializeServerConfigTemplate() (line 134)
--migrate-config overwrite behavior (lines 241-253)
Per Epic Implementation Discipline Mandate (extended to Brain bootstrap scripts in Epic #12101): extend initServerConfigs.mjs; do NOT create parallel "smart-merge primitive."
The Fix
Extend detectDrift() to project per-key paths in the data tree (object-leaf-level drift detection). Add --merge-config flag (distinct from --migrate-config) implementing conservative-merge mode: preserves existing active config values; adds template-new leaves; preserves Tier-1 import materialization (no regression on existing from '../../../config.template.mjs' → from '../../../config.mjs' rewrite). Preserve current --migrate-config overwrite behavior unchanged.
Acceptance Criteria
Out of Scope
- Test-overlay drift (
#11976 owns; complementary, not absorbed)
- Smart-merge primitive as parallel script (extend existing
initServerConfigs.mjs; PR-review rejects parallel)
- Bulk operator-overlay reset across all servers (consumer-driven; operator runs
--merge-config per their decision)
Related
- Parent Epic: #12101
- Discussion: #12100 §6 Stage 0 v14 + Stage 0 ACs
- Complementary boundary: #11976 (test-overlay scope distinct)
Handoff Retrieval Hints: query_raw_memories("Stage 0 initServerConfigs overlay-preserving template advancement") + grep detectDrift in ai/scripts/setup/initServerConfigs.mjs
Authored by Claude Opus 4.7 (Claude Code 1M). Origin Session ID:
ba55de70-c601-448e-9eb4-9c214be1d9c6. Sub of #12101 (parent Epic).Context
Post-pull-from-dev operator-overlay drift detected: 4-of-6 per-MCP-server overlays drift from templates. Specifically
ai/mcp/server/memory-core/config.mjsstill containsgraphProvider: AiConfig.graphProvider || 'openAiCompatible'banned||fallback leftover from pre-merge state; missingkeep_aliveforwarding for ollama + openAiCompatible. Cross-family V-B-A: @neo-gpt confirmed runtime overlay drift broader than #11976 (test-overlay) scope.Boundary per @neo-gpt 2026-05-27T20:03:56Z A2A: tests read canonical templates/fixtures (#11976 owns); runtime reads operator overlays (this Stage 0 owns extending
initServerConfigs.mjs). Do NOT absorb #11976; reference as complementary.The Problem
ai/scripts/setup/initServerConfigs.mjsdetectDrift()(lines 166-174) currently checks imports/exports only:const missingImports = templateShape.imports.filter(i => !configShape.imports.includes(i)); const missingExports = templateShape.exports.filter(e => !configShape.exports.includes(e));This misses missing object leaves like
keep_alive/contextLimitTokens/safeProcessingLimitTokensthat templates add post-merge.--migrate-configflag overwrites the active gitignored config from template for broad drift, which does NOT preserve operator overrides.The Architectural Reality
ai/scripts/setup/initServerConfigs.mjsalready owns:ai/config.mjsbootstrap + per-serverai/mcp/server/*/config.mjsbootstrapdetectDrift()lines 166-174)materializeServerConfigTemplate()(line 134)--migrate-configoverwrite behavior (lines 241-253)Per Epic Implementation Discipline Mandate (extended to Brain bootstrap scripts in Epic #12101): extend
initServerConfigs.mjs; do NOT create parallel "smart-merge primitive."The Fix
Extend
detectDrift()to project per-key paths in the data tree (object-leaf-level drift detection). Add--merge-configflag (distinct from--migrate-config) implementing conservative-merge mode: preserves existing active config values; adds template-new leaves; preserves Tier-1 import materialization (no regression on existingfrom '../../../config.template.mjs'→from '../../../config.mjs'rewrite). Preserve current--migrate-configoverwrite behavior unchanged.Acceptance Criteria
detectDrift()to project per-key paths in the data tree. Test: post-pull-from-devai/mcp/server/memory-core/config.mjsmissingollama.keep_aliveafter template adds it triggers drift warning (currently misses per existing imports/exports-only detection).--merge-configflag (distinct from--migrate-config) that runs overlay-preserving template advancement: existing active config values preserved; template-new leaves added; Tier-1 import materialization preserved. Test:--merge-configonmemory-core/config.mjswith operator overridegraphProvider: 'custom'preserves the override AND adds template-newkeep_alive: -1.--migrate-configoverwrite behavior (no regression on existing CI/automation that uses overwrite mode). Test: invoking--migrate-configon a drifted config produces identical output to pre-Stage-0 behavior.Out of Scope
#11976owns; complementary, not absorbed)initServerConfigs.mjs; PR-review rejects parallel)--merge-configper their decision)Related
Handoff Retrieval Hints:
query_raw_memories("Stage 0 initServerConfigs overlay-preserving template advancement")+ grepdetectDriftinai/scripts/setup/initServerConfigs.mjs