LearnNewsExamplesServices
Frontmatter
id12051
titlebootstrapWorktree: hydrate Tier-1 + materialize per-server configs (Discussion #12049)
stateClosed
labels
bugaiarchitecture
assigneesneo-gpt
createdAtMay 26, 2026, 11:11 PM
updatedAtJun 7, 2026, 7:16 PM
githubUrlhttps://github.com/neomjs/neo/issues/12051
authorneo-opus-ada
commentsCount1
parentIssuenull
subIssues[]
subIssuesCompleted0
subIssuesTotal0
blockedBy[]
blocking[]
closedAtMay 27, 2026, 12:41 AM

bootstrapWorktree: hydrate Tier-1 + materialize per-server configs (Discussion #12049)

Closed v13.0.0/archive-v13-0-0-chunk-14 bugaiarchitecture
neo-opus-ada
neo-opus-ada commented on May 26, 2026, 11:11 PM

Context

Graduated from Discussion #12049 ("Worktree config-substrate workflow: operator-edit propagation vs fresh-materialized configs") with cross-family [GRADUATION_APPROVED by @neo-gpt @ Discussion #12049 body updated 2026-05-26T20:53:08Z]. C-lite convergent shape — see Discussion body for §5.1 Double Diamond matrix, §5.1.1 Reflective Pause documentation, and OQ1-5 resolutions.

The Problem

ai/scripts/migrations/bootstrapWorktree.mjs copies the canonical checkout's per-server ai/mcp/server/*/config.mjs files verbatim into the worktree via fs.copyFile. Two gaps:

  1. No materialize-on-copy: if canonical's per-server config.mjs was generated before materializeServerConfigTemplate() landed (or --migrate-config was never re-run), the un-materialized state propagates into every worktree. The transitive ai/services.mjs import then loads ai/config.template.mjs instead of the operator overlay, double-registering Neo.ai.Config under unitTestMode (empirical anchor: PR #12044 cycle-2 → cycle-2.1).
  2. Tier-1 ai/config.mjs not in BOOTSTRAP_CONFIGS: once materialized, per-server config.mjs imports point at '../../../config.mjs' (operator overlay); if Tier-1 isn't also bootstrapped, the chain breaks in the worktree.

The Architectural Reality

The Fix

C-lite shape per Discussion #12049 convergence:

  1. Add 'ai/config.mjs' to BOOTSTRAP_CONFIGS so Tier-1 is copied alongside the four per-server configs.
  2. After fs.copyFile, apply materializeServerConfigTemplate() (imported from initServerConfigs.mjs) to each copied per-server config.mjs so the AiConfig import is rewritten from ../../../config.template.mjs../../../config.mjs when needed. The function is idempotent — already-materialized files are unchanged.
  3. Operator-edit propagation semantic stays intact: worktree gets canonical's tenantRepos[] and other operator edits exactly as before; only the import-path layer gets normalized.
  4. DO NOT duplicate materializeServerConfigTemplate in bootstrapWorktree.mjs — import from initServerConfigs.mjs (single source of truth for the rewrite logic).

Decision Record impact

aligned-with ADR 0014 — narrow bootstrap-script behavior change within existing topology.

Contract Ledger

Backfilled post-filing per @neo-gpt's intake-blocker on this ticketticket-create-workflow.md §5 + learn/agentos/contract-ledger.md require a formal Contract Ledger matrix for any ticket modifying an agent-consumed bootstrap surface. Matrix structure follows @neo-gpt's suggested rows verbatim:

Target Surface Source of Authority Proposed Behavior Fallback / Edge Case Docs Evidence
BOOTSTRAP_CONFIGS (the array at bootstrapWorktree.mjs:113-118) Discussion #12049 C-lite scope; this ticket #12051 Includes top-level ai/config.mjs plus the four existing per-server ai/mcp/server/<name>/config.mjs paths Existing destination configs stay skipped/preserved per current idempotence semantics (bootstrapWorktree.mjs:226-253 fs.copyFile short-circuit on already-existing target) bootstrapWorktree.mjs JSDoc updated to describe Tier-1 inclusion Unit test proves copied Tier-1 ai/config.mjs exists in the fake worktree post-bootstrap
Per-server config copy path in bootstrapWorktree() (copy loop at lines 226-253) initServerConfigs.mjs#materializeServerConfigTemplate() (single source of truth — imported, not duplicated) After fs.copyFile, materialize stale ../../../config.template.mjs AiConfig imports to ../../../config.mjs Already-materialized configs remain unchanged (function is idempotent); missing source configs retain current skip behavior bootstrapWorktree.mjs JSDoc updated to describe materialize-on-copy semantic Unit test proves no copied per-server config retains ../../../config.template.mjs AiConfig import
Operator-edit propagation Discussion #12049 OQ1 resolution (C-lite preserves current operator-edit propagation semantic) Preserve canonical operator edits (tenantRepos[], custom config keys, etc.) exactly — the only transformation is the AiConfig import-path normalization on per-server configs Existing destination configs remain untouched (idempotence preserved) JSDoc only — no operator-facing behavior change worth surfacing in learn/agentos/cloud-deployment/ Unit test proves non-import content (custom keys, tenantRepos[] arrays, comments) survives the copy + materialization step verbatim
Non-overlap with #11976 (direct test-file imports) + #12047 (canonical-checkout materialization-migration) Discussion #12049 OQ5 + this ticket's ## Out of Scope section This ticket/PR does NOT change direct test-file import behavior (#11976's surface) and does NOT add the canonical-checkout migration tooling (#12047's surface) #11976 + #12047 surfaces remain owned by their respective tickets — orthogonal layers PR body cross-links to #11976 + #12047; explicit AC enforces the non-overlap PR body audits + tests scope-limited to bootstrapWorktree.mjs + a focused test fixture; neither modifies test-import-path conventions nor adds migration commands

Acceptance Criteria

  • BOOTSTRAP_CONFIGS covers top-level 'ai/config.mjs' plus the four existing per-server config.mjs paths.
  • When copying a per-server config.mjs from canonical, bootstrap applies materializeServerConfigTemplate() (imported from initServerConfigs.mjs) to rewrite any stale ../../../config.template.mjs AiConfig import to ../../../config.mjs.
  • Operator edits in canonical config files are otherwise preserved (operator-edit propagation semantic intact).
  • Unit coverage proves a fake canonical checkout with stale per-server template imports produces a worktree with:
    • copied ai/config.mjs;
    • per-server config imports rewritten to ../../../config.mjs;
    • no remaining ../../../config.template.mjs AiConfig import in copied per-server configs;
    • existing destination configs still skipped/preserved per current idempotence semantics.
  • Explicit cross-substrate constraint: this ticket/PR does NOT close, reshape, or auto-merge with #11976. #11976's test-fixture-pattern surface remains independent.
  • Docs scope (per @neo-gpt's graduation polish): update bootstrapWorktree.mjs JSDoc to describe the materialize-on-copy + Tier-1 behavior. Touch cloud-deployment docs only if the implementation surfaces operator-facing behavior changes (which C-lite shouldn't).

Out of Scope

  • Option A (delegate to initServerConfigs / fresh-materialized worktree semantic): explicitly deferred to a future Discussion if anyone wants to pursue the workflow-semantic change. Per Discussion #12049 classification challenge, that would be high-blast and require the §5.2 step-back sweep — orthogonal to this bounded fix.
  • The materialization-migration concern for existing canonical checkouts (covered by #12047).
  • Direct test-file imports of config.mjs (covered by #11976); see Discussion #12049 OQ5 for the explicit non-overlap constraint.

Avoided Traps

  • Pure Option B (materialize-on-copy without Tier-1): surfaced by @neo-gpt's peer-role as under-specified — materialized per-server imports require Tier-1 to exist in the worktree. C-lite includes both.
  • Duplicating the materialize function: would create substrate drift if the rewrite logic changes later. Import from the canonical owner (initServerConfigs.mjs) instead.

Related

  • Graduates from Discussion #12049 (full design history + matrix + OQ resolutions).
  • Empirical anchor: PR #12044 cycle-2 → cycle-2.1 (the materialization gap surfaced).
  • Sibling substrate concerns (orthogonal layers): #12047 (materialization-migration for existing checkouts), #11976 (direct test-file imports).
  • Closed predecessor (wrong-shape ticket): #12048.
  • Empirical session: first real-world cloud Agent OS deployment, 2026-05-26.
tobiu referenced in commit b9b96ad - "fix(orchestrator): wire NEO_TENANT_REPO_MIRROR_ROOT to Tier-1 mirrorRoot fallback (#12036) (#12050) on May 26, 2026, 11:44 PM
tobiu referenced in commit eb0c444 - "fix(worktree): materialize copied config overlays (#12051) (#12054) on May 27, 2026, 12:41 AM
tobiu closed this issue on May 27, 2026, 12:41 AM