LearnNewsExamplesServices
Frontmatter
id11051
title[ai] Extract CadenceEngine from Orchestrator (M3.5 Sub-3)
stateClosed
labels
enhancementai
assigneesneo-gemini-3-1-pro
createdAtMay 9, 2026, 10:12 PM
updatedAtMay 9, 2026, 11:19 PM
githubUrlhttps://github.com/neomjs/neo/issues/11051
authorneo-gemini-3-1-pro
commentsCount0
parentIssue11022
subIssues[]
subIssuesCompleted0
subIssuesTotal0
blockedBy[]
blocking[]
closedAtMay 9, 2026, 11:19 PM

[ai] Extract CadenceEngine from Orchestrator (M3.5 Sub-3)

Closedenhancementai
neo-gemini-3-1-pro
neo-gemini-3-1-pro commented on May 9, 2026, 10:12 PM

Parent Epic: #11022 (M3.5 Orchestrator Decomposition)

Context

As part of the M3.5 Orchestrator decomposition, we have successfully extracted TaskStateService (Sub-1) and ProcessSupervisorService (Sub-2). The next step is Sub-3: CadenceEngine extraction.

Currently, interval polling logic and cadence parsing (shouldRunIntervalTask, parseInterval, and boilerplate cycle-run logic) are tightly coupled inside ai/daemons/Orchestrator.mjs. We need to extract this into a dedicated CadenceEngine service.

Per OQ8 resolution in Discussion #11025, CadenceEngine must be a pure trigger-builder, NOT an execute-runner. It exposes a primitive like getIntervalTrigger({taskName, now, lastRunAt, intervalMs, reasonPrefix}).

Execution Plan

  1. Target: Extract interval/cadence logic from ai/daemons/Orchestrator.mjs into ai/daemons/services/CadenceEngine.mjs.
  2. Boundary: CadenceEngine returns a trigger object (or null if not due). It does not execute the task. Per-task coordinators decide "what work is due" by composing this primitive; the supervisor executes; the orchestrator wires.
  3. Tests: Implement unit tests for CadenceEngine.spec.mjs covering interval parsing and trigger boundary conditions. Remove corresponding redundant tests from Orchestrator.spec.mjs while maintaining behavior.

Avoided Traps

  • Making CadenceEngine an execute-runner: Doing a runIfDue shape would make CadenceEngine a mini-Orchestrator and violates OQ8.
  • Direct state mutation: The trigger object will be passed down to ProcessSupervisor, which consumes TaskStateService for state updates.

Acceptance Criteria

  • ai/daemons/services/CadenceEngine.mjs implemented as a pure trigger-builder.
  • Orchestrator no longer contains parseInterval and shouldRunIntervalTask.
  • CadenceEngine.spec.mjs authored and passing.
tobiu closed this issue on May 9, 2026, 11:19 PM
tobiu referenced in commit 6dfad62 - "refactor(ai): extract CadenceEngine from Orchestrator (#11051) (#11059) on May 9, 2026, 11:19 PM