LearnNewsExamplesServices
Frontmatter
id11900
titleSub 18 Phase 2: CadenceEngine.runIfDue drop + dispatch switch + Sub-13 cleanup + test collapse
stateClosed
labels
enhancementairefactoringarchitecture
assigneesneo-gpt
createdAtMay 24, 2026, 3:09 PM
updatedAtJun 7, 2026, 5:13 AM
githubUrlhttps://github.com/neomjs/neo/issues/11900
authorneo-opus-ada
commentsCount3
parentIssuenull
subIssues[]
subIssuesCompleted0
subIssuesTotal0
blockedBy[]
blocking[]
closedAtJun 7, 2026, 5:13 AM

Sub 18 Phase 2: CadenceEngine.runIfDue drop + dispatch switch + Sub-13 cleanup + test collapse

Closed v13.0.0/archive-v13-0-0-chunk-13 enhancementairefactoringarchitecture
neo-opus-ada
neo-opus-ada commented on May 24, 2026, 3:09 PM

Context

Follow-up to PR #11899 (Sub 18 Phase 1: scaffolding + MBS wiring). Phase 1 split off the substrate-evolution foundation (registry + collector + picker primitives + MaintenanceBackpressureService activation) and shipped under a focused PR. Phase 2 ships the dispatch switchover + cleanup (mechanical work consuming the foundation) to complete ticket #11862 ACs.

This sub-ticket is a delivery-shape adjustment: Phase 1/2 split was operator-velocity-pushback-driven course correction from #11862's monolithic 5-commit Plan agent prescription. Substantive direction unchanged; mechanical execution staged for reviewer-side clarity + ship-velocity recovery.

The Problem

#11862 ACs not satisfied by PR #11899:

  • AC1 (partial): CadenceEngine.runIfDue still has the executeFn parameter; pure-trigger-builder refactor per v13-path.md:117 / #11025 spec is incomplete.
  • AC2: Orchestrator.mjs currently 611 LOC (was 892); target ≤400 LOC requires Phase 2 dispatch switch + Sub-13 cleanup.
  • AC3: 13 mock-heavy Orchestrator.spec.mjs tests still present; per-module collapse pending.
  • AC6: Sub-13 cleanup (strip class @summary historical narrative + section divider comments "=== Service-DI Class A/B/C/D ===") pending.

Phase 1's per-poll MBS binding refresh is a defensive substrate idiom that should be revisited during Phase 2 — once cadenceEngine.runIfDue is dropped + dispatch becomes a single collect → pick → execute pipeline, the per-poll refresh location can be evaluated for consolidation OR replacement with per-prop afterSet hooks.

Architectural Reality

PR #11899 Phase 1 lands:

  • ai/daemons/orchestrator/scheduling/registry.mjs — 7 frozen coordinator descriptors
  • ai/daemons/orchestrator/scheduling/collector.mjscollectDueCandidates pure function
  • ai/daemons/orchestrator/scheduling/picker.mjspickNextCandidate pure function with 3-stage pipeline
  • 3 spec files (23 tests)
  • Orchestrator.mjs (892 → 611 LOC) — MBS wiring + 11 method deletes + Class B propagation

Phase 2 consumes Phase 1's primitives:

  • poll() body currently has 7 this.cadenceEngine.runIfDue(taskName, dueCheckFn, executeMaintenanceTask(executeFn), context) blocks
  • Phase 2 replaces these with the 3-line pipeline:
      const {candidates, errors} = collectDueCandidates({registry: TASK_REGISTRY, context: this.buildContext()});
    // ... orchestrator-side error reporting from errors ...
    const winner = pickNextCandidate({candidates, runningTasks, policyContext: this.buildPolicyContext()});
    if (winner) await this.execute(winner);
  • Add execute(winner) method with 4-key dispatch map (supervised-child-processrunViaProcessSupervisor; service-runner → primary-dev-sync runner; in-process-async → dream/golden-path/swarm-heartbeat envelope)
  • Delete cadenceEngine.runIfDue from CadenceEngine.mjs + its dedicated tests
  • Class @summary strip: lines 95-141 of current Orchestrator.mjs ("Service-DI 4-way classification" + "No configure(). No DEFAULT_X_*_MS" trailer) → compact 4-line @summary
  • Section divider comments: 4-6 "=== Service-DI Class A/B/C/D ===" comments removed

The Fix

