Context
First-real-world cloud-deployment exercise (external operator authoring an ai/deploy-canonical-mirror compose stack) surfaced that PR #11844 (Sub 8: Orchestrator-cluster co-location ai/scripts/orchestrator-daemon.mjs → ai/daemons/orchestrator/daemon.mjs) merged with three stale references to the pre-refactor entrypoint path. Tests pass and CI is green for the canonical neo checkout, but the cloud-profile container build is currently unbuildable from ai/deploy/docker-compose.yml as-published, and post-crash self-recovery of the running daemon is broken under the new filename.
The drift is mechanical follow-up, not architectural — ai/daemons/orchestrator/ is the correct location per ADR 0014 implementation. The fix is path-aligning the three downstream consumers.
The Problem
PR #11844 relocated the orchestrator daemon and made Orchestrator.mjs / daemon.mjs substantially lighter. Three references to the pre-refactor path ai/scripts/orchestrator-daemon.mjs were not updated:
Compose entrypoint — ai/deploy/docker-compose.yml:137 passes SERVICE_ENTRYPOINT: ai/scripts/orchestrator-daemon.mjs to the canonical ai/deploy/Dockerfile. The build stage proceeds (Dockerfile does not stat the path), but the resulting container CMD references a non-existent file, so the orchestrator service is unbuildable end-to-end under --profile cloud. Verified empirically against dev HEAD (test -f ai/scripts/orchestrator-daemon.mjs returns false).
Self-detection regex — ai/daemons/orchestrator/daemon.mjs:98 reads if (cmd.includes('orchestrator-daemon.mjs')) for stale-PID detection during crash recovery. The new entrypoint filename is daemon.mjs, so a crash-recovered process whose cmd line contains only daemon.mjs will fail self-detection. Tests do not exercise the crash-recovery path against the new filename (CI green is consistent with this gap).
JSDoc @module paths — ai/daemons/orchestrator/daemon.mjs:2 cites @module ai/scripts/orchestrator-daemon; Orchestrator.mjs:108,150 JSDoc prose cites ai/scripts/orchestrator-daemon.mjs in @see and inline-prose form. Documentation drift only — not a build break — but mis-routes any future reader following the @module path.
The Architectural Reality
Affected files (verified at dev HEAD):
ai/deploy/docker-compose.yml:137 — build arg.
ai/daemons/orchestrator/daemon.mjs:2 — module-level JSDoc.
ai/daemons/orchestrator/daemon.mjs:36-37 — DAEMON_DATA_DIR + PID_FILE derivation is correct (writes to .neo-ai-data/orchestrator-daemon/, preserves the existing data-dir contract).
ai/daemons/orchestrator/daemon.mjs:98 — self-detection regex.
ai/daemons/orchestrator/Orchestrator.mjs:2,108,150 — module + class-level JSDoc references.
The .neo-ai-data/orchestrator-daemon/state.json path used by the canonical healthcheck in docker-compose.yml:179 is still correct — the data-dir contract was preserved by the refactor; only the entry-point filename moved.
The Fix
ai/deploy/docker-compose.yml:137: replace SERVICE_ENTRYPOINT: ai/scripts/orchestrator-daemon.mjs with SERVICE_ENTRYPOINT: ai/daemons/orchestrator/daemon.mjs.
ai/daemons/orchestrator/daemon.mjs:98: update the self-detect regex to match the new filename. Recommend matching the path-tail ai/daemons/orchestrator/daemon.mjs (more specific than bare daemon.mjs, which would collide with sibling daemons under ai/daemons/{bridge,kb-gc,kb-reconciliation,kb-alerting}/).
ai/daemons/orchestrator/{daemon,Orchestrator}.mjs JSDoc: replace ai/scripts/orchestrator-daemon / .mjs with ai/daemons/orchestrator/daemon / .mjs at the cited lines.
Contract Ledger
| Target Surface |
Source of Authority |
Proposed Behavior |
Fallback |
Docs |
Evidence |
ai/deploy/docker-compose.yml:137 SERVICE_ENTRYPOINT arg |
ai/deploy/Dockerfile SERVICE_ENTRYPOINT ARG |
Path-corrected to ai/daemons/orchestrator/daemon.mjs |
None — build break is a fatal config error, not a soft fallback |
ai/deploy/Dockerfile:35 comment already cites the correct new-path style; align the live arg with the comment |
Current file absence verified via test -f ai/scripts/orchestrator-daemon.mjs; PR #11844 git history confirms move |
ai/daemons/orchestrator/daemon.mjs:98 self-detect regex |
Sibling-daemon naming convention (ai/daemons/{bridge,kb-gc,kb-reconciliation,kb-alerting}/daemon.mjs) |
Match the orchestrator-specific path-tail to avoid sibling collision |
Conservative substring match on ai/daemons/orchestrator/daemon.mjs |
Inline-comment the chosen scope width |
Crash-recovery branch not currently spec-covered for the new filename (consistent with green CI + broken-in-practice state) |
ai/daemons/orchestrator/{daemon,Orchestrator}.mjs @module + @see |
learn/agentos/decisions/0014-cloud-deployment-topology-and-scheduler-task-taxonomy.md (ADR-aligned new location) |
Cite ai/daemons/orchestrator/daemon.mjs consistently |
None — pure docs drift |
None |
grep -rn 'ai/scripts/orchestrator-daemon' ai/daemons/ enumerates current matches |
Decision Record impact
aligned-with ADR 0014 — implementation cleanup under existing authority. No ADR successor risk; ADR 0014 already describes the post-refactor topology.
Acceptance Criteria
Out of Scope
- Changes to the post-refactor data-dir contract (
.neo-ai-data/orchestrator-daemon/) — preserved intentionally by #11844.
- Sibling-daemon JSDoc audits (
ai/daemons/{bridge,kb-gc,kb-reconciliation,kb-alerting}/). Likely warrant the same sweep; file as a separate sub if confirmed.
- Cloud-profile compose changes beyond the entrypoint path (resource limits, healthcheck cadence, profile gating, etc.).
Avoided Traps
- Splitting into three tickets per stale surface — rejected; all three stem from the same
mv semantics and a single agent can address them in one PR.
- Generic bare
daemon.mjs regex in the self-detect — rejected for collision risk with ai/daemons/{bridge,kb-gc,kb-reconciliation,kb-alerting}/daemon.mjs.
Related
- PR #11844 (originating refactor — orchestrator-cluster co-location).
- PR #11849 (dev merge of #11844).
- ADR 0014 (cloud-deployment topology — substrate authority).
- Sibling sub-daemon refactor #11845 (potentially affected by analogous drift — sweep recommended).
Handoff Retrieval Hints
- Git anchor:
git log --oneline 6cc917980 f81d18968 -- ai/daemons/orchestrator/ brackets the #11844 merge.
- Semantic query: "orchestrator daemon co-location stale path references" / "docker-compose SERVICE_ENTRYPOINT orchestrator".
- Grep:
grep -rn 'ai/scripts/orchestrator-daemon' ai/ learn/ enumerates current matches; the ticket targets driving this to zero.
Context
First-real-world cloud-deployment exercise (external operator authoring an
ai/deploy-canonical-mirror compose stack) surfaced that PR #11844 (Sub 8: Orchestrator-cluster co-location ai/scripts/orchestrator-daemon.mjs → ai/daemons/orchestrator/daemon.mjs) merged with three stale references to the pre-refactor entrypoint path. Tests pass and CI is green for the canonical neo checkout, but the cloud-profile container build is currently unbuildable fromai/deploy/docker-compose.ymlas-published, and post-crash self-recovery of the running daemon is broken under the new filename.The drift is mechanical follow-up, not architectural —
ai/daemons/orchestrator/is the correct location per ADR 0014 implementation. The fix is path-aligning the three downstream consumers.The Problem
PR #11844 relocated the orchestrator daemon and made
Orchestrator.mjs/daemon.mjssubstantially lighter. Three references to the pre-refactor pathai/scripts/orchestrator-daemon.mjswere not updated:Compose entrypoint —
ai/deploy/docker-compose.yml:137passesSERVICE_ENTRYPOINT: ai/scripts/orchestrator-daemon.mjsto the canonicalai/deploy/Dockerfile. The build stage proceeds (Dockerfile does not stat the path), but the resulting container CMD references a non-existent file, so theorchestratorservice is unbuildable end-to-end under--profile cloud. Verified empirically against dev HEAD (test -f ai/scripts/orchestrator-daemon.mjsreturns false).Self-detection regex —
ai/daemons/orchestrator/daemon.mjs:98readsif (cmd.includes('orchestrator-daemon.mjs'))for stale-PID detection during crash recovery. The new entrypoint filename isdaemon.mjs, so a crash-recovered process whosecmdline contains onlydaemon.mjswill fail self-detection. Tests do not exercise the crash-recovery path against the new filename (CI green is consistent with this gap).JSDoc
@modulepaths —ai/daemons/orchestrator/daemon.mjs:2cites@module ai/scripts/orchestrator-daemon;Orchestrator.mjs:108,150JSDoc prose citesai/scripts/orchestrator-daemon.mjsin@seeand inline-prose form. Documentation drift only — not a build break — but mis-routes any future reader following the@modulepath.The Architectural Reality
Affected files (verified at dev HEAD):
ai/deploy/docker-compose.yml:137— build arg.ai/daemons/orchestrator/daemon.mjs:2— module-level JSDoc.ai/daemons/orchestrator/daemon.mjs:36-37—DAEMON_DATA_DIR+PID_FILEderivation is correct (writes to.neo-ai-data/orchestrator-daemon/, preserves the existing data-dir contract).ai/daemons/orchestrator/daemon.mjs:98— self-detection regex.ai/daemons/orchestrator/Orchestrator.mjs:2,108,150— module + class-level JSDoc references.The
.neo-ai-data/orchestrator-daemon/state.jsonpath used by the canonical healthcheck indocker-compose.yml:179is still correct — the data-dir contract was preserved by the refactor; only the entry-point filename moved.The Fix
ai/deploy/docker-compose.yml:137: replaceSERVICE_ENTRYPOINT: ai/scripts/orchestrator-daemon.mjswithSERVICE_ENTRYPOINT: ai/daemons/orchestrator/daemon.mjs.ai/daemons/orchestrator/daemon.mjs:98: update the self-detect regex to match the new filename. Recommend matching the path-tailai/daemons/orchestrator/daemon.mjs(more specific than baredaemon.mjs, which would collide with sibling daemons underai/daemons/{bridge,kb-gc,kb-reconciliation,kb-alerting}/).ai/daemons/orchestrator/{daemon,Orchestrator}.mjsJSDoc: replaceai/scripts/orchestrator-daemon/.mjswithai/daemons/orchestrator/daemon/.mjsat the cited lines.Contract Ledger
ai/deploy/docker-compose.yml:137SERVICE_ENTRYPOINTargai/deploy/DockerfileSERVICE_ENTRYPOINTARGai/daemons/orchestrator/daemon.mjsai/deploy/Dockerfile:35comment already cites the correct new-path style; align the live arg with the commenttest -f ai/scripts/orchestrator-daemon.mjs; PR #11844 git history confirms moveai/daemons/orchestrator/daemon.mjs:98self-detect regexai/daemons/{bridge,kb-gc,kb-reconciliation,kb-alerting}/daemon.mjs)ai/daemons/orchestrator/daemon.mjsai/daemons/orchestrator/{daemon,Orchestrator}.mjs@module+@seelearn/agentos/decisions/0014-cloud-deployment-topology-and-scheduler-task-taxonomy.md(ADR-aligned new location)ai/daemons/orchestrator/daemon.mjsconsistentlygrep -rn 'ai/scripts/orchestrator-daemon' ai/daemons/enumerates current matchesDecision Record impact
aligned-with ADR 0014— implementation cleanup under existing authority. No ADR successor risk; ADR 0014 already describes the post-refactor topology.Acceptance Criteria
ai/deploy/docker-compose.yml:137SERVICE_ENTRYPOINTpoints atai/daemons/orchestrator/daemon.mjs.ai/daemons/orchestrator/daemon.mjs:98self-detection matches the new filename without colliding with sibling daemons.ai/daemons/orchestrator/daemon.mjs:2@modulecitesai/daemons/orchestrator/daemon.ai/daemons/orchestrator/Orchestrator.mjs:2,108,150JSDoc references citeai/daemons/orchestrator/daemon.mjs.docker compose -f ai/deploy/docker-compose.yml --profile cloud buildsucceeds against dev HEAD (regression guard for the entrypoint fix).ai/scripts/orchestrator-daemonremain (post-merge-only check).Out of Scope
.neo-ai-data/orchestrator-daemon/) — preserved intentionally by #11844.ai/daemons/{bridge,kb-gc,kb-reconciliation,kb-alerting}/). Likely warrant the same sweep; file as a separate sub if confirmed.Avoided Traps
mvsemantics and a single agent can address them in one PR.daemon.mjsregex in the self-detect — rejected for collision risk withai/daemons/{bridge,kb-gc,kb-reconciliation,kb-alerting}/daemon.mjs.Related
Handoff Retrieval Hints
git log --oneline 6cc917980 f81d18968 -- ai/daemons/orchestrator/brackets the #11844 merge.grep -rn 'ai/scripts/orchestrator-daemon' ai/ learn/enumerates current matches; the ticket targets driving this to zero.