---
id: 11831
title: 'Orchestrator.mjs masterclass-reference: 4-way Service-DI classification + Neo.util.Env substrate + 2-value chain'
state: CLOSED
labels:
  - enhancement
  - epic
  - ai
  - refactoring
  - architecture
  - model-experience
assignees:
  - neo-opus-ada
createdAt: '2026-05-23T11:20:38Z'
updatedAt: '2026-06-07T17:14:45Z'
githubUrl: 'https://github.com/neomjs/neo/issues/11831'
author: neo-opus-ada
commentsCount: 5
parentIssue: null
subIssues:
  - '[x] 11832 Sub 6: Neo.util.Env THIN substrate primitive (lift EnvConfig.mjs parsers to src/util/Env.mjs)'
  - '[x] 11833 Sub 1: Orchestrator masterclass-reference refactor (4-way Service-DI + 2-value chain + configure() removal)'
  - '[x] 11834 Sub 2: Orchestrator test-fixture + invariant coverage for new config substrate'
  - '[x] 11835 Sub 3: Removal of DEFAULT_* constants + parser surfaces made obsolete by Orchestrator refactor'
  - '[x] 11836 Sub 4: Sibling daemon propagation of masterclass-reference pattern (5-6 daemon files)'
  - '[x] 11837 Sub 5: External-user configurability audit (forks, npx neo-app workspaces, non-Neo-team clients)'
  - '[x] 11840 Sub 7: Bump swarmHeartbeatMs wake interval 5m → 15m'
  - '[x] 11844 Sub 8: Orchestrator-cluster co-location (ai/daemons/orchestrator/) + daemon.mjs naming + test mirror + package.json'
  - '[x] 11845 Sub 9: Sub-daemon cluster co-location (bridge + kb-alerting + kb-gc + kb-reconciliation) with daemon.mjs naming'
  - '[x] 11846 Sub 10: Cross-daemon services bucket (ai/services/graph/ + ai/services/ingestion/)'
  - '[x] 11847 Sub 11: ai/scripts/ thematic split (lifecycle/maintenance/migrations/diagnostics/runners/setup/lint)'
  - '[x] 11848 Sub 12: Collapse buildScripts/ai/ into ai/scripts/{maintenance,migrations,diagnostics,runners,setup}/'
  - '[x] 11854 Sub 13: Collapse over-engineered Orchestrator Service-DI (Class C field deletion + historical-context comment strip)'
  - '[x] 11855 Sub 14: Centralize env-binding registry — ai/config/env.mjs + dotenv lift'
  - '[x] 11858 Sub 15: Extract DreamCoordinatorService — getDueTask only, due-trigger selection only'
  - '[x] 11859 Sub 16: Extract SwarmHeartbeatCoordinatorService — getDueTask only, initAsync stays in service'
  - '[x] 11860 Sub 17: Extract GoldenPathCoordinatorService — due/dependency trigger only, synthesizer stays as execution service'
  - '[x] 11861 Sub 19: Extract MaintenanceBackpressureService — heavy/golden predicates + deferral recording + lease/dependency executor wrappers (B-prime)'
  - '[x] 11862 Sub 18: Orchestrator generic registry wire-up + CadenceEngine pure-trigger-builder correction + collector/pickNextCandidate (Round-2 closer)'
  - "[x] 11864 Sub 20: Harmonize existing Coordinator services to scheduling/<task>.mjs pure-function pattern\_ \_"
  - '[x] 12130 IssueIngestor community-multiplier hardcodes operator login ''tobiu'''
subIssuesCompleted: 21
subIssuesTotal: 21
blockedBy: []
blocking: []
closedAt: '2026-06-07T08:17:13Z'
---
# Orchestrator.mjs masterclass-reference: 4-way Service-DI classification + Neo.util.Env substrate + 2-value chain

## Epic Origin

Graduated from Discussion #11828 (Cycle-3.3 `[GRADUATION_APPROVED by @neo-gpt @ DC_kwDODSospM4BA-Ic]` at body anchor `2026-05-23T10:58:31Z`).

Originating empirical anchor: operator-triggered substrate-quality crisis 2026-05-23. Operator framing: *"current version: not maintainable, bloats your context window... this is the worst code i have seen in over a year. junior cowboy coding SHIT. quality scale 1 to 100 => a 5. neo standards is 90+. let us turn the orchestrator into a masterclass elegant solution."* PR #11825 closed Drop+Supersede; #11827 captured only ~5% of the actual anti-pattern stack.

## Concept

Redesign `ai/daemons/Orchestrator.mjs` as a **masterclass-reference implementation** of the Neo daemon config substrate. Eliminates the layered anti-pattern stack (~30 cargo-cult reactive configs, `configure()` shadow-resolver, 6-value fallback chains, `DEFAULT_X` constants in `TaskDefinitions.mjs`, domain-class env-parser ownership). Then propagate the pattern to ~6+ sibling daemon files.

## Tier classification

**Tier-2** (substrate-architecture, touches `core/Base.mjs` consumption pattern + propagation to ~6+ daemon files + sets cross-substrate config contract).

## Acceptance Criteria

1. **AC1 — No cargo-cult `_`-suffix configs:** `Orchestrator.mjs` has no `_`-suffix reactive config unless the PR introduces real `beforeGet*` / `beforeSet*` / `afterSet*` hook for that property. Legitimate reactive collaborators (e.g., `cadenceEngine_`) keep `_`-suffix with hooks + `ClassSystemUtil.beforeSetInstance(value, DefaultClass, defaults)` — DefaultClass passed DIRECTLY as 2nd arg (NOT via `{module: DefaultClass}` config). NO `beforeGet*` + NO manual backing assignment; reactive setter handles defaulting naturally.
2. **AC2 — 2-value policy chain:** Operator-tunable daemon values resolve through exactly two policy sources: canonical env var OR `AiConfig`. No `options.X`, no `DEFAULT_X` constant fallback, no env-alias chain.
3. **AC3 — Explicit env decoding:** Env decoding handles unset, empty string, zero, invalid numeric values, and boolean false explicitly. Invalid env operator-visible (warn-and-undefined per `Neo.util.Env` semantics).
4. **AC4 — 4-way Service-DI classification:** (A) class-system-managed utility collaborators with hooks + ClassSystemUtil; (B) parent-configured child collaborators with creation hooks + parent `afterSet*` propagation hooks (covers `processSupervisorService_`; explicit removal of `processSupervisorService.set({...this...})` context-replay block in `start()`); (C) simple direct-import instance-fields ONLY when no class-system conversion / no parent-child propagation / no lifecycle side effect; (D) operator policy values via lazy getter + 2-value chain. Mis-classification = Tier-2 revalidation trigger. Logger function passed to child services must be a stable function seam (not per-call `.bind(this)` allocation).
5. **AC5 — `configure()` removed:** REMOVED as runtime-policy resolver. `start(options)` may keep narrow boot-wrapper seams for paths/process/test harnesses, but not as a second default system for intervals/toggles/services.
6. **AC6 — Thin daemon wrapper:** `orchestrator-daemon.mjs` remains a thin process wrapper (PID, cleanup, local config loading, start invocation). NOT new policy-translation dumping ground.
7. **AC7 — Test coverage of real surfaces:** Unit tests prove config precedence through real surfaces: env over AiConfig, gitignored config mutation via `AiConfig.data`, service override by instance field, singleton leak prevention, source-level invariants for removed anti-patterns. Tests must prove parent-config mutations on `Orchestrator` propagate to `ProcessSupervisorService` via `afterSet*` hooks (NOT via `start()` context replay).
8. **AC8 — Tier-2 liveness + revalidationTrigger:** Gemini benched on this convergence pass → Epic carries `## Unresolved Liveness` + `revalidationTrigger` AC. Revalidation triggers if implementation chooses eager snapshotting / keeps `configure()` as policy resolver / reintroduces env aliases / adds shared helper that knows fallback policy / places env-parser on a domain class.
9. **AC9 — `Neo.util.Env` substrate primitive:** Lives at `src/util/Env.mjs`, mirrors `Neo.util.String` static-class precedent. API: `parseNumber`, `parseBool`, `parsePort`, `parseUrl`, `parseString`, `applyEnvBindings`, `setDeep`. **Availability:** added to `src/util/_export.mjs` barrel AND consumers use direct `import Env from '<path>/src/util/Env.mjs'`. **Boolean compatibility:** `parseBool` MUST preserve `PrimaryRepoSyncService.parseEnabledFlag` token semantics (`'0'`, `'false'`, `'no'`, `'off'` → false) OR Epic explicitly declares hard-cut behavior change with tests + env-var migration notes. All env-parser surfaces at lower tiers (`EnvConfig.mjs`, `CadenceEngine.parseInterval`, `PrimaryRepoSyncService.parseEnabledFlag`) retire or rewire through `Neo.util.Env`. No env-parser methods on domain classes. Test surface: `test/playwright/unit/util/Env.spec.mjs`.

## Sub-decomposition (6 subs)

Sub 6 is the substrate-prerequisite; Sub 1 depends on Sub 6; Subs 2-5 parallel after Sub 1.

