Skip to content

break the 22-module seriesAutopilot/creativeDirector import cycle with a project-start sink - #6094

Merged
atomantic merged 1 commit into
mainfrom
claim/issue-5920
Sep 3, 2026
Merged

break the 22-module seriesAutopilot/creativeDirector import cycle with a project-start sink#6094
atomantic merged 1 commit into
mainfrom
claim/issue-5920

Conversation

@atomantic

Copy link
Copy Markdown
Owner

Summary

Closes #5920.

The 22-module seriesAutopilot / creativeDirector strongly-connected component is gone, not shrunkfindImportCycleComponents now reports nothing across that half of the graph, and the #5920 entry is deleted from KNOWN_CYCLIC_COMPONENTS in serviceImportCycles.test.js.

  • The cut. Exactly one static edge ran pipeline/*creativeDirector/*: pipeline/episodeVideo.js importing completionHook.js#startCreativeDirectorProject. Everything else in the ring flowed the other way (CD's tool registry starts a Series Autopilot). Removing that single edge dissolves the whole component.
  • The seam. New leaf creativeDirector/projectStartSink.js inverts it: the pipeline depends on the sink, and the completion hook registers the concrete starter on it at module evaluation. server/index.js imports the hook for that side effect at boot. An unregistered request throws rather than silently dropping the start — a CD project that never advances is otherwise invisible.
  • Barrel rule. Applied the rule the issue names: creativeDirector/planAdvance.js and creative/tools/pipeline.js now import the modules that DECLARE the autopilot symbols (seriesAutopilot/state.js, seriesAutopilot/session.js, seriesAutopilot/orchestrator.js) instead of re-entering the seriesAutopilot.js barrel from outside the package.
  • No deferred imports. await import() would have hidden the cycle from the guard without removing the boot-order hazard, so it was not used.

The barrel's __testing lazy getters stay (their comment now records that the cycle they defended against is gone), and the cold-import guard is unchanged.

Test plan

  • New services/creativeDirector/projectStartSink.test.js — unregistered request throws and names the project, registered starter is delegated to, idempotent re-registration vs. a conflicting registrant, non-function registrant refused.
  • completionHook.test.js gains an arming assertion: importing the hook registers its own startCreativeDirectorProject on the sink (identity-checked via the idempotent-re-register path). Without it, a dropped side effect would silently stall every pipeline episode.
  • episodeVideo.test.js now asserts the fire-and-forget start actually reaches the sink with the new project id.
  • serviceImportCycles.test.js is the measurement: its "no baseline entry for a cycle that is already fixed" assertion fails if the component is still live, and its no-new-cycles assertion fails if the change closed a different ring.
  • Full cd server && npm test: 1910 files passed, 38520 tests passed, 1 file / 24 tests skipped.

… a project-start sink (#5920)

`pipeline/episodeVideo.js` importing `creativeDirector/completionHook.js` was the
only static edge running pipeline -> creativeDirector, and the CD tool registry
starts a Series Autopilot in the other direction — together they closed a
22-module strongly-connected component, the largest in `server/services`. In a
static ESM cycle whichever member evaluates first sees `undefined` for the
others' bindings, so any top-level const derived from an import in the ring is a
TDZ crash waiting on a module-ordering change.

New leaf `creativeDirector/projectStartSink.js` inverts that one edge: the
pipeline depends on the sink, the completion hook registers the concrete starter
on it at module evaluation, and `server/index.js` imports the hook for that side
effect at boot. An unregistered request throws rather than silently dropping the
start, because a CD project that never advances is otherwise invisible.

Also applied the barrel rule the issue names: `planAdvance.js` and
`creative/tools/pipeline.js` now import the modules that DECLARE the autopilot
symbols instead of re-entering the `seriesAutopilot.js` barrel from outside the
package. Deferring an import with `await import()` would have hidden the cycle
from the guard without removing the hazard, so it was not used.

The component is gone, not shrunk — `findImportCycleComponents` reports nothing
in that half of the graph, and the #5920 baseline entry is deleted from
KNOWN_CYCLIC_COMPONENTS in serviceImportCycles.test.js.
@atomantic
atomantic merged commit f711142 into main Sep 3, 2026
12 checks passed
@atomantic
atomantic deleted the claim/issue-5920 branch September 3, 2026 17:22
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Shrink the 22-module seriesAutopilot / creativeDirector import cycle

1 participant