Resolves Sub-1 of Epic #11022.
Problem Statement
The Orchestrator daemon currently suffers from the fat-class problem, mutating raw task state directly. Before we extract the ProcessSupervisorService, we must invert the dependency order: we must first extract TaskStateService to lock the state-mutation boundary. If we extract the supervisor first against raw mutable state, the new service will inherit the exact anti-pattern we are trying to eliminate.
Proposed Prescription
Extract TaskStateService into ai/daemons/services/TaskStateService.mjs.
This new service will own:
- Mutation API:
markStarted, markSkipped, markCompleted, markFailed, adoptRunning, clearRecovered, getLastRunAt
- On-disk Persistence:
readState, writeState, createInitialTaskState
The Orchestrator will consume this service via the taskState_ reactive collaborator. No downstream service will mutate raw state directly; they will consume the TaskStateService API.
Substrate
- Location:
ai/daemons/services/TaskStateService.mjs
- Consumer: Orchestrator, ProcessSupervisorService (future extraction)
Acceptance Criteria
Avoided Traps
- ❌ Extract ProcessSupervisor first — this would bake in raw-state-mutation responsibility we're trying to remove.
TaskStateService must extract first.
- ❌ Change behavior — this is a pure refactor/extraction. The on-disk state schema and task behavior must remain identical.
Resolves Sub-1 of Epic #11022.
Problem Statement
The
Orchestratordaemon currently suffers from the fat-class problem, mutating raw task state directly. Before we extract theProcessSupervisorService, we must invert the dependency order: we must first extractTaskStateServiceto lock the state-mutation boundary. If we extract the supervisor first against raw mutable state, the new service will inherit the exact anti-pattern we are trying to eliminate.Proposed Prescription
Extract
TaskStateServiceintoai/daemons/services/TaskStateService.mjs.This new service will own:
markStarted,markSkipped,markCompleted,markFailed,adoptRunning,clearRecovered,getLastRunAtreadState,writeState,createInitialTaskStateThe Orchestrator will consume this service via the
taskState_reactive collaborator. No downstream service will mutate raw state directly; they will consume theTaskStateServiceAPI.Substrate
ai/daemons/services/TaskStateService.mjsAcceptance Criteria
TaskStateServiceNeo class is created atai/daemons/services/TaskStateService.mjs.OrchestratortoTaskStateService.TaskStateServicevia thetaskState_reactive config.TaskStateService.Avoided Traps
TaskStateServicemust extract first.