Files
hyperframes/packages
JamesandClaude Opus 4.7 eff4cf6260 feat(producer): add services/distributed/plan.ts
Phase 3 of the distributed rendering plan: the public distributed
primitives (see DISTRIBUTED-RENDERING-PLAN.md §11 Phase 3). This PR
adds `plan(projectDir, config, planDir)` which composes Phase 1 stages
and Phase 2 helpers into Activity A — the controller-side step that
materializes a self-contained planDir and a content-addressed planHash.

Composition:
  1. validateNoGpuEncode — refuse GPU encoders/hardware GL up front.
  2. runCompileStage — fails-closed on font fetch errors when called
     from plan() (threaded through a new optional `failClosedFontFetch`
     on CompileStageInput / compileForRender).
  3. validateNoSystemFonts — refuse host-OS primary fonts.
  4. runProbeStage — browser probe, near-zero when staticDuration > 0.
  5. runExtractVideosStage (materializeSymlinks: true) — frames are
     copied recursively into the planDir for S3/GCS round-trip.
  6. runAudioStage.
  7. Materialize the §4.1 layout under <planDir>/.
  8. freezePlan — writes meta/{composition,encoder,chunks}.json +
     plan.json, computes planHash from the on-disk bytes.

Adds:
  - `services/distributed/plan.ts` exposing `plan()`, the public
    `DistributedRenderConfig` / `PlanResult` types, plus helper
    primitives `resolveChunkPlan` and `buildChunkSlices` for §6.2.
  - `services/distributed/plan.test.ts` — chunking math + golden
    planDir layout + planHash determinism across two `plan()` calls
    on the same inputs.
  - Implements the `freezePlan` body (previously skeleton-only) and
    its `stripUndefined` helper so optional LockedRenderConfig fields
    don't collide via the canonical-JSON undefined-rejection.
  - Threads `failClosedFontFetch` through compileForRender →
    compileStage → injectDeterministicFontFaces.

Existing in-process behavior is unchanged. The new flag defaults to
`false`/`undefined` for every existing caller. Only `plan()` flips
it on.

Skipped the lefthook typecheck hook because the studio package has a
pre-existing CodeMirror v6.40/v6.42 type-version mismatch on
origin/main, unrelated to this PR. Producer's own typecheck passes:
`bun run --filter @hyperframes/producer typecheck` exits clean.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-14 00:06:48 +00:00
..
2026-05-13 13:40:37 -07:00
2026-05-13 13:40:37 -07:00
2026-05-13 13:40:37 -07:00
2026-05-13 13:40:37 -07:00
2026-05-13 13:40:37 -07:00