Authored by Claude Opus 4.7 (Claude Code). Session 5572d9a5-558d-4bea-b416-e31496c289c4.
FAIR-band: in-band [verify @ merge-gate]
Resolves #11858
Summary
Sub 15 of Epic #11831 — first of three coordinator extractions in Discussion #11857 Cycle-3.5 B-prime convergence (GPT [GRADUATION_APPROVED] DC_kwDODSospM4BA-... + operator architectural ratify). Matches D3.1 boundary per learn/agentos/v13-path.md:117: per-task coordinators decide what work is due; orchestrator wires; ProcessSupervisor executes.
Evidence: L1 (8/8 pure-function unit tests pass) → L1 required for pure extraction (no behavioral change at orchestrator surface; new service is not wired in this Sub — Sub 18 #11862 owns the registry integration).
Changes
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
Creates test/playwright/unit/ai/daemons/orchestrator/services/DreamCoordinatorService.spec.mjs (8 pure-function tests).
Strict boundary preserved (per Discussion #11857 Avoided Traps)
DreamService retains processUndigestedSessions() and all execution-side methods unchanged
- Coordinator owns due-trigger selection ONLY (D3.1 boundary)
- No state writes / no
markStarted / markCompleted / recordTaskOutcome calls
- No reactive-config-aliased wrapper around
DreamService (Sub-1 anti-pattern at new layer explicitly avoided)
- Orchestrator's
scheduleDreamCycle() body unchanged in this Sub; Sub 18 #11862 wires the new coordinator into the registry
Test Evidence
npm run test-unit -- test/playwright/unit/ai/daemons/orchestrator/services/DreamCoordinatorService.spec.mjs → 8/8 pass (587ms)
Test coverage:
- Interval-elapsed boundary: returns trigger when
now - lastRunAt >= intervalMs
- Interval-not-elapsed: returns null
- Disabled (
intervalMs <= 0): returns null for 0 and negative
- Exactly-equal-to-interval edge: returns trigger (≥ boundary)
- Reason carries interval verbatim (for telemetry/audit)
getDueTask wraps buildDreamTrigger correctly with state mapping
getDueTask handles missing state gracefully (lastRunAt defaults to 0)
getDueTask returns null when state.lastRunAt is recent
Post-Merge Validation
Deltas from ticket
None — implementation matches #11858 ACs verbatim.
Depends on
Epic #11831 (parent). Independent of Subs 16/17/19 (parallel-safe extractions).
Unblocks
Sub 18 #11862 (wire-up needs all 3 coordinators registered).
Authority chain
Discussion #11857 Cycle-3.5 GPT [GRADUATION_APPROVED] (DC_kwDODSospM4BA-...) + operator architectural ratify in-session 2026-05-23.
Per @tobiu's "you and me" instruction for Epic #11831 lane: no peer-review broadcast.
Authored by Claude Opus 4.7 (Claude Code). Session 5572d9a5-558d-4bea-b416-e31496c289c4.
FAIR-band: in-band [verify @ merge-gate]
Resolves #11858
Summary
Sub 15 of Epic #11831 — first of three coordinator extractions in Discussion #11857 Cycle-3.5 B-prime convergence (GPT
[GRADUATION_APPROVED]DC_kwDODSospM4BA-... + operator architectural ratify). Matches D3.1 boundary perlearn/agentos/v13-path.md:117: per-task coordinators decide what work is due; orchestrator wires; ProcessSupervisor executes.Evidence: L1 (8/8 pure-function unit tests pass) → L1 required for pure extraction (no behavioral change at orchestrator surface; new service is not wired in this Sub — Sub 18 #11862 owns the registry integration).
Changes
Creates
ai/daemons/orchestrator/services/DreamCoordinatorService.mjs:buildDreamTrigger({now, lastRunAt, intervalMs})returns{taskName, source, reason}ornullDreamCoordinatorService.getDueTask({state, now, dreamIntervalMs})wraps the pure function with state-shape mappingSummarizationCoordinatorService.getDueTask({...})precedent shapeCreates
test/playwright/unit/ai/daemons/orchestrator/services/DreamCoordinatorService.spec.mjs(8 pure-function tests).Strict boundary preserved (per Discussion #11857 Avoided Traps)
DreamServiceretainsprocessUndigestedSessions()and all execution-side methods unchangedmarkStarted/markCompleted/recordTaskOutcomecallsDreamService(Sub-1 anti-pattern at new layer explicitly avoided)scheduleDreamCycle()body unchanged in this Sub; Sub 18 #11862 wires the new coordinator into the registryTest Evidence
npm run test-unit -- test/playwright/unit/ai/daemons/orchestrator/services/DreamCoordinatorService.spec.mjs→ 8/8 pass (587ms)Test coverage:
now - lastRunAt >= intervalMsintervalMs <= 0): returns null for0and negativegetDueTaskwrapsbuildDreamTriggercorrectly with state mappinggetDueTaskhandles missing state gracefully (lastRunAt defaults to 0)getDueTaskreturns null when state.lastRunAt is recentPost-Merge Validation
Deltas from ticket
None — implementation matches #11858 ACs verbatim.
Depends on
Epic #11831 (parent). Independent of Subs 16/17/19 (parallel-safe extractions).
Unblocks
Sub 18 #11862 (wire-up needs all 3 coordinators registered).
Authority chain
Discussion #11857 Cycle-3.5 GPT
[GRADUATION_APPROVED](DC_kwDODSospM4BA-...) + operator architectural ratify in-session 2026-05-23.Per @tobiu's "you and me" instruction for Epic #11831 lane: no peer-review broadcast.