5-commit sequence (each independently green per Plan agent design from #11862):

  1. C3: Switch dispatch from cadenceEngine.runIfDue to collect → pick → execute pipeline. Add execute(winner) method with 4-key dispatch map. Delete cadenceEngine.runIfDue + 3 dedicated tests in CadenceEngine.spec. Orchestrator drops to ~430 LOC.
  2. C4: Sub-13 cleanup. Strip class @summary historical narrative (lines 95-141, ~46 LOC). Remove 4-6 section divider comments. Replace with compact 4-line @summary citing scheduling/registry.mjs for descriptor model. Orchestrator drops to ~400 LOC (AC2 hit).
  3. C5: Collapse 13 mock-heavy Orchestrator.spec.mjs tests (lines 142-413 per pre-#11862 grep). Keep 4-5 integration smoke tests through real registry+picker+MBS pipeline (one per executionKind). Test count drops from 22 → ~9 in Orchestrator.spec.mjs.

Per-poll MBS binding refresh (from PR #11899 Phase 1) re-evaluation: after C3 collapses the 7 runIfDue blocks into single 3-line pipeline, the per-poll refresh can either stay (defensive idiom; covers future test-bypass-start cases) OR migrate to a single afterSetWriteLog hook (cleaner but more code). Recommend stay-as-is unless review surfaces alternative.

Acceptance Criteria

  • AC1: cadenceEngine.runIfDue parameter executeFn dropped per v13-path.md:117 / #11025; signature becomes runIfDue(taskName, dueCheckFn, context) returning trigger or null. OR runIfDue deleted entirely if Phase 2 dispatch shape doesn't need a trigger-builder layer (collector calls descriptor.getDueTask directly).
  • AC2: Orchestrator.mjs ≤ 400 LOC post-Phase-2 merge.
  • AC3: 13 mock-heavy Orchestrator.spec.mjs tests collapsed; 4-5 integration smoke tests retained (one per executionKind + 1 lease-cross-daemon E2E).
  • AC4 (PR #11899 retained): collectDueCandidates causes no observable state mutation — NEGATIVE test in collector.spec.mjs already enforces.
  • AC5 (PR #11899 retained): collectDueCandidates contains no switch(profile) policy body — source-text guardrail test in collector.spec.mjs already enforces.
  • AC6: Sub-13 cleanup folded in — class @summary stripped of "Service-DI 4-way classification" historical narrative + "No configure(). No DEFAULT_X_*_MS" trailer + 4-6 Class A/B/C/D section divider comments.
  • AC7 (PR #11899 retained): poll() calls MaintenanceBackpressureService.acquireLeaseAndExecute({...}) and .executeWithGoldenPathDependencyGate({...}) — already wired in Phase 1.
  • AC8: Phase 2 PR body includes before/after Orchestrator.mjs LOC count + Orchestrator.spec.mjs test count for mechanical AC2 / AC3 verification.

Out of Scope

  • No further Orchestrator splitting beyond ≤400 LOC target (Round-3 evaluation deferred to post-measurement per Plan agent design from #11862).
  • No bootstrap split (deferred to Round-3).
  • No new abstractions beyond the dispatch map (the existing registry primitives are the substrate).

Avoided Traps

  • ❌ Re-implementing per-poll MBS binding refresh logic (PR #11899 idiom should stay until proven unnecessary).
  • ❌ Adding more reactive parent-prop afterSet hooks (the per-poll refresh covers more cases for less code — substrate-lesson banked in PR #11899 commit 85e6b4928).
  • ❌ Breaking the runIfDue API mid-poll (atomic single-commit replacement preserves test green throughout).
  • ❌ Aggressive test removal beyond the 13 mock-heavy identified ones (keeps integration smoke coverage).

Depends on

PR #11899 (Sub 18 Phase 1) — must merge first to ship Phase 1 primitives that Phase 2 consumes.

Related

  • #11862 (parent — partially-resolved by PR #11899 Phase 1)
  • Epic #11831 (parent epic — Orchestrator Round-2 closure)
  • Discussion #11857 (origination)
  • PR #11899 (Phase 1 implementation)
  • Sub 19 #11861 (MaintenanceBackpressureService — merged, activated in Phase 1)

Origin Session ID: ba62643a-ae78-41b2-9ce5-e7890155760b

Handoff Retrieval Hints:

  • Query Memory Core for Sub 18 Phase 1 PR #11899 scaffolding MBS wiring per-poll refresh
  • Query Memory Core for Sub 18 Plan agent 5-commit design
  • Branch: tobiu/11862-orchestrator-sub-18 continues here after Phase 1 merge

Authored by: Claude Opus 4.7 (Claude Code)

tobiu referenced in commit 26ef267 - "feat(orchestrator): wire MBS via Class B propagation + applyBindings dual-pattern (#11900) (#11918) on May 24, 2026, 9:44 PM
tobiu referenced in commit 15eba86 - "feat(orchestrator): consume registry dispatch pipeline (#11900) (#12670) on Jun 7, 2026, 5:13 AM
tobiu closed this issue on Jun 7, 2026, 5:13 AM