1. **Orchestrator masterclass-reference refactor** — primary lane; DEPENDS ON Sub 6.
2. **Test-fixture + invariant coverage** for the new config substrate.
3. **Removal/narrowing of `DEFAULT_*` / parser surfaces** (subsumes #11827).
4. **Sibling daemon propagation** (`SwarmHeartbeatService`, `KbAlertingService`, `KbReconciliationService`, `KbGarbageCollectionService`, `GapInferenceEngine`).
5. **External-user configurability audit** — forks, `npx neo-app` workspaces, non-Neo-team clients.
6. **`Neo.util.Env` THIN substrate primitive** — create + register + Orchestrator-needed parser surface + `EnvConfig.mjs` consumer rewire + test surface. Full 61-file consumer migration decomposes into Sub 6a/6b/6c follow-up tickets.

## Avoided Traps

- Defense-in-depth fallback layers (2 values max per operator).
- Keeping `_`-suffix configs for "future hooks" (YAGNI; cargo-cult).
- Treating `configure()` as a Neo-class idiom (it isn't).
- Placing env-parser methods on domain classes (Cycle-3 anti-pattern; Tier-1 Neo substrate is the correct landing).
- Making the full 61-file env-var migration a Sub-1 prerequisite (Sub 6 stays THIN).
- Manual backing-assignment + `beforeGet*` defaulting for reactive configs (Cycle-3.2 lesson; reactive setter handles defaulting through `ClassSystemUtil.beforeSetInstance` directly).
- Citing non-existent import paths in body authority snippets (Cycle-3.3 lesson; V-B-A import paths against actual file tree before body-finalization).

## Unresolved Liveness

- `gemini` (`@neo-gemini-pro`): `participationStatus: operator_benched since 2026-05-18T00:00:00.000Z`. `reactivationTrigger` per `ai/graph/identityRoots.mjs`. STATUS: pending Gemini reactivation; Epic carries `revalidationTrigger` AC per §6.2(c) Tier-2 requirement (AC8 explicitly). Sub #11803 mechanism (`npm run ai:revalidation-sweep -- --family gemini`) notifies Gemini at reactivation.

## Related substrate anchors

- Originating Discussion: #11828 (Cycle-3.3 `[GRADUATION_APPROVED]` at body `updatedAt 2026-05-23T10:58:31Z`)
- `src/core/Base.mjs:64-93` — reactive vs non-reactive config primitive documentation
- `src/util/ClassSystem.mjs:23-60` — `beforeSetInstance(value, DefaultClass, defaults)` API (V-B-A: file exists; sibling consumers `Breadcrumb.mjs:1`, `Loop.mjs:3`, `Database.mjs:2`)
- `src/util/String.mjs` — substrate-utility static-class precedent for `Neo.util.Env`
- `src/toolbar/Breadcrumb.mjs:38-126` — `store_` reactive-config-with-hooks precedent (Service-DI Class A)
- `src/grid/Container.mjs:520-540` — parent-store-propagation precedent (Service-DI Class B)
- `ai/config.template.mjs` — canonical defaults substrate
- `ai/mcp/server/shared/helpers/EnvConfig.mjs` — 95% correct env-parser surface at wrong (T2) tier; lifts to `Neo.util.Env`
- `ai/daemons/services/CadenceEngine.mjs` / `ProcessSupervisorService.mjs` — `singleton: true` examples (named-class import required for ClassSystemUtil)
- #11825 — closed Drop+Supersede (~5% capture)
- #11827 — narrow audit-record (subsumed by Sub 3)
- #11075 — original "exploration: migrate orchestrator magic numbers" ticket

## Discussion Cycle History (compressed)

- Cycle-1: original 5-layer proposal
- Cycle-2 `[GRADUATION_APPROVED]` (superseded): env-decoder substrate correction per GPT `node -e` falsification — `Number(undefined) === NaN`, `NaN ?? fallback === NaN`
- Cycle-2.5: CadenceEngine reactive correction per @tobiu — class-system-managed collaborator with hooks
- Cycle-3 (STRONG VETO from @tobiu): env-parser primitive lifted Tier-3 → Tier-1 (`Neo.util.Env`); Epic 5→6 subs
- Cycle-3.1: 8 body-anchor fixups per GPT
- Cycle-3.2: CadenceEngine direct-class-arg pattern
- Cycle-3.3 `[GRADUATION_APPROVED]`: 3 narrow snippet-authority fixes (import path, semantics callout, ProcessSupervisorService symmetric correction)

**Authored by:** [Claude Opus 4.7] (Claude Code)

## Timeline

- 2026-05-23T11:20:39Z @neo-opus-ada assigned to @neo-opus-ada
- 2026-05-23T11:20:40Z @neo-opus-ada added the `enhancement` label
- 2026-05-23T11:20:40Z @neo-opus-ada added the `epic` label
- 2026-05-23T11:20:40Z @neo-opus-ada added the `ai` label
- 2026-05-23T11:20:40Z @neo-opus-ada added the `refactoring` label
- 2026-05-23T11:20:40Z @neo-opus-ada added the `architecture` label
- 2026-05-23T11:20:40Z @neo-opus-ada added the `model-experience` label
- 2026-05-23T11:21:24Z @neo-opus-ada cross-referenced by #11832
- 2026-05-23T11:21:48Z @neo-opus-ada cross-referenced by #11833
- 2026-05-23T11:21:55Z @neo-opus-ada cross-referenced by #11834
- 2026-05-23T11:22:07Z @neo-opus-ada cross-referenced by #11835
- 2026-05-23T11:22:18Z @neo-opus-ada cross-referenced by #11836
- 2026-05-23T11:22:32Z @neo-opus-ada cross-referenced by #11837
- 2026-05-23T11:22:55Z @neo-opus-ada added sub-issue #11832
- 2026-05-23T11:22:59Z @neo-opus-ada added sub-issue #11833
- 2026-05-23T11:23:07Z @neo-opus-ada added sub-issue #11834
- 2026-05-23T11:23:12Z @neo-opus-ada added sub-issue #11835
- 2026-05-23T11:23:31Z @neo-opus-ada added sub-issue #11836
- 2026-05-23T11:23:37Z @neo-opus-ada added sub-issue #11837
- 2026-05-23T12:13:57Z @neo-gpt cross-referenced by PR #11838
- 2026-05-23T12:14:16Z @neo-opus-ada cross-referenced by #11840
- 2026-05-23T12:14:29Z @neo-opus-ada added sub-issue #11840
- 2026-05-23T13:03:13Z @neo-opus-ada cross-referenced by PR #11842
- 2026-05-23T13:10:37Z @tobiu referenced in commit `27f7a65` - "refactor(agentos): Orchestrator masterclass-reference (4-way Service-DI + Neo.util.Env + configure() removal) (#11833) (#11842)

Sub 1 of Epic #11831. Refactors ai/daemons/Orchestrator.mjs from 1046 lines
to 760 lines via the 4-way Service-DI classification + 2-value chain pattern
graduated from Discussion #11828.

Architecture changes:
- 30+ cargo-cult `_`-suffix configs replaced with lazy getters (Class D):
  `Env.parseNumber(process.env.X, 'X') ?? AiConfig.orchestrator.intervals.X`
  for 8 interval values, `Env.parseBool(...) ?? resolveDeploymentEnabled(...)`
  for 5 boolean values. No setter overhead, no DEFAULT_X constants, no
  per-property fallback chain.
- cadenceEngine_ (Class A) becomes proper class-system-managed reactive
  collaborator with `beforeSet` + ClassSystemUtil.beforeSetInstance for
  polymorphic class/instance/config-object input.
- processSupervisorService_ (Class B) becomes parent-configured child
  collaborator with `beforeSet` creation from parent state + parent
  afterSet* propagation hooks for dataDir / taskDefinitions / taskStateService
  / healthService / spawnFn. Stable processSupervisorWriteLog seam avoids
  per-call .bind() allocation. start() no longer replays parent config
  imperatively via processSupervisorService.set({...this...}).
- Simple service singletons become Class C instance fields (direct import,
  no reactive config slot).
- configure() shadow-resolver REMOVED entirely (was duplicating
  initConfig's work and shadowing AiConfig precedence).

Substrate dependency removals:
- CadenceEngine + ProcessSupervisorService no longer `singleton: true`
  (per @tobiu: "if a class needs external configs, it should not be a
  singleton in the first place"). Each Orchestrator instance now constructs
  its own collaborator instances via ClassSystemUtil.
- DEFAULT_*_INTERVAL_MS constants (8) removed from TaskDefinitions.mjs;
  canonical defaults live in ai/config.template.mjs:79-88 orchestrator.intervals.
- DEFAULT_*_INTERVAL_MS re-exports removed from orchestrator-daemon.mjs.

Test refactor:
- createTestOrchestrator() helper migrated to AiConfig.data mutation +
  afterEach restore for Class D operator policy values (lazy getters not
  reachable via Neo.create initConfig). Simple service mocks assigned
  directly as instance fields after Neo.create.
- 3 configure()-based path/mlx tests migrated to instance-field-assignment +
  direct buildTaskDefinitions calls (substrate-correct shape without
  side-effecting start()).
- CadenceEngine.spec.mjs migrated to per-test instance via Neo.create
  (parseInterval queued for removal by Sub 3 #11835).

Tests: 69/69 pass (1.6s) across 6 affected spec files: Orchestrator.spec.mjs
(26), ProcessSupervisorService.spec.mjs (13), CadenceEngine.spec.mjs (5),
orchestrator-daemon.spec.mjs (10), config.template.spec.mjs (3), Env.spec.mjs
(20 from Sub 6 #11832).

File-size delta: Orchestrator.mjs 1046 → 760 lines (-286 / -27%). Net
project delta: +349 / -416 = -67 lines across 8 files.

Graduates from Discussion #11828 (Cycle-3.3 GRADUATION_APPROVED at body
anchor 2026-05-23T10:58:31Z by @neo-gpt @ DC_kwDODSospM4BA-Ic).

Co-authored-by: tobiu <tobiasuhlig78@gmail.com>"
- 2026-05-23T13:16:47Z @neo-opus-ada cross-referenced by PR #11843
- 2026-05-23T13:28:43Z @tobiu referenced in commit `7e7adb2` - "refactor(agentos): delete obsolete CadenceEngine.parseInterval + PrimaryRepoSyncService.parseEnabledFlag (#11835) (#11843)

* refactor(agentos): delete obsolete CadenceEngine.parseInterval + PrimaryRepoSyncService.parseEnabledFlag (#11835)

Sub 3 of Epic #11831. Removes two parser surfaces whose sole runtime consumer
(Orchestrator) was rewired in Sub 1 (#11833) to use Neo.util.Env from Sub 6
(#11832). Both functions had zero remaining non-test consumers per grep.

Removed:
- CadenceEngine.parseInterval() — Orchestrator now uses
  Env.parseNumber(process.env.X, 'X') ?? AiConfig.X via lazy getters.
  Math.max(0, n) clamp re-applied at caller if non-negative semantics needed
  (Orchestrator does not — intervals already validated by AiConfig schema).
- PrimaryRepoSyncService.parseEnabledFlag() — Orchestrator now uses
  Env.parseBool(process.env.X, 'X') ?? resolveDeploymentEnabled('X')
  via lazy getters. Env.parseBool preserves the legacy false tokens
  ('0', 'false', 'no', 'off') per Sub 6 (#11832) AC9 boolean compatibility,
  so the runtime behavior is unchanged.

Test surface migration:
- CadenceEngine.spec.mjs — 3 parseInterval tests removed (coverage lives in
  test/playwright/unit/util/Env.spec.mjs ?? fallback + boolean tests).
- PrimaryRepoSyncService.spec.mjs — parseEnabledFlag import + 4 inline
  assertions removed; the existing "preserves PrimaryRepoSyncService.parseEnabledFlag
  legacy false tokens" test in Env.spec.mjs documents the lift.

Out of scope (deferred to Sub 4 #11836 sibling-daemon propagation):
- SwarmHeartbeatService.mjs:37 LOCAL DEFAULT_POLL_INTERVAL_MS (consumer
  rewire requires the full Sub-1-style daemon refactor).
- KbAlertingService.mjs:13/202 DEFAULT_COOLDOWN_MS (same — full daemon refactor).
- #11827 audit-record closure (will be handled post-merge as `gh issue close
  #11827 --reason 'superseded by Epic #11831 Sub 3 #11835'`).

Tests: 49/49 pass (1.3s) across 3 affected specs.

* refactor(agentos): drop historical removal-tombstone comments (#11835)

Per @tobiu: "removed per Epic X" inline comments are bloat that provide zero
value to future readers. Git log + commit message hold the rationale.

Removes the 4 tombstone comment blocks added in the prior commit on this
branch. Net: -19 lines bloat.

Tests: 23/23 pass.

---------

Co-authored-by: tobiu <tobiasuhlig78@gmail.com>"
- 2026-05-23T13:32:20Z @neo-opus-ada cross-referenced by #11844
- 2026-05-23T13:32:31Z @neo-opus-ada added sub-issue #11844
- 2026-05-23T13:53:54Z @neo-opus-ada cross-referenced by #11845
- 2026-05-23T13:54:06Z @neo-opus-ada cross-referenced by #11846
- 2026-05-23T13:54:29Z @neo-opus-ada cross-referenced by #11847
- 2026-05-23T13:55:00Z @neo-opus-ada cross-referenced by #11848
- 2026-05-23T13:55:22Z @neo-opus-ada added sub-issue #11845
- 2026-05-23T13:55:26Z @neo-opus-ada added sub-issue #11846
- 2026-05-23T13:55:34Z @neo-opus-ada added sub-issue #11847
- 2026-05-23T13:55:38Z @neo-opus-ada added sub-issue #11848
- 2026-05-23T14:14:11Z @neo-opus-ada referenced in commit `f81d189` - "refactor(agentos): orchestrator-cluster co-location ai/daemons/orchestrator/ + daemon.mjs (#11844)

Sub 8 of Epic #11831. Move Orchestrator's cluster into self-contained
ai/daemons/orchestrator/{,services/} folder. Entry-script renamed to
daemon.mjs (folder context provides daemon identity).

13 source moves + 12 test moves (mirror structure) + ai/services.mjs +
7 buildScripts/ai/ consumer-import updates + package.json ai:orchestrator
path update.

Tests: 119/119 pass (6.6s).

Subsequent subs filed: Sub 9 #11845, Sub 10 #11846, Sub 11 #11847, Sub 12 #11848."
- 2026-05-23T14:14:46Z @neo-opus-ada cross-referenced by PR #11849
- 2026-05-23T14:57:05Z @tobiu referenced in commit `6cc9179` - "refactor(agentos): orchestrator-cluster co-location ai/daemons/orchestrator/ + daemon.mjs (#11844) (#11849)

* refactor(agentos): orchestrator-cluster co-location ai/daemons/orchestrator/ + daemon.mjs (#11844)

Sub 8 of Epic #11831. Move Orchestrator's cluster into self-contained
ai/daemons/orchestrator/{,services/} folder. Entry-script renamed to
daemon.mjs (folder context provides daemon identity).

13 source moves + 12 test moves (mirror structure) + ai/services.mjs +
7 buildScripts/ai/ consumer-import updates + package.json ai:orchestrator
path update.

Tests: 119/119 pass (6.6s).

Subsequent subs filed: Sub 9 #11845, Sub 10 #11846, Sub 11 #11847, Sub 12 #11848.

* test(agentos): update laneC spec HeavyMaintenanceLeaseService path post-move (#11844)

Sub 8 #11844 moved HeavyMaintenanceLeaseService into
ai/daemons/orchestrator/services/. laneCManualScriptLeaseAdoption.spec.mjs
content-verifies that buildScripts/ai/{runSandman,syncKnowledgeBase,backup,
syncGithubWorkflow}.mjs import the lease service from the canonical path.
2 path assertions updated (regex on line 61 + toContain on line 173) to
match the new location.

The 7 laneC test failures were entirely path-string assertions; tests pass
post-update. Other 21 unit-test failures observed are PRE-EXISTING flakes
unrelated to Sub 8 (verified via git stash baseline) — grid/vdom/checkSunsetted
tests fail on origin/dev too, separate test-isolation/timing concerns.

* fix(agentos): update MailboxService.spec dynamic import for SwarmHeartbeatService post-move (#11844)

Sub 8 co-located SwarmHeartbeatService into ai/daemons/orchestrator/services/
but my static-import sweep regex (`from '...'`) missed dynamic `await import(...)`
call-sites. CI unit job 26335211375 caught: MailboxService.spec.mjs:49
`await import('../../../../../../ai/daemons/SwarmHeartbeatService.mjs')`
threw `Cannot find module`.

Fix: insert `/orchestrator/services` into the dynamic-import path. Local
re-run: 59/59 tests pass.

V-B-A miss anchor: prior turn claimed "Sub 8 introduces ZERO new failures
with NEO_TEST_SKIP_CI=true"; CI's full unit run without that flag exposed
the stale dynamic-import. Next sweep tooling for cross-cutting moves must
cover dynamic `await import()` call-sites, not just static `from '...'`.

---------

Co-authored-by: tobiu <tobiasuhlig78@gmail.com>"
- 2026-05-23T15:18:44Z @neo-opus-ada cross-referenced by PR #11850
- 2026-05-23T15:26:13Z @tobiu referenced in commit `91366d2` - "refactor(agentos): sub-daemon cluster co-location ai/daemons/{bridge,kb-alerting,kb-gc,kb-reconciliation}/ + daemon.mjs (#11845) (#11850)

Sub 9 of Epic #11831 — co-locates the four sub-daemon clusters into per-folder
mirrors of Sub 8's orchestrator pattern.

Source moves (8):
- ai/scripts/bridge-daemon.mjs            → ai/daemons/bridge/daemon.mjs
- ai/scripts/bridge-daemon-queries.mjs    → ai/daemons/bridge/queries.mjs (renamed)
- ai/daemons/KbAlertingService.mjs        → ai/daemons/kb-alerting/KbAlertingService.mjs
- ai/scripts/kb-alerting-daemon.mjs       → ai/daemons/kb-alerting/daemon.mjs
- ai/daemons/KbGarbageCollectionService.mjs → ai/daemons/kb-gc/KbGarbageCollectionService.mjs
- ai/scripts/kb-gc-daemon.mjs             → ai/daemons/kb-gc/daemon.mjs
- ai/daemons/KbReconciliationService.mjs  → ai/daemons/kb-reconciliation/KbReconciliationService.mjs
- ai/scripts/kb-reconciliation-daemon.mjs → ai/daemons/kb-reconciliation/daemon.mjs

Test moves (5 — ticket undercounted; included pre-existing bridge specs):
- bridge-daemon.spec.mjs         → ai/daemons/bridge/daemon.spec.mjs
- bridge-daemon-queries.spec.mjs → ai/daemons/bridge/queries.spec.mjs
- KbAlertingService.spec.mjs          → ai/daemons/kb-alerting/
- KbGarbageCollectionService.spec.mjs → ai/daemons/kb-gc/
- KbReconciliationService.spec.mjs    → ai/daemons/kb-reconciliation/

package.json: 3 npm script paths updated (ai:kb-alerting/kb-gc/kb-reconciliation).

Orchestrator wiring:
- Orchestrator.mjs:14-16  bridge-daemon-queries import → '../bridge/queries.mjs'
- TaskDefinitions.mjs:70  bridgeDaemon.args path → resolve('../daemons/bridge/daemon.mjs')
- TaskDefinitions.mjs:72  expectedCommand → 'daemons/bridge/daemon.mjs' (unique
  among the 5 daemon.mjs files post-Sub-8/9)
- bridge/daemon.mjs:179   enforceSingleton() process.command substring check
  updated to 'daemons/bridge/daemon.mjs' (was 'bridge-daemon.mjs')
- SummarizationCoordinatorService.mjs:8  bridge-daemon-queries import path
- KbAlertRuleEngine + KbGarbageCollectionEngine + KbReconciliationEngine: JSDoc @see paths
- CoalescingEngineService: code reference path
- multi-tenant integration spec:114 dynamic import path

V-B-A discipline from Sub 8 (#11844): swept BOTH static `from '...'` AND
dynamic `await import('...')` call-sites. Local full unit run: 2011 passed,
19 failed (all pre-existing — Authorization, checkAllAgentIdle, checkSunsetted,
QueryReRanker, TextEmbeddingService.retry, WriteSideInvariant, Grid family;
none reference moved files; confirmed via grep).

Co-authored-by: tobiu <tobiasuhlig78@gmail.com>"
- 2026-05-23T15:34:48Z @neo-opus-ada cross-referenced by PR #11851
- 2026-05-23T15:44:48Z @tobiu referenced in commit `32893c1` - "refactor(agentos): cross-daemon services bucket ai/services/{graph,ingestion}/ (#11846) (#11851)

Authored by Claude Opus 4.7 (Claude Code). Session 5572d9a5-558d-4bea-b416-e31496c289c4.

FAIR-band: in-band [verify @ merge-gate]

Resolves #11846

Sub 10 of Epic #11831 — moves the 10 cross-daemon services out of
`ai/daemons/services/` (cleared by Subs 8 + 9) into thematic
`ai/services/{graph,ingestion}/` folders mirroring the existing
`ai/services/{github-workflow,gitlab-workflow,knowledge-base,memory-core,neural-link}/`
buckets. Empty `ai/daemons/services/` folder removed.

Source moves to ai/services/graph/ (6):
- GapInferenceEngine.mjs + GoldenPathSynthesizer.mjs + GraphMaintenanceService.mjs
- LazyEdgeDrainer.mjs + SemanticGraphExtractor.mjs + TopologyInferenceEngine.mjs

Source moves to ai/services/ingestion/ (4):
- ConceptDiscoveryService.mjs + ConceptIngestor.mjs + IssueIngestor.mjs
- MemorySessionIngestor.mjs

Test moves mirror source structure (7 files).

Depth preserved (both old `ai/daemons/services/X` and new
`ai/services/{graph,ingestion}/X` are 2-deep under `ai/`), so consumer
import rewrites are pure substring substitutions `daemons/services/X.mjs`
→ `services/{folder}/X.mjs` regardless of consumer location. 22 consumer
files updated.

Manual fixes for relative-path consumers whose strings DIDN'T contain the
literal `daemons/` segment:
- Orchestrator.mjs:32 — `'../services/GoldenPathSynthesizer.mjs'` (resolves
  to old via `ai/daemons/services/`) → `'../../services/graph/...'`
- DreamService.mjs:14-23 — 9× `'../../services/X.mjs'` pattern → `'../../../services/{folder}/...'`

V-B-A from Sub 9 (#11845) lesson: my regex-only sweep missed paths that
resolve to the moved location but don't contain the explicit `daemons/`
segment. Two-stage sweep (substring rewrite + grep for proximity-relative
patterns) caught both classes here.

Local validation:
- Moved-spec subsuite (graph/ingestion): 61/61 pass
- Orchestrator suite: 119/119 pass (DreamService spec required individual rerun
  due to parallel-worker flake; passes deterministically)
- Touched consumer specs (5): 130/130 pass
- Full unit suite: 2011 pass / 19 fail / 2 skip / 10 did-not-run — all 19
  failures are pre-existing flakes (Authorization, checkAllAgentIdle,
  checkSunsetted, QueryReRanker, SessionSummarization, TextEmbeddingService.retry,
  Grid family, vdom/table); verified zero references to moved files via grep.

Per @tobiu "you and me" instruction: no peer-review broadcast on this lane.

Co-authored-by: tobiu <tobiasuhlig78@gmail.com>"
- 2026-05-23T16:01:17Z @neo-opus-ada cross-referenced by PR #11852
- 2026-05-23T16:37:08Z @tobiu referenced in commit `e207fa3` - "refactor(agentos): ai/scripts/ thematic split lifecycle|migrations|diagnostics|setup|lint (#11847) (#11852)

* refactor(agentos): ai/scripts/ thematic split lifecycle|migrations|diagnostics|setup|lint (#11847)

Authored by Claude Opus 4.7 (Claude Code). Session 5572d9a5-558d-4bea-b416-e31496c289c4.

FAIR-band: in-band [verify @ merge-gate]

Resolves #11847

Sub 11 of Epic #11831 — categorizes the 30 remaining ai/scripts/ files
into 5 thematic subfolders mirroring the existing buildScripts/ai/ pattern.
After Sub 8/9 moved daemon entries out, ai/scripts/ root is now empty of
.mjs files (all categorized).

Source moves (30):
- lifecycle/ (13): checkAllAgentIdle, checkSunsetted, harnessLifecycle,
  heartbeatLock, idleOutNudge, inflightLock, resumeHarness, revalidationSweep,
  summarize-sessions, sweepExpiredTasks, trioWakeCooldown, wakeSafetyGate,
  windowsBatchSpawn
- migrations/ (7): backfillChromaSharedUserId, bootstrapWorktree,
  migrate-discussions-b1, migrateWakeSubscriptions, normalizeGraphIdentities,
  priorityBackfill, refetchTruncatedIssues
- diagnostics/ (7): analyzeNlTelemetry, check-retired-primitives,
  check-substrate-size, detectTruncatedTimelines, diagnoseMcpConcurrency,
  review-cost-meter, validateConceptEdges
- setup/ (1): seedAgentIdentities
- lint/ (2): lint-agents, lint-skill-manifest

Test moves (17): mirror source folder structure.

Internal-import depth shifts: was 2-deep under ai/; now 3-deep —
needed BOTH '../X/' → '../../X/' AND '../../X/' → '../../../X/' patterns
(my initial sweep missed the 1-deep class; supplement caught 11 more files).

External consumer rewrites: 40 files updated via substring sweep
`scripts/X.mjs` → `scripts/<cat>/X.mjs`. Includes 3 GitHub workflows
(check-retired-primitives, skill-manifest-lint, substrate-size-guard)
and 8 npm scripts in package.json.

Manual V-B-A fixes (sweep-missed patterns):
- lint/lint-skill-manifest.mjs + lint/lint-agents.mjs: ROOT_DIR
  `path.resolve(__dirname, '../..')` → '../../..' (depth +1 for lint/)
- sweepExpiredTasks.spec.mjs: projectRoot 5 → 6 levels up, scriptPath
  added 'lifecycle' segment, 3 hardcoded regex literals updated for new
  depths, added explicit Neo + core/_export imports (spec previously
  relied on sibling-spec transitive Neo loading; isolated-worker moves
  broke that)
- wakeDualModeExports.spec.mjs: bare `import(...)` (no `await`) needed
  depth +1; original Phase 2 regex only matched `await import(...)`

Local validation:
- All 30 sources syntax-clean (`node --check`)
- Moved-spec subsuites pass (lifecycle/migrations/diagnostics/lint)
- Full unit suite: 1993 pass / 22 fail / 2 skip / 24 did-not-run — all 22
  failures verified to have ZERO references to moved files via grep
  (pre-existing flakes: Authorization, checkAllAgentIdle×2,
  checkSunsetted×5, resumeHarness, trioWakeCooldown, QueryReRanker,
  SessionSummarization, TextEmbeddingService.retry, WriteSideInvariant,
  grid×7, vdom/table).

Per @tobiu "you and me" instruction: no peer-review broadcast on this lane.

* fix(agentos): TaskDefinitions summary.args needs lifecycle/ segment post-Sub-11 move (#11847)

CI unit run 26337262726 caught the regression: `Orchestrator.spec.mjs:476`
expected `ai/scripts/lifecycle/summarize-sessions.mjs` but
`taskDefinitions.summary.args[0]` returned the stale flat path
`ai/scripts/summarize-sessions.mjs`.

Sub 11's substring sweep on path strings caught the test assertion (which
DOES contain the literal `scripts/summarize-sessions.mjs` substring after
the test was rewritten) but missed `TaskDefinitions.mjs:77` where the
filename is a STANDALONE string argument to `path.join(scriptDir, 'X.mjs')`
— the literal `scripts/X.mjs` substring never appears in source code,
only at runtime after path concatenation.

Fix: `path.join(scriptDir, 'summarize-sessions.mjs')` →
`path.join(scriptDir, 'lifecycle', 'summarize-sessions.mjs')`.

V-B-A lesson: when a refactor categorizes script files, audit ALL
`path.join(scriptDir, ...)` / `path.resolve(scriptDir, ...)` call-sites
in TaskDefinitions or similar — the literal filename argument is
invisible to substring sweeps. Same class as Sub 9's bridge-daemon
expectedCommand fix.

Local re-run: 26/26 Orchestrator spec tests pass.

* fix(agentos): update daemon.spec summary.args assertion for lifecycle/ post-Sub-11 (#11847)

CI cycle-3 caught the symmetric miss: daemon.spec.mjs:30 hardcodes the
expected `tasks.summary.args` via `path.join(scriptDir, 'summarize-sessions.mjs')`.
After the cycle-2 fix to TaskDefinitions.mjs:77 (adding 'lifecycle' segment),
the assertion now needs the same segment.

Same root cause as cycle-2's TaskDefinitions fix: substring-sweep rewrites
on path strings cannot see literal filename arguments to path.join() — the
test text never contained the literal `scripts/summarize-sessions.mjs`
substring (the filename was a separate string arg, joined at runtime).

Local re-run: 10/10 daemon.spec tests pass.

---------

Co-authored-by: tobiu <tobiasuhlig78@gmail.com>"
- 2026-05-23T16:59:42Z @neo-opus-ada referenced in commit `34b45e1` - "refactor(agentos): buildScripts/ai/ collapse into ai/scripts/{maintenance,migrations,diagnostics,runners,setup}/ (#11848)

Authored by Claude Opus 4.7 (Claude Code). Session 5572d9a5-558d-4bea-b416-e31496c289c4.

FAIR-band: in-band [verify @ merge-gate]

Resolves #11848

Sub 12 (final) of Epic #11831 — collapses buildScripts/ai/ (19 files)
into ai/scripts/<cat>/ mirroring Sub 11's thematic structure. After
this Sub, buildScripts/ai/ directory deleted entirely; buildScripts/
reverts to genuine build-pipeline content only.

Source moves (19):
- maintenance/ (12): backup, buildKbAgentFaqs, defragChromaDB,
  defragSQLiteDB, downloadKnowledgeBase, ingestTenant, kbPushClient,
  recreateGraphDb, restore, syncGithubWorkflow, syncKnowledgeBase,
  uploadKnowledgeBase
- migrations/ (1): migrateMemoryCore
- diagnostics/ (1): mcpHealthcheck
- runners/ (4): roadmapPlanner, runAgent, runGoldenPath, runSandman
- setup/ (1): initServerConfigs

Test moves (12): mirror source by category. One pre-existing spec
util/check-chore-sync.spec.mjs tests buildScripts/util/ (non-AI),
left in place — out of Sub 12 scope.

External consumers (34 files updated via substring sweep + manual fixes):
- package.json: 16 npm script paths (ticket listed 11; actual 16
  including prepare hook + sync-github-workflow + sync-kb)
- ai/deploy/docker-compose.yml: 2 paths
- 2 integration specs + 3 KbReconciliationService.spec dynamic-imports
- ai/daemons/orchestrator/{Orchestrator,TaskDefinitions}.mjs
- ai/services/knowledge-base/DatabaseService + memory-core variant

Manual V-B-A fixes (sweep-missed patterns from Subs 9/10/11 lessons):
- TaskDefinitions kbSync + backup args: refactored awkward
  path.resolve(scriptDir, '../../ai/scripts/maintenance/X') →
  path.join(scriptDir, 'maintenance', 'X'). daemon.spec assertions
  matched. Consistent with Sub-11 summary pattern.
- laneCManualScriptLeaseAdoption.spec: refactored single scriptDir
  variable (was 'buildScripts/ai' literal) into per-file path map
  because tests span maintenance/ + runners/ categories. Updated
  HML import regex + substring assertions for new
  '../../daemons/orchestrator/services/...' source path. Added
  explicit Neo + core imports (latent cross-spec coupling).
- peer-architecture.spec: REPO_ROOT depth +1; regex updated from
  ai\/services\.mjs → \/services\.mjs (source now uses
  '../../services.mjs' not '...ai/services.mjs').
- restore-hardening.spec: repoRoot path.resolve depth +1.
- Doc-string updates: 19 @module annotations + 3 test.describe strings.

V-B-A composite lesson applied (Subs 9/10/11/12):
1. Substring sweep for explicit path strings
2. Relative-path proximity grep for paths missing the literal segment
3. path.join(scriptDir, X) audit for filename-as-arg patterns
4. Isolated-worker Neo-import check for cross-spec coupling
5. Doc-string + describe-name cleanup for non-code references

Local validation:
- Moved-spec subsuites: 220/220 pass
- Full unit suite: 1995 pass / 21 fail / 2 skip / 24 did-not-run —
  all 21 failures pre-existing flakes (Authorization, checkAllAgentIdle,
  checkSunsetted, resumeHarness, trioWakeCooldown, QueryReRanker,
  SessionSummarization, TextEmbeddingService.retry, WriteSideInvariant,
  grid×7, Teleportation×2); zero references to moved files in any failure.

Epic #11831 complete: Subs 8, 9, 10, 11, 12 all landed. ai/daemons/,
ai/scripts/, buildScripts/ai/ structure now fully refactored to
self-contained per-daemon folders + thematic script categorization +
buildScripts/ reverted to genuine build-pipeline only.

Per @tobiu "you and me" instruction: no peer-review broadcast on this lane."
- 2026-05-23T17:00:28Z @neo-opus-ada cross-referenced by PR #11853
- 2026-05-23T17:42:33Z @tobiu referenced in commit `e6c9df0` - "refactor(agentos): buildScripts/ai/ collapse into ai/scripts/{maintenance,migrations,diagnostics,runners,setup}/ (#11848) (#11853)

* refactor(agentos): buildScripts/ai/ collapse into ai/scripts/{maintenance,migrations,diagnostics,runners,setup}/ (#11848)

Authored by Claude Opus 4.7 (Claude Code). Session 5572d9a5-558d-4bea-b416-e31496c289c4.

FAIR-band: in-band [verify @ merge-gate]

Resolves #11848

Sub 12 (final) of Epic #11831 — collapses buildScripts/ai/ (19 files)
into ai/scripts/<cat>/ mirroring Sub 11's thematic structure. After
this Sub, buildScripts/ai/ directory deleted entirely; buildScripts/
reverts to genuine build-pipeline content only.

Source moves (19):
- maintenance/ (12): backup, buildKbAgentFaqs, defragChromaDB,
  defragSQLiteDB, downloadKnowledgeBase, ingestTenant, kbPushClient,
  recreateGraphDb, restore, syncGithubWorkflow, syncKnowledgeBase,
  uploadKnowledgeBase
- migrations/ (1): migrateMemoryCore
- diagnostics/ (1): mcpHealthcheck
- runners/ (4): roadmapPlanner, runAgent, runGoldenPath, runSandman
- setup/ (1): initServerConfigs

Test moves (12): mirror source by category. One pre-existing spec
util/check-chore-sync.spec.mjs tests buildScripts/util/ (non-AI),
left in place — out of Sub 12 scope.

External consumers (34 files updated via substring sweep + manual fixes):
- package.json: 16 npm script paths (ticket listed 11; actual 16
  including prepare hook + sync-github-workflow + sync-kb)
- ai/deploy/docker-compose.yml: 2 paths
- 2 integration specs + 3 KbReconciliationService.spec dynamic-imports
- ai/daemons/orchestrator/{Orchestrator,TaskDefinitions}.mjs
- ai/services/knowledge-base/DatabaseService + memory-core variant

Manual V-B-A fixes (sweep-missed patterns from Subs 9/10/11 lessons):
- TaskDefinitions kbSync + backup args: refactored awkward
  path.resolve(scriptDir, '../../ai/scripts/maintenance/X') →
  path.join(scriptDir, 'maintenance', 'X'). daemon.spec assertions
  matched. Consistent with Sub-11 summary pattern.
- laneCManualScriptLeaseAdoption.spec: refactored single scriptDir
  variable (was 'buildScripts/ai' literal) into per-file path map
  because tests span maintenance/ + runners/ categories. Updated
  HML import regex + substring assertions for new
  '../../daemons/orchestrator/services/...' source path. Added
  explicit Neo + core imports (latent cross-spec coupling).
- peer-architecture.spec: REPO_ROOT depth +1; regex updated from
  ai\/services\.mjs → \/services\.mjs (source now uses
  '../../services.mjs' not '...ai/services.mjs').
- restore-hardening.spec: repoRoot path.resolve depth +1.
- Doc-string updates: 19 @module annotations + 3 test.describe strings.

V-B-A composite lesson applied (Subs 9/10/11/12):
1. Substring sweep for explicit path strings
2. Relative-path proximity grep for paths missing the literal segment
3. path.join(scriptDir, X) audit for filename-as-arg patterns
4. Isolated-worker Neo-import check for cross-spec coupling
5. Doc-string + describe-name cleanup for non-code references

Local validation:
- Moved-spec subsuites: 220/220 pass
- Full unit suite: 1995 pass / 21 fail / 2 skip / 24 did-not-run —
  all 21 failures pre-existing flakes (Authorization, checkAllAgentIdle,
  checkSunsetted, resumeHarness, trioWakeCooldown, QueryReRanker,
  SessionSummarization, TextEmbeddingService.retry, WriteSideInvariant,
  grid×7, Teleportation×2); zero references to moved files in any failure.

Epic #11831 complete: Subs 8, 9, 10, 11, 12 all landed. ai/daemons/,
ai/scripts/, buildScripts/ai/ structure now fully refactored to
self-contained per-daemon folders + thematic script categorization +
buildScripts/ reverted to genuine build-pipeline only.

Per @tobiu "you and me" instruction: no peer-review broadcast on this lane.

* fix(agentos): depth-shift missed '../../X' patterns post-Sub-12 collapse (#11848)

CI install failed: `npm prepare` hook → `node ai/scripts/maintenance/downloadKnowledgeBase.mjs`
→ `Cannot find module '/home/runner/work/neo/neo/ai/package.json'`.

Root cause: Sub 12 depth-shift sweep handled `'../../src/'` → `'../../../src/'`
and `'../../ai/<sub>/'` → `'../../<sub>/'` collapses, but missed:

- `'../../package.json'` (was repo-root from buildScripts/ai/; now resolves to
  ai/package.json from ai/scripts/<cat>/) — broke downloadKnowledgeBase +
  uploadKnowledgeBase
- `'../../ROADMAP.md'` — broke roadmapPlanner
- `'../../ai/agent/'` (agent/ wasn't in my known sub-list along with services,
  daemons, mcp, etc.) — broke runAgent

Fix: 4 targeted single-line replacements. Local smoke-test:
- downloadKnowledgeBase --help: ✓ runs
- uploadKnowledgeBase --help: ✓ runs (triggers defrag pre-step)
- runAgent --help: ✓ initializes orchestrator
- roadmapPlanner syntax-check: ✓

V-B-A lesson: when shifting depths for moved files, audit ALL '../../X'
patterns (regardless of whether X is under a known subdir prefix). Allow-list
approach (`src/`, `node_modules/`, `services/`...) misses repo-root files
(package.json, ROADMAP.md, LICENSE etc.). Deny-list — "what relative paths
do these files use that resolve outside the new parent?" — would have caught
all 4 at once.

* fix(agentos): 13 missed __dirname depth shifts post-Subs-11/12 (#11848)

CI install failed: `npm prepare` → initServerConfigs.mjs reported
"MCP Server directory not found" → ai/services.mjs couldn't load the
gitignored config.mjs (normally generated by initServerConfigs from
config.template.mjs).

Root cause: my Sub 11 + Sub 12 sweeps depth-shifted `from '...'` import
strings but missed `path.resolve(__dirname, '../..')` and `'../../'`
computed-path patterns. These return repo-root or `.neo-ai-data/`
locations and need an extra `..` per level the script moved deeper.

13 fixes across:
- initServerConfigs.mjs: cwd `'../../'` → `'../../../'`
- diagnostics/{analyzeNlTelemetry, detectTruncatedTimelines,
  diagnoseMcpConcurrency, validateConceptEdges}: ROOT_DIR/projectRoot
  needed +1
- lifecycle/{harnessLifecycle, inflightLock, resumeHarness,
  wakeSafetyGate}: `'../../.neo-ai-data/...'` patterns needed +1
- maintenance/{backup, defragChromaDB, defragSQLiteDB, restore}:
  PROJECT_ROOT needed +1 (was 2-deep from buildScripts/ai/, now 3-deep)

These were latent — none of Sub 11's CI checks invoked the affected
code paths. Sub 12's `npm prepare` hook triggered initServerConfigs,
surfacing the class. Sister scripts in lifecycle/diagnostics/maintenance
would have failed at first runtime invocation if not fixed now.

Local smoke-test: `node ai/scripts/setup/initServerConfigs.mjs`:
- Before: "MCP Server directory not found, skipping config initialization"
- After: "Config missing for MCP server 'gitlab-workflow'. Cloning from template..."

V-B-A composite lesson update: cross-cutting folder moves need a sweep
class beyond `from '...'` import strings — also audit ANY
`path.resolve(__dirname, ...)` / `path.join(__dirname, ...)` for
relative components. Same depth-shift rule applies.

* fix(agentos): update Dockerfile + pre-push-hook for buildScripts/ai collapse (#11848)

CI integration failed: Docker build step
  RUN npm rebuild better-sqlite3 && node ./buildScripts/ai/initServerConfigs.mjs
errored with "Cannot find module '/app/buildScripts/ai/initServerConfigs.mjs'".

Sub 12's substring sweep ran against *.mjs, *.json, *.yml, *.yaml.
Missed file types:
- Dockerfile (no extension): ai/deploy/Dockerfile:19
- Shell scripts: examples/cloud-deployment/pre-push-hook.sh (lines 16, 18)

Fixes (3):
- Dockerfile: ./buildScripts/ai/initServerConfigs.mjs → ./ai/scripts/setup/initServerConfigs.mjs
- pre-push-hook.sh: NEO_KB_PUSH_CLIENT + NEO_INGEST_CLI defaults updated to ai/scripts/maintenance/

V-B-A composite lesson update (Subs 9/10/11/12):
Cross-cutting folder moves' substring-sweep file-type matrix needs
extension-less filenames (Dockerfile, Makefile) + shell scripts (.sh)
in addition to .mjs/.json/.yml/.yaml. Documentation files (.md) are
deliberately excluded — they describe historical context, not runtime
behavior. But operational artifacts (Dockerfiles, hooks, env scripts)
ARE runtime-load-bearing.

---------

Co-authored-by: tobiu <tobiasuhlig78@gmail.com>"
- 2026-05-23T17:58:07Z @neo-opus-ada cross-referenced by #11854
- 2026-05-23T17:58:46Z @neo-opus-ada cross-referenced by #11855
- 2026-05-23T17:59:11Z @neo-opus-ada added sub-issue #11854
- 2026-05-23T17:59:13Z @neo-opus-ada added sub-issue #11855
- 2026-05-23T18:06:46Z @neo-opus-ada cross-referenced by PR #11856
- 2026-05-23T19:29:26Z @neo-opus-ada cross-referenced by #11858
- 2026-05-23T19:29:35Z @neo-opus-ada cross-referenced by #11859
- 2026-05-23T19:29:46Z @neo-opus-ada cross-referenced by #11860
- 2026-05-23T19:30:11Z @neo-opus-ada cross-referenced by #11861
- 2026-05-23T19:30:38Z @neo-opus-ada cross-referenced by #11862
- 2026-05-23T19:30:58Z @neo-opus-ada added sub-issue #11858
- 2026-05-23T19:30:59Z @neo-opus-ada added sub-issue #11859
- 2026-05-23T19:31:00Z @neo-opus-ada added sub-issue #11860
- 2026-05-23T19:31:01Z @neo-opus-ada added sub-issue #11861
- 2026-05-23T19:31:03Z @neo-opus-ada added sub-issue #11862
- 2026-05-23T19:34:17Z @neo-opus-ada cross-referenced by PR #11863
- 2026-05-23T20:37:18Z @tobiu referenced in commit `e365943` - "feat(agentos): extract DreamCoordinatorService — getDueTask only (#11858) (#11863)

* feat(agentos): extract DreamCoordinatorService — getDueTask only (#11858)

Authored by Claude Opus 4.7 (Claude Code). Session 5572d9a5-558d-4bea-b416-e31496c289c4.

FAIR-band: in-band [verify @ merge-gate]

Resolves #11858

Sub 15 of Epic #11831 — first of three coordinator extractions in Discussion
#11857 Cycle-3.5 B-prime convergence (graduated 2026-05-23T19:23Z, GPT
[GRADUATION_APPROVED] DC_kwDODSospM4BA-...). Matches D3.1 boundary per
v13-path.md:117: per-task coordinators decide what work is due; orchestrator
wires; ProcessSupervisor executes.

Creates `ai/daemons/orchestrator/services/DreamCoordinatorService.mjs`:
- Pure-function `buildDreamTrigger({now, lastRunAt, intervalMs})` returns
  `{taskName, source, reason}` or null
- `DreamCoordinatorService.getDueTask({state, now, dreamIntervalMs})` wraps
  the pure function with state-shape mapping
- Mirrors `SummarizationCoordinatorService.getDueTask({...})` precedent shape

Strict boundary preserved:
- DreamService retains `processUndigestedSessions()` and all execution-side
  methods unchanged — coordinator owns due-trigger selection ONLY
- No state writes / no markStarted/markCompleted/recordTaskOutcome calls
- No reactive-config-aliased wrapper around DreamService (Sub-1 anti-pattern
  at new layer is explicitly avoided per Discussion #11857 Avoided Traps)
- Orchestrator's scheduleDreamCycle() body unchanged in this Sub; Sub 18
  #11862 wires the new coordinator into the registry

Pure-function unit tests: 8/8 pass covering interval-elapsed boundaries,
disabled (`intervalMs <= 0`), exactly-equal-to-interval edge, reason-carries-
interval-verbatim for telemetry, getDueTask state mapping (including
graceful missing-state default to lastRunAt=0).

* fix(agentos): switch DreamCoordinatorService to gatekeep pattern (#11858)

Same anti-pattern operator caught earlier today on Env (Sub 1 review):
class extending Base + singleton: true + Neo.setupClass for a service that
uses ZERO Neo features — no reactive configs, no lifecycle hooks, no
construct/apply/createId, no className/singleton semantics actually used.
Just a namespace for one pure-wrapper method around buildDreamTrigger.

Switched to gatekeep pattern per src/core/IdGenerator.mjs + src/util/Env.mjs
precedent: plain object literal + Neo.gatekeep(obj, 'Neo.x.y.Z'). Drops
Base inheritance overhead + setupClass processing + the empty static config.

Consumer surface unchanged (DreamCoordinatorService.getDueTask({...}) works
identically). 8/8 unit tests pass against the new shape.

Precedent debt acknowledged: SummarizationCoordinatorService /
BackupCoordinatorService / PrimaryRepoSyncService all have the same
anti-pattern (Base + singleton: true for stateless utilities). Worth a
follow-up sweep — flagged via spawn_task in this turn for separate cleanup.

* refactor(agentos): collapse DreamCoordinator's pure-fn/wrapper split — one getDueTask (#11858)

Operator caught the split as ceremony-without-payoff. Honest answer: I
mimicked SummarizationCoordinatorService's pattern (separate buildSummaryTrigger
pure function + getDueTask wrapper) without challenging whether the split
was earned. There it IS earned — SummarizationCoordinator.getDueTask calls
getUnreadSunsetHandoversFn(db) for additional I/O input + attaches an
onSuccess hook that marks handovers as read. The pure function takes 4
inputs across 2 branches; the wrapper does real extra work.

DreamCoordinator's getDueTask just maps state.lastRunAt ?? 0 into the
pure function's arg. No I/O, no side-effect hooks, no extra branches.
The split adds ceremony, not value.

Collapsed to single getDueTask({state, now, dreamIntervalMs}). Spec
collapses 8 → 5 tests (the redundant pure-vs-wrapper duplicates
disappear). Default export still uses Neo.gatekeep so the registry
descriptor shape (coordinator field with .getDueTask method) works
identically.

* refactor(agentos): DreamCoordinator pure module — drop gatekeep + default export (#11858)

Two issues operator caught on re-read:

1. Stale namespace path. Both the @namespace JSDoc tag and the Neo.gatekeep
   argument referenced `Neo.ai.daemons.services.DreamCoordinatorService`
   (the pre-Sub-8 path). Actual filesystem location is now
   `ai/daemons/orchestrator/services/` → namespace would be
   `Neo.ai.daemons.orchestrator.services.DreamCoordinatorService`. Copied
   stale JSDoc from SummarizationCoord precedent without updating.

2. Double export of the same function. `getDueTask` was exported both as
   a named export AND wrapped in the gatekeep default-export object. One
   function exposed via two import paths = same ceremony-without-payoff
   anti-pattern from the prior commit, just at a different layer.

Deeper question: why register via Neo.gatekeep at all? Env / IdGenerator
use it because Neo.util.Env / Neo.core.IdGenerator are broadly-used
substrate where tooling/debug access via Neo.ns() has real value.
DreamCoordinator is orchestrator-internal — consumers import the function
directly; namespace registration buys nothing.

Final shape: pure module with one named export. No gatekeep. No default.
No @namespace JSDoc. Spec drops the Neo + core/_export bootstrap imports
too (not needed without module-load gatekeep call).

4/4 spec tests pass. Net diff vs prior commit: -36 LOC.

Sub 18's registry will consume via `import {getDueTask as dreamGetDueTask}
from '.../DreamCoordinatorService.mjs'` and register the function on a
descriptor — coordinator-as-object wrapper not needed.

* refactor(agentos): rename — not a Service, just a function in scheduling/ (#11858)

Operator: "this is not a service. it is a function." Service/Coordinator
suffixes imply state + methods + lifecycle; this file holds one pure
trigger projection. Files describe what they are.

Renames:
- ai/daemons/orchestrator/services/DreamCoordinatorService.mjs
  -> ai/daemons/orchestrator/scheduling/dream.mjs
- test/.../services/DreamCoordinatorService.spec.mjs
  -> test/.../scheduling/dream.spec.mjs

New folder scheduling/ (sibling to services/) holds per-task due-trigger
projections. services/ keeps things that are genuine services. Example:
SummarizationCoordinatorService calls getUnreadSunsetHandoversFn(db) and
attaches onSuccess hooks; that one EARNED the Service suffix. DreamService
/ SwarmHeartbeatService / GoldenPathSynthesizer stay in services/ as
execution-side responsibilities.

JSDoc + describe title updated. No more Coordinator/Service in this file
or its spec. 4/4 spec tests pass at new location.

Sub 18's registry will consume via:
  import {getDueTask as dreamGetDueTask} from './scheduling/dream.mjs'

Downstream churn flagged: Discussion #11857 body + tickets #11859/11860
still use ...CoordinatorService naming. Will update when filing Sub 16 /
Sub 17 work (same shape: scheduling/<task>.mjs). Sub 19 #11861 stays
Service-named since MaintenanceBackpressureService IS a genuine service
(state + multiple visibly-separate surfaces + lease delegation).

* docs(agentos): drop decay-prone JSDoc references in scheduling/dream.mjs (#11858)

Operator: "we e.g. change the referenced file, and then what? history versus
intents."

Removed brittle cross-references that lie when targets shift:
- v13-path.md:117 (line number — lies on any edit above line 117)
- D3.1 boundary (section label — lies on doc restructure)
- DreamService.processUndigestedSessions() (specific method name — lies on rename)
- @see ai/daemons/orchestrator/services/DreamService.mjs (scaffolding the
  reader can infer from file location + function name)

Same anti-pattern as Sub 1's historical-context comments: describes a
moment-in-time architecture state, not the file's own intent. JSDoc
should describe what THIS file IS so it stays true regardless of
neighboring substrate evolution.

Result: JSDoc now describes the function's contract (returns trigger
when interval elapsed since lastRunAt; pure). No external coordinates.
4/4 spec tests still pass.

Lesson for Sub 16/17/18/19: no baked line numbers, no section labels,
no neighboring-file method names in JSDoc prose.

* docs(agentos): collapse duplicate JSDoc blocks — one function, one comment (#11858)

Operator: file has ONE function, two comment blocks said the same thing
twice. File-level @summary made sense when this was a class with methods
(class JSDoc + method JSDoc). Now that it's a single pure function, the
file IS the function — one JSDoc above getDueTask covers both.

4/4 spec tests still pass.

---------

Co-authored-by: tobiu <tobiasuhlig78@gmail.com>"
- 2026-05-23T20:39:41Z @neo-opus-ada cross-referenced by #11864
- 2026-05-23T20:39:51Z @neo-opus-ada added sub-issue #11864
- 2026-05-23T20:42:53Z @neo-opus-ada cross-referenced by PR #11865
- 2026-05-23T20:50:21Z @tobiu referenced in commit `ac2fecf` - "feat(agentos): extract swarm-heartbeat due-trigger projection (#11859) (#11865)

Sub 16 of Epic #11831. Pure function in scheduling/<task>.mjs, matching the
shape Sub 15 (PR #11863) established after 6 iterations of operator-led
KISS pressure. Applies all Sub-15 lessons from the start:

- File at scheduling/swarmHeartbeat.mjs (no Service/Coordinator suffix)
- One JSDoc block above the one function (no file-level + function-level split)
- No class extends Base, no singleton config, no Neo.gatekeep
- No decay-prone JSDoc references (no v13-path.md:N, no D3.1, no method names)
- Spec doesn't import Neo (no module-load gatekeep call requiring globalThis.Neo)
- Function signature parallel to scheduling/dream.mjs

4/4 spec tests pass.

Orchestrator's inline schedule logic (lines 906-934) is NOT modified yet —
Sub 18 #11862 wires the new projection into the registry. SwarmHeartbeatService
retains initAsync() + pulse() + all lifecycle/execution methods. The
enabled-gate (this.swarmHeartbeatEnabled) stays in Orchestrator's call-site
until Sub 18 moves profile-aware filtering into pickNextCandidate.

Co-authored-by: tobiu <tobiasuhlig78@gmail.com>"
- 2026-05-23T20:57:22Z @neo-opus-ada cross-referenced by PR #11866
- 2026-05-23T21:30:25Z @neo-opus-ada cross-referenced by PR #11867
- 2026-05-23T21:42:38Z @neo-opus-ada cross-referenced by PR #11868
- 2026-05-24T01:21:53Z @neo-opus-ada cross-referenced by #11874
- 2026-05-24T01:46:30Z @neo-opus-ada cross-referenced by PR #11877
- 2026-05-24T13:04:19Z @neo-opus-ada cross-referenced by PR #11899
- 2026-05-24T13:09:49Z @neo-opus-ada cross-referenced by #11900
- 2026-05-24T13:40:31Z @neo-gpt cross-referenced by PR #11901
- 2026-05-24T17:26:56Z @neo-gpt cross-referenced by PR #11918
- 2026-05-24T23:42:29Z @neo-opus-ada cross-referenced by PR #11941
- 2026-05-25T01:10:00Z @neo-opus-ada cross-referenced by PR #11945
- 2026-05-25T01:23:08Z @neo-opus-ada cross-referenced by PR #11946
- 2026-05-25T01:36:09Z @neo-opus-ada cross-referenced by #11948
- 2026-05-25T05:26:05Z @tobiu referenced in commit `9836060` - "refactor(agentos): harmonize 3 Coordinator services to scheduling/<task>.mjs (#11864) (#11941)

* refactor(agentos): harmonize 3 Coordinator services to scheduling/<task>.mjs pure-function pattern (#11864)

Sub 20 of Epic #11831 — completes the scheduling/services boundary established by Sub 15 (PR #11863) for the 3 pre-existing coordinator services that retained class+singleton+Neo.setupClass machinery despite using zero Neo class-system features.

- Delete services/SummarizationCoordinatorService.mjs (superseded by scheduling/summary.mjs which already exists with the same shape)
- Delete services/BackupCoordinatorService.mjs (superseded by scheduling/backup.mjs)
- Slim services/PrimaryRepoSyncService.mjs: drop the getDueTask method + buildPrimaryRepoSyncTrigger export (both already in scheduling/primaryDevSync.mjs); keep runTask + execution helpers per the per-file split prescription in #11864
- Orchestrator.mjs: import {getDueTask as <name>Import} from ./scheduling/<task>.mjs for all 3; expose as function-typed instance-field DI seams (summaryGetDueTask, backupGetDueTask, primaryDevSyncGetDueTask) so tests still override without module-level mocking
- Update Orchestrator.spec.mjs: 4 mock injection sites swap from {getDueTask: fn} object-shape to function-shape; primaryRepoSyncService stays object-shape for runTask
- Update services/PrimaryRepoSyncService.spec.mjs: drop the 1 interval-triggers test (scheduling/primaryDevSync.spec.mjs has the canonical coverage)
- Update daemon.spec.mjs: tighten daemonSource maintenance-script assertions to quoted-filename form so scheduling/backup.mjs imports don't false-positive against the maintenance/backup.mjs guard
- daemon.mjs JSDoc: drop the SummarizationCoordinatorService reference from the bootstrap comment

Substrate-net-reduction: 2 source files + 2 spec files deleted; PrimaryRepoSyncService.mjs slimmed by 40 lines. Compression-positive per Discussion #11891.

* docs(agentos): update v13-path.md SummarizationCoordinatorService references to scheduling/summary.mjs (#11864)

Reconciles indexed architecture docs with the post-#11864 pure-function scheduling boundary. Future-agent KB rebuilds will no longer point at the removed `services/SummarizationCoordinatorService.mjs` precedent.

- Structure diagram (line 102) — now shows `scheduling/summary.mjs` as the Piece C trigger location with `services/PrimaryRepoSyncService.mjs` clarified as runTask-only post-#11864
- CadenceEngine boundary doc (line 117) — `getDueTask` precedent pointer updated to `scheduling/summary.mjs`; historical pointer to retired class preserved for archaeology
- M3 milestone narrative (line 169) — original SummarizationCoordinatorService text replaced with "summarization sweep coordinator" generic + parenthetical post-#11864 shape pointer
- M3 MVP split narrative (line 171) — "Piece C trigger selection" sentence rephrased so the active-pointer matches scheduling/summary.mjs
- M3.5 extraction-location precedent (line 188) — preserves historical SummarizationCoordinatorService.mjs line-233 reference but explicitly annotates that the precedent class was retired by #11864; the services/ landing-place decision for execution-shaped collaborators remains canonical

Addresses @neo-gpt cycle-1 RA on PR #11941: stale `learn/agentos/v13-path.md` references would otherwise borrow authority from the removed precedent in future KB rebuilds.

---------

Co-authored-by: tobiu <tobiasuhlig78@gmail.com>"
- 2026-05-25T05:49:31Z @tobiu referenced in commit `193b5f5` - "test(orchestrator): add Sub-1 invariant + config-precedence + propagation coverage (#11834) (#11945)

Sub 2 of Epic #11831 — locks the contract Sub 1 (#11833) established by adding the regression-detection layer that prevents the removed anti-patterns from re-entering.

New spec file Orchestrator.invariants.spec.mjs (16/16 pass) covering 3 AC clusters:

**AC2 — Config-precedence (6 tests)**:
- Env var overrides AiConfig.data for interval values
- AiConfig.data is consulted when env var is absent
- Env var overrides AiConfig.data for boolean enable flags (localOnly)
- AiConfig.localOnly.X=null falls through to deployment-profile default (local enables, cloud disables)
- AiConfig.data mutations are isolated per test via beforeEach/afterEach restore (substrate-leak prevention)

**AC3 — Parent-prop propagation via afterSetX hooks (5 tests, witness-property style)**:
- taskDefinitions → processSupervisorService
- dataDir → processSupervisorService + maintenanceBackpressureService
- healthService → both (witness via marker property)
- taskStateService → both (witness via marker)
- spawnFn → processSupervisorService (witness via marker on function)
- heavyMaintenanceLeasePath → maintenanceBackpressureService

Propagation uses witness-property assertions rather than reference equality because child reactive setters may wrap inputs via ClassSystemUtil.beforeSetInstance — the Sub-1 contract is value content flows through afterSetX, not reference identity.

**AC4 — Source-level invariants (5 tests, comment/string-stripped)**:
- Orchestrator.mjs has no `configure()` shadow-resolver method
- TaskDefinitions.mjs has no `DEFAULT_*_INTERVAL_MS` exports
- Orchestrator.mjs has no `parseInterval` / `parseEnabledFlag` call sites
- Orchestrator.mjs has no `processSupervisorService.set({...this...})` context-replay block
- Orchestrator.mjs has no `_`-suffix reactive config slot without a corresponding `beforeSet*` or `afterSet*` hook

Inline stripCommentsAndStrings helper handles block comments, line comments, and string literals so source-grep doesn't false-positive against JSDoc that explicitly names what the class doesn't do (lines 124-125 of Orchestrator.mjs document the absences).

cloudOnly handling is defensive — save+restore only if present on origin/dev. The cloudOnly collection lands on dev when #11940 merges; until then, this spec runs cleanly without depending on it.

AC1 (refactored createTestOrchestrator) is the helper Sub 1 (#11833) already shipped; Sub 2 layers the invariant-test coverage on top. Total touched-surface: 232/232 orchestrator-tree unit tests pass.

Co-authored-by: tobiu <tobiasuhlig78@gmail.com>"
- 2026-05-25T05:50:23Z @tobiu referenced in commit `5d428ab` - "test(orchestrator): external-config audit invariants AC1-3 + AC4-5 findings (#11837) (#11946)

* test(orchestrator): external-config audit invariants AC1-3 + AC4-5 documented findings (#11837)

Sub 5 of Epic #11831 — external-user configurability audit (forks, npx neo-app workspaces, cloud tenants). V-B-A grep across ai/daemons/ confirms the substrate is already clean for AC1-3; this PR ships invariant tests that lock the clean state with regression-detection so future-agent changes can't silently re-introduce Neo-team-specific assumptions.

New spec file Orchestrator.externalConfig.spec.mjs (3/3 pass) covering:

**AC1 — No Neo-team identity literals (@neo-opus-4-7 / @neo-gpt / @neo-gemini-3-1-pro)** across the ai/daemons/ subtree (includes the orchestrator-daemon entrypoint at ai/daemons/orchestrator/daemon.mjs post-#11847 thematic split). Daemon code must resolve identities via the ai/graph/identityRoots.mjs registry, never via hardcoded literals.

**AC2 — No hardcoded "Project 12" / "v13" / "release:v*" literals** in daemon code. These don't survive Neo-release-cycle transitions or external deployments.

**AC3 — No operator absolute paths** (/Users/Shared/github/neomjs/neo or /Users/tobiasuhlig). All paths must resolve relative to checkout root via existing Neo path helpers.

The walker recurses ai/daemons/ skipping node_modules, dist, .git, .neo-ai-data; stripCommentsAndStrings inlines so JSDoc/comment-prose mentions of the patterns don't false-positive. String literals are preserved (exactly the surface AC1-3 specify scanning).

**AC4 — Deployment-profile honoring** verified at audit-time: all Orchestrator enable-flag getters route through resolveDeploymentEnabled(key) which respects AiConfig.orchestrator.deploymentMode (Orchestrator.mjs:347-351). localOnly substrate populated symmetrically per daemon.mjs:229-261. Not turned into invariant test (the existing #11941 + #11940 PRs introduce additional helper functions like resolveCloudOnlyEnabled for the cloud-default-on lane class; a meta-invariant would need to know that both helpers are acceptable — out of scope for AC4 narrow framing).

**AC5 — `npx neo-app` workspace safety** requires spawning a fresh workspace and exercising daemon boot under missing-Neo-substrate conditions — too heavy for unit-test scope. Deferred to follow-up (will file ticket if not already tracked).

Test-spec-only PR. 3/3 PASS at branch head; ai/daemons substrate unchanged. Close-target as `Refs #11837` (not Resolves) until AC4/AC5 follow-up coverage lands.

* docs(test): correct stripCommentsAndStrings JSDoc to match string-preserving behavior (#11837)

Per @neo-gpt #11946 cycle-1 truth-in-code RA: the helper JSDoc claimed it strips string literals, but the implementation deliberately preserves them because AC1-3 specifically target string-literal occurrences (e.g., '@neo-opus-4-7' as a literal is a violation, but a comment mentioning the same handle is not). Updated JSDoc to match implementation + added the AC1-3 rationale explaining why string-literal preservation is load-bearing.

---------

Co-authored-by: tobiu <tobiasuhlig78@gmail.com>"
- 2026-05-26T07:37:21Z @neo-gpt cross-referenced by PR #12011
- 2026-05-28T07:04:41Z @neo-opus-ada cross-referenced by #12130
- 2026-05-28T07:05:03Z @neo-opus-ada added sub-issue #12130
### @neo-gpt - 2026-06-06T21:08:06Z

**Input from GPT-5 (Codex Desktop):**

> ● ## Epic Review by @neo-gpt (Codex Desktop)
> 
> Scope: first @neo-gpt sub pickup review for #11831 before acting on #11836.
> 
> ### Stage 1 - Roadmap Fit
> 
> [PASS] The epic still fits v13: it turns the Orchestrator daemon config stack into a maintainable reference pattern while keeping policy resolution explicit. The multi-tenant cloud constraint remains active: local-only daemon behavior must stay behind the existing deployment-mode and opt-in gates.
> 
> ### Stage 2 - Approach Elegance
> 
> [PASS] The intended solution shape is still substrate-correct: `Neo.util.Env` owns env parsing, operator policy values use a 2-value chain, class-system-managed collaborators use real hooks, and `configure()` is not treated as a parallel policy resolver. Current source confirms `Orchestrator.mjs` already carries the deployment-aware Class A/B/C/D Service-DI framing that #11836 should propagate only where the sibling files actually have the same shape.
> 
> ### Stage 2.5 - Source Discussion Mapping
> 
> [PASS] Discussion #11828 graduated to #11831 after the Cycle-3.3 approval path. The six subissues map to the discussion criteria without a missing criterion: #11832 (`Neo.util.Env`), #11833 (Orchestrator reference), #11834 (test/invariants), #11835 (parser/default cleanup), #11836 (sibling propagation), and #11837 (external configurability audit).
> 
> ### Stage 3 - Sub-Structure Coherence
> 
> [PASS WITH NARROWING] Current live state shows #11832, #11833, #11834, #11835, and #11837 are terminal. #11836 is the only remaining open sub from the original decomposition.
> 
> The #11836 body has stale target paths, so the implementation lane must follow current-source intent rather than the literal old locations. Current-source V-B-A narrows the relevant residue to hookless underscore config slots in these files:
> 
> - `ai/daemons/orchestrator/services/SwarmHeartbeatService.mjs`: `pollIntervalMs_`
> - `ai/daemons/kb-alerting/KbAlertingService.mjs`: `isPolling_`, `pollHandle_`, `pollIntervalMs_`
> - `ai/daemons/kb-reconciliation/KbReconciliationService.mjs`: `isPolling_`, `pollHandle_`, `pollIntervalMs_`
> - `ai/daemons/kb-gc/KbGarbageCollectionService.mjs`: `isPolling_`, `pollHandle_`, `pollIntervalMs_`
> 
> `ai/services/graph/GapInferenceEngine.mjs` no longer presents the sibling daemon config residue described by the original #11836 target list; do not force a change there without fresh evidence.
> 
> ### Closeout Matrix Seed
> 
> | Sub | Status | Current evidence |
> | --- | --- | --- |
> | #11832 `Neo.util.Env` primitive | Done | Closed via #11838. |
> | #11833 Orchestrator reference | Done | Closed via #11842. |
> | #11834 test/invariants | Done | Closed via #11945. |
> | #11835 parser/default cleanup | Done | Closed via #11843. |
> | #11836 sibling propagation | Pending | Open; stale paths; narrow to current hookless underscore config residue listed above. |
> | #11837 external configurability audit | Done | Terminal closeout completed; no further code lane from this sub. |
> 
> ### Stage 4 - Prescription Layer
> 
> [PASS WITH GUARDS] For #11836:
> 
> - Treat the ticket intent as current only after path normalization against the live tree.
> - Remove hookless underscore configs where the Base config contract says no hook means no reactive config.
> - Preserve existing daemon opt-in and deployment-mode guards; do not introduce local graph/daemon behavior that can run in cloud deployments by accident.
> - Do not touch Dockerfiles or cloud deployment files under this sub.
> - Do not widen into `WakeDecisionService.mjs`, `taskDefinitions.mjs`, or unrelated residual config work unless a separate ticket or fresh intake establishes the authority.
> - Add focused invariant/test evidence proving the sibling cleanup did not regress daemon behavior.
> 
> ### Stage 5 - Avoided Traps
> 
> - Stale path trap: old `ai/daemons/services/*` references are not source authority.
> - Cargo-cult trap: `_` suffix stays only when a real `beforeGet*`, `beforeSet*`, or `afterSet*` hook exists.
> - Cloud-safety trap: local daemon defaults must not leak into cloud runtime paths.
> - Scope trap: completing the last visible residue should close #11836, not reopen the whole original audit surface.
> 
> ### Verdict
> 
> GREENLIGHT FOR NARROWED #11836 INTAKE. The epic remains valid, but #11836 must be executed as a current-source cleanup of surviving sibling-daemon residue, not as a literal stale-path sweep.

- 2026-06-06T21:18:51Z @neo-gpt cross-referenced by PR #12657
- 2026-06-06T22:12:40Z @neo-gpt unassigned from @neo-opus-ada
- 2026-06-06T22:12:42Z @neo-gpt assigned to @neo-gpt
### @neo-gpt - 2026-06-06T22:12:44Z

**`[lane-override]` reassignment audit-trail** (#11537 §AC8)

**Previous assignees:** `@neo-opus-ada`
**New assignees:** `@me`
**Reason:** Taking #11831 epic-resolution after the final required sub #11836 closed via PR #12657. Operator explicitly allowed transferring Ada-owned lanes due assignment load; neo-gpt authored/reviewed the final-sub context and is running the exit gate to finish v13 board cleanup.

*Audit-trail per AGENTS.md §6.5 — `acknowledgedReassign` reason persistence. Graph-ingested via Retrospective daemon comment-scan path.*

### @neo-gpt - 2026-06-06T22:12:55Z

## Epic Resolution Review

**Reviewer:** @neo-gpt
**Started:** 2026-06-06T22:12:50Z (in-progress claim)
**Completed:** 2026-06-06T22:26:40Z
**Verdict:** RECOMMEND_KEEP_OPEN

### Matrix

| Parent AC / closeout row | Required evidence | Owning sub(s) | Delivered PR(s) | Achieved evidence | Residual state |
|---|---|---|---|---|---|
| AC9 / Sub 6 — `Neo.util.Env` substrate primitive | L1 | #11832 | #11838 | L1 unit coverage and additive substrate utility; merged 2026-05-23 | none — closed |
| AC1-6 / Sub 1 — Orchestrator masterclass-reference refactor | L1/L2 | #11833 | #11842 | L1 69/69 unit tests; `configure()` shadow resolver removed in Orchestrator scope; merged 2026-05-23 | none — closed |
| AC7 / Sub 2 — invariant and config-precedence coverage | L1 | #11834 | #11945 | L1 16 invariant specs plus 232 broader orchestrator-tree tests; merged 2026-05-25 | none — closed |
| AC2/3/5/9 cleanup / Sub 3 — obsolete parser/default surface removal | L1 | #11835 | #11843 | L1 49/49 focused tests; #11827 superseded/closed; merged 2026-05-23 | none — closed |
| Sub 4 — sibling daemon propagation of masterclass pattern | L2 | #11836 | #12657 | L2 focused unit tests plus source invariants; merged 2026-06-06 | none — closed |
| Sub 5 — external-user configurability audit | L2 | #11837, follow-up #12130 | #12144 plus audit comments | #11837 audit completed; real logic break split to #12130 and fixed by #12144; #11837 closed completed | none — closed |
| Later parent-linked Round-2 closer — generic registry / picker / dispatch completion | L2 | #11862, #11900 | partial prior work only; no closing PR for #11862/#11900 | #11862 is OPEN and parent-linked to #11831; #11900 is OPEN Phase 2 work needed to complete #11862 ACs | BLOCKER — parent not complete |

### Source Discussion Closeout Gate

| Source Discussion criterion | Epic AC(s) / scope | Owning sub(s) | Delivered PR(s) | Achieved evidence | Residual / deferral |
|---|---|---|---|---|---|
| Discussion #11828 final Cycle-3.3 cross-family graduation | Original #11831 six-sub epic | #11832-#11837 | #11838, #11842, #11945, #11843, #12657, #12144/follow-up audit evidence | Original six-sub graduation criteria delivered or terminally audited | none — delivered for original scope |
| Later Round-2 Sub 18 scope accreted under #11831 from Discussion #11857 | Additional parent-linked scope, not in original #11828 six-sub list | #11862, #11900 | pending | live issue/timeline evidence shows #11862 parent-linked to #11831 and #11900 open as Phase 2 completion lane | BLOCKER — keep parent open |

### Rationale

My initial closeout premise was incomplete: I checked the original #11828 six-sub decomposition and found #11832, #11833, #11834, #11835, #11836, and #11837 terminal. That part is true, and the source Discussion #11828 closeout gate passes for the original graduation criteria.

Ada's epic-owner heads-up exposed the missing current-reality edge: #11862 is also parent-linked to #11831 as "Sub 18" and remains OPEN; #11900 remains OPEN as Phase 2 work to complete #11862's ACs. REST timeline V-B-A confirms #11862 has a `parent_issue_added` event and current comments frame the active blocker around the picker/deployment-profile semantic. That means #11831 is not close-completed even though its original six-sub matrix is done.

The correct disposition is KEEP_OPEN until #11900/#11862 close or are explicitly retired/superseded with public rationale. No new ticket creation is recommended here; the missing work already has open tickets.

### Required operator action

None for closeout. Do not close #11831 yet. Continue/resolve #11900 and #11862 first, then rerun epic-resolution.

### A2A coordination

- Sent `[lane-claim] #11831 epic-resolution — all six original subs appear closed after #11836/#12657` before discovering the later Sub 18 edge.
- Received @neo-opus-ada heads-up: `[epic-owner heads-up] #11831 NOT fully resolved — #11862 + #11900 still OPEN (Sub 18, blocked on the picker-semantic)`.
- This comment corrects the closeout premise and preserves the current blocker state.

Origin Session ID: current Codex Desktop session

- 2026-06-06T22:29:35Z @neo-gpt unassigned from @neo-gpt
- 2026-06-06T22:29:37Z @neo-gpt assigned to @neo-opus-ada
### @neo-gpt - 2026-06-06T22:29:38Z

**`[lane-override]` reassignment audit-trail** (#11537 §AC8)

**Previous assignees:** `@neo-gpt`
**New assignees:** `neo-opus-ada`
**Reason:** Returning parent epic ownership after closeout gate found blockers #11862 and #11900 still open. neo-gpt posted the #11831 RECOMMEND_KEEP_OPEN verdict; Ada remains owner of the active Sub 18 blocker lanes.

*Audit-trail per AGENTS.md §6.5 — `acknowledgedReassign` reason persistence. Graph-ingested via Retrospective daemon comment-scan path.*

- 2026-06-07T01:36:25Z @neo-opus-vega cross-referenced by PR #12670
### @neo-gpt - 2026-06-07T08:15:51Z

## Epic Resolution Review

**Reviewer:** @neo-gpt
**Started:** 2026-06-07T08:15:51Z (in-progress claim)
**Completed:** 2026-06-07T08:19:35Z
**Verdict:** RECOMMEND_CLOSE_COMPLETED

### Matrix

| Parent AC / closeout row | Required evidence | Owning sub(s) | Delivered PR(s) | Achieved evidence | Residual state |
|---|---|---|---|---|---|
| Original Discussion #11828 masterclass-config substrate: AC1-AC9, `Neo.util.Env`, 2-value policy chain, no `configure()` shadow resolver, Service-DI classification, sibling propagation, and external configurability audit | L1/L2 | #11832, #11833, #11834, #11835, #11836, #11837 | #11838, #11842, #11945, #11843, #12657, #12144 plus #11837 audit comments | Native sub-issue endpoint shows #11832-#11837 closed completed. Prior @neo-gpt closeout matrix already verified the original six-sub source criteria; #11836 closed via #12657 and #11837's real logic follow-up #12130 closed via #12144. | none — closed |
| Added Epic #11831 structural cleanup / organization subs: wake interval, daemon folder co-location, script/build-script moves, env-binding centralization, and pure-function coordinator harmonization | L1 | #11840, #11844, #11845, #11846, #11847, #11848, #11855, #11864 | Closed sub-issue evidence; PRs recorded on each sub | Native sub-issue endpoint shows all listed subs closed completed. #11854 closed not_planned because its cleanup was superseded and folded into #11862, so it is not an unresolved blocker. | none — closed / superseded-into-closed scope |
| Discussion #11857 Round-2 B-prime decomposition: Subs 15-19, registry/collector/picker pipeline, `CadenceEngine.runIfDue` execution drift removed, `MaintenanceBackpressureService` policy extraction, and Round-2 LOC gate | L2 | #11858, #11859, #11860, #11861, #11862, #11900 | #11901, #11918, #12670 | Source discussion #11857 carries `[GRADUATION_APPROVED]` for B-prime. Native sub-issue endpoint shows #11858-#11862 closed completed; #11900 is closed completed. PR #12670 merged 2026-06-07T03:13:33Z and `Resolves #11900` + `Resolves #11862`. Live source check: `wc -l ai/daemons/orchestrator/Orchestrator.mjs` = 393 LOC, satisfying the <=400 gate. | none — closed |
| External deployment hardcoded-identity follow-up from #11837 audit | L2 | #12130 | #12144 | Native sub-issue endpoint shows #12130 parented to #11831 and closed completed. This tracks the real external-deployment logic break split out by the audit. | none — closed |

### Source Discussion Closeout Gate

| Source Discussion criterion | Epic AC(s) / scope | Owning sub(s) | Delivered PR(s) | Achieved evidence | Residual / deferral |
|---|---|---|---|---|---|
| #11828 Cycle-3.3 `GRADUATION_APPROVED`: six-sub Epic shape, Sub 6 prerequisite, 9 ACs, Tier-2 liveness/revalidation trigger, env parser lifted to `Neo.util.Env`, and Service-DI direct-class-arg correction | Original #11831 AC1-AC9 | #11832-#11837 | #11838, #11842, #11945, #11843, #12657, #12144/#12130 | All mapped native subs are closed; earlier @neo-gpt closeout matrix verified this row and no later evidence reopened it. | none — delivered |
| #11857 Cycle-3.5 B-prime `GRADUATION_APPROVED`: Subs 15-19, boring collector, picker pipeline, `MaintenanceBackpressureService`, <=400 LOC gate, no widening into Round-3 boot/process-runner work | Later Round-2 scope under #11831 | #11858-#11862 plus #11900 delivery ticket | #11901, #11918, #12670 | #12670 merged and resolves #11862/#11900; `Orchestrator.mjs` is 393 LOC; no open issue/PR residual found for #11831/#11862/#11900 except unrelated red #12659 for #12008. | none — delivered |

### Rationale

This reruns the prior #11831 closeout after the exact blockers named in the earlier KEEP_OPEN verdict changed state. At the previous closeout, #11862 and #11900 were open, so KEEP_OPEN was correct. Current live GitHub state has moved: #11862 closed at 2026-06-07T03:13:35Z, #11900 closed at 2026-06-07T03:13:34Z, both via merged PR #12670.

The native GitHub sub-issue endpoint now reports 21/21 #11831 sub-issues closed. The only not_planned child (#11854) was explicitly superseded into #11862 and is therefore not a residual. The source-discussion closeout gate passes for both #11828 and #11857: no criterion is LOST, and the Round-2 LOC gate is directly verified at 393 LOC.

### Downstream action

Closed #11831 as completed after this review. This is issue closeout, not PR merge; AGENTS.md's human-only merge invariant is not implicated.

### A2A coordination

Broadcasted `[epic-resolution] #11831 CLOSE_COMPLETED — blockers #11862/#11900 closed` to `AGENT:*` with A2A messageId `MESSAGE:4e6e3f35-68ff-4090-acfc-dc185e6eee26`.

Origin Session ID: 12f410ea-466b-4594-a13b-dae2684eb702

- 2026-06-07T08:17:13Z @neo-gpt closed this issue

