LearnNewsExamplesServices
Frontmatter
title>-
authorneo-opus-ada
stateMerged
createdAtMay 23, 2026, 10:57 PM
updatedAtMay 23, 2026, 11:04 PM
closedAtMay 23, 2026, 11:04 PM
mergedAtMay 23, 2026, 11:04 PM
branchesdevtobiu/11860-scheduling-batch-goldenpath-and-harmonize
urlhttps://github.com/neomjs/neo/pull/11866
Merged
neo-opus-ada
neo-opus-ada commented on May 23, 2026, 10:57 PM

Authored by Claude Opus 4.7 (Claude Code). Session 5572d9a5-558d-4bea-b416-e31496c289c4.

FAIR-band: in-band [verify @ merge-gate]

Resolves #11860 (Sub 17) Partial #11864 (Sub 20 — additive half; destructive half folds into Sub 18 #11862)

Summary

Combined PR per @tobiu's CI-efficiency framing on PR #11865: 1-sub-per-PR is right for risky work, pure CI tax for near-identical mechanical extractions. 4 new scheduling/<task>.mjs pure-function modules + their specs land in one CI round instead of four (4×7min integration = 28min saved).

Additive only. Does NOT touch Orchestrator, does NOT delete the old class files, does NOT modify PrimaryRepoSyncService. The wire-up shift (Orchestrator imports + call sites + old-class deletions + PrimaryRepoSync trim) is Sub 18 #11862's atomic scope (registry + collectDueCandidates + pickNextCandidate + CadenceEngine correction). Keeping this PR additive reduces risk + matches Sub 18's planned wire-up scope.

Evidence: L1 (29/29 specs pass across all 6 scheduling/ files — 4 new + 2 from Subs 15/16) → L1 required for pure-function extraction (no behavioral change at orchestrator surface; new files not wired in this PR).

New files (4 source + 4 spec)

  • ai/daemons/orchestrator/scheduling/goldenPath.mjs (Sub 17 — pure interval projection)
  • ai/daemons/orchestrator/scheduling/summary.mjs (Sub 20 — buildSummaryTrigger + getDueTask with sunset-handover priority + onSuccess hook for mark-read)
  • ai/daemons/orchestrator/scheduling/backup.mjs (Sub 20 — buildBackupTrigger + getDueTask)
  • ai/daemons/orchestrator/scheduling/primaryDevSync.mjs (Sub 20 — buildPrimaryRepoSyncTrigger + getDueTask with enabled-gate)

Sub-15 / Sub-16 KISS lessons applied from the start

  • Pure functions (no class extends Base, no singleton: true, no Neo.setupClass, no Neo.gatekeep)
  • One JSDoc block per function (no file-level + function-level split)
  • No decay-prone references (no v13-path.md:N, no section labels like D3.1, no neighboring-file method names)
  • Specs don't import Neo bootstrap (no module-load gatekeep call requiring globalThis.Neo)

Earned vs not-earned buildTrigger separate exports

summary.mjs IS the one earning the buildTrigger + getDueTask split — getDueTask does meaningful extra work (calls getUnreadSunsetHandoversFn(db) + attaches onSuccess mark-read closure). backup.mjs + primaryDevSync.mjs follow the same shape for consistency + to keep the test-seam pattern (overridable getUnreadSunsetHandoversFn / markNodesAsReadFn). goldenPath.mjs has only getDueTask (no extra work to warrant the split — matches dream.mjs precedent).

Test Evidence

npm run test-unit -- test/playwright/unit/ai/daemons/orchestrator/scheduling/29/29 pass (691ms)

Per-file:

  • dream.spec.mjs (existing from Sub 15) — 4 tests
  • swarmHeartbeat.spec.mjs (existing from Sub 16) — 4 tests
  • goldenPath.spec.mjs (new) — 4 tests (interval-elapsed / not-elapsed / disabled / missing-state)
  • summary.spec.mjs (new) — 6 tests (handover priority / periodic-sweep / disabled / getDueTask wrap / sunset-handover with onSuccess)
  • backup.spec.mjs (new) — 5 tests (buildTrigger boundaries + getDueTask state mapping)
  • primaryDevSync.spec.mjs (new) — 6 tests (enabled gate + interval / state mapping by PRIMARY_DEV_SYNC_TASK_NAME)

Sub 18 #11862 scope expanded to include the destructive half

Sub 18 (Round-2 closer) now also owns:

  • Delete services/SummarizationCoordinatorService.mjs + services/BackupCoordinatorService.mjs
  • Trim services/PrimaryRepoSyncService.mjs (remove buildPrimaryRepoSyncTrigger + getDueTask method; keep runTask + sync logic + class — the 803-LOC service has earned its Service shape via substantive runTask state/I/O)
  • Update Orchestrator imports + call sites to consume scheduling/<task>.mjs directly
  • Remove now-stale this.summarizationCoordinator + this.backupCoordinator instance fields

Post-Merge Validation

  • No behavioral change observable in orchestrator boot or scheduling (additive only; new files not wired)
  • Sub 18 #11862 cleanly imports the new files post-merge

Deltas from tickets

  • Sub 20 #11864 originally planned to do BOTH the additive (new scheduling/ files) AND destructive (delete old + Orchestrator update) work in one PR. Splitting: this PR does additive; Sub 18 absorbs destructive. Atomic risk surface per sub.
  • File location uses scheduling/<task>.mjs (no Service/Coordinator suffix) per @tobiu's KISS feedback on PR #11863. Sub 17 / Sub 20 ticket titles still use ...CoordinatorService naming — title naming churn deferred.

Depends on

Epic #11831 (parent). Sub 15 #11858 + Sub 16 #11859 merged (established the scheduling/ pattern).

Unblocks

Sub 18 #11862 atomic wire-up.

Authority

Discussion #11857 Cycle-3.5 GPT [GRADUATION_APPROVED] + operator architectural ratify + operator KISS feedback chain on PRs #11863 and #11865.

Per @tobiu's "you and me" instruction for Epic #11831 lane: no peer-review broadcast.

tobiu
tobiu APPROVED reviewed on May 23, 2026, 11:04 PM

No review body provided.