Skip to content

test(producer): add mov ProRes distributed fixture#848

Merged
jrusso1020 merged 2 commits into
mainfrom
05-14-test_producer_add_mov_prores_distributed_fixture
May 15, 2026
Merged

test(producer): add mov ProRes distributed fixture#848
jrusso1020 merged 2 commits into
mainfrom
05-14-test_producer_add_mov_prores_distributed_fixture

Conversation

@jrusso1020
Copy link
Copy Markdown
Collaborator

@jrusso1020 jrusso1020 commented May 14, 2026

Description

Phase 4 of the distributed rendering plan: test fixtures (see DISTRIBUTED-RENDERING-PLAN.md §11 Phase 4 + §10 test strategy). This is PR 4.5 of the Phase 4 remainder, stacked on PR 4.4 (#847) which added png-sequence format support to the harness.

This PR adds the mov ProRes fixture (tests/distributed/mov-prores/). The composition is a 2-second (60-frame) scene at 30fps with a transparent background, a crossfade transition straddling the frame-30 chunk seam, and a continuously rotating SVG icon — same shape as the mp4-h264-sdr and png-sequence fixtures. renderConfig.format: "mov" + chunkSize: 15 produces N=4 chunks, each encoded as ProRes 4444 with alpha (yuva444p10le) and assembled via -c copy.

ProRes is intra-only — every frame is a keyframe — so concat-copy at the frame level is structurally trivial. What this fixture pins is the orthogonal contract: that ffmpeg's concat -c copy across four mov files preserves the QuickTime atoms (moov, mvhd, trak, mdia) intact so the assembled file plays in mov-native editors (Premiere, FCPX, DaVinci) without re-encoding. Both modes produced byte-identical 60-frame output against the in-process baseline (all 100 PSNR checkpoints came back ∞ for both modes).

LFS:

  • .gitattributes adds packages/producer/tests/distributed/*/output/output.mov and output.webm patterns. The 3.8 MB ProRes baseline is the main motivation; .webm is included pre-emptively so when webm becomes distributed-supported the path is already configured.

Testing

  • bun run --cwd packages/producer docker:test:update mov-prores — baseline rendered inside Dockerfile.test (60 ProRes 4444 frames, 640×360, alpha, ~3.8 MB)
  • bun run --cwd packages/producer docker:test mov-prores — in-process passes (100/100 checkpoints byte-identical against baseline)
  • bun run --cwd packages/producer docker:test:distributed mov-prores — distributed-simulated passes (100/100 checkpoints byte-identical against baseline)
  • bun run --cwd packages/producer docker:test:distributed font-variant-numeric many-cuts gsap-letters-render-compat style-1-prod sub-composition-video mp4-h264-sdr png-sequence mov-prores -- --sequential — full smoke set + all three stacked fixtures pass (8/8)
  • bunx oxlint + bunx oxfmt --check clean on changed files
  • bunx tsc --noEmit (producer package) clean

🤖 Generated with Claude Code

miguel-heygen
miguel-heygen previously approved these changes May 14, 2026
Copy link
Copy Markdown
Collaborator

@miguel-heygen miguel-heygen left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Re-reviewed as part of the fixture stack. LGTM.

Copy link
Copy Markdown
Collaborator

@vanceingalls vanceingalls left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(Intended verdict: APPROVE — posting as COMMENT because the self-stamp guard blocked the approval action; treat as a green review modulo the notes below.)

Clean addition. Matches the established #845/#847 stack pattern; correctly identifies that ProRes is intra-only and pins the orthogonal -c copy + QuickTime-atom contract, not state-continuity. Validated end-to-end (in-process + distributed-simulated both byte-identical against the baseline).

Strengths

  • meta.json:11-15chunkSize: 15 correctly produces N=4 chunks at 60 frames, and the GSAP crossfade at src/index.html:91-92 (0.9s → 1.1s) straddles the frame-30 seam by design, so the fixture meaningfully exercises chunk boundaries even though ProRes is keyframe-only.
  • Fixture leans entirely on existing wiring from #847 (harness outputFormat branching + runDistributedSimulatedRender format cast at regression-harness.ts:805) — no plumbing duplication.
  • Description is unusually precise about what this fixture pins vs. what it doesn't (atom preservation through concat-copy, not frame inter-dependency). That framing prevents the next contributor from re-litigating "is this redundant with mp4-h264-sdr?"

Findings

important

  • .gitattributes:10 — the output.webm LFS pattern is added pre-emptively, but webm is actively rejected by checkDistributedSupport (regression-harness-distributed.ts) and plan() throws FORMAT_NOT_SUPPORTED_IN_DISTRIBUTED (distributed/plan.ts:270). There is no current or near-future code path that produces a tests/distributed/*/output/output.webm. Adding LFS rules for a path that can't exist is scope creep — recommend deferring to whichever PR actually enables webm in distributed mode. Failure mode is minor (an inert LFS pattern), but it muddies the audit trail when the webm fixture eventually does land and someone wonders "did this PR add the LFS rule, or is it the same one?".
  • meta.json:3 description — worth one sentence noting that the PSNR comparator (psnrAtCheckpoint in regression-harness.ts:415) does not include the alpha plane in average: by default (ffmpeg's psnr filter measures Y/U/V only). For this fixture byte-equality + maxFrameFailures: 0 catches drift, but a future author cribbing this fixture and authoring minPsnr: 30 against an alpha-only regression would get a false pass. Forward-looking note prevents that footgun.

nits

  • src/index.html is missing two comments siblings have: the "no <audio> element on purpose — AAC frame quantization extends container duration past 2.0s and trips the last PSNR checkpoint" rationale (mp4-h264-sdr/src/index.html:92-98), and the explicit annotation that frames {15, 30, 45} sit inside the crossfade window (mp4-h264-sdr/src/index.html:103-105). Cribbing those over keeps the three fixtures' surface explanations parallel.
  • .label text is PHASE here but CHUNK in mp4-h264-sdr. Cosmetic, but stack coherence is cheap.
  • minAudioCorrelation / maxAudioLagWindows in meta.json:7-8 are dead config for silent compositions — the audio block short-circuits when extracted PCM is empty. Carried over from the sibling pattern; not actionable here, just calling it out for whoever revisits the meta schema.

Verdict: APPROVE (posted as COMMENT — see top note)
Reasoning: Fixture is correct, well-scoped, and lands cleanly on the harness wiring #847 set up. The webm LFS rule and alpha-PSNR docstring are worth addressing but neither blocks merge — both are easier to fix in a follow-up than to gate a fixture PR on.

Review by Vai

…ov-prores fixture

Address @vanceingalls review on #848: the mp4-h264-sdr sibling fixture
explains the crossfade-straddles-frame-30 and continuous-rotation
chunk-seam design choices inline; mov-prores didn't. Add the parallel
comment so the next contributor reading either fixture finds the same
context. Notes specifically that ProRes is intra-only and therefore
exercises the QuickTime atom / -c copy contract rather than frame-level
state continuity.

🤖 Generated with [Claude Code](https://claude.com/claude-code)
@jrusso1020 jrusso1020 force-pushed the 05-14-test_producer_add_png-sequence_distributed_fixture branch from 7dbdb7b to 3c29060 Compare May 14, 2026 23:52
@jrusso1020 jrusso1020 force-pushed the 05-14-test_producer_add_mov_prores_distributed_fixture branch from 271dcda to 967ebe6 Compare May 14, 2026 23:52
@jrusso1020
Copy link
Copy Markdown
Collaborator Author

Thanks @vanceingalls — addressed comment-parity in commit 8628a683. The mov-prores fixture now carries the same chunk-seam mapping + ProRes-intra-only rationale comments as the mp4 siblings.

On the output.webm LFS pattern — kept it intact. The team's stance is that any video file in the repo MUST go through LFS, so the pattern is a safety net to prevent a future webm fixture from accidentally landing as a regular binary. Cost of leaving it is zero (inert pattern); cost of removing it is one round-trip when webm distributed support lands.

The alpha-plane-PSNR docstring nit is a fair forward-looking note but doesn't load-bear here (this fixture uses byte equality, not PSNR) — leaving for the v1.5 PR that enables alpha-aware comparison.

Base automatically changed from 05-14-test_producer_add_png-sequence_distributed_fixture to main May 15, 2026 01:07
@jrusso1020 jrusso1020 dismissed miguel-heygen’s stale review May 15, 2026 01:07

The base branch was changed.

@jrusso1020 jrusso1020 merged commit 9cc09fc into main May 15, 2026
35 checks passed
@jrusso1020 jrusso1020 deleted the 05-14-test_producer_add_mov_prores_distributed_fixture branch May 15, 2026 01:13
jrusso1020 added a commit that referenced this pull request May 15, 2026
…852)

## Description

Phase 4 of the distributed rendering plan: test fixtures (see DISTRIBUTED-RENDERING-PLAN.md §11 Phase 4 + §10 test strategy). This is PR 4.7 of the Phase 4 remainder — the final fixture PR.

This PR adds six per-adapter chunk-boundary fixtures under `tests/distributed/{gsap,anime,three,lottie,css,waapi}-boundary/` plus a single `bun:test` driver (`chunkBoundary.test.ts`) that exercises each fixture's seek-determinism contract. Each fixture is a 60-frame composition (2s @ 30fps, 320×180) that drives the named adapter through the HyperFrames runtime's seek hook. The test renders each at `chunkSize=60` (N=1 chunk, no seams) and `chunkSize=15` (N=4 chunks, three seams at frames 15/30/45), then asserts every PNG frame is byte-identical across the two runs.

**Why png-sequence**: mp4 bitstreams encode keyframe placement directly. At `chunkSize=60` libx264 emits 1 IDR; at `chunkSize=15` it emits 4 IDRs at frames 0/15/30/45. Those are legitimately different bytes even when the captured pixels are identical. png-sequence's assemble path merges chunk frame directories with no re-encode, so per-frame byte equality is exactly pixel equality — the strongest contract a distributed render can satisfy.

**Fixture design** (each is ~60 lines of HTML):
- `gsap-boundary` — single GSAP `tl.to(...)` driving translateX + rotation linearly across 2s.
- `anime-boundary` — anime.js v4 timeline registered via `window.__hfAnime`.
- `three-boundary` — minimal Three.js scene; cube rotation derived from `window.__hfThreeTime`.
- `lottie-boundary` — inline Lottie JSON (rectangle layer animating position+rotation) loaded via `lottie-web` and registered via `window.__hfLottie`.
- `css-boundary` — pure `@keyframes` animation; the HyperFrames CSS adapter seeks via `animation-delay`.
- `waapi-boundary` — `element.animate()` with linear keyframes; runtime sets `currentTime` per frame.

The fixtures intentionally omit `meta.json` so the regression-harness discovery skips them with a clear `missing meta.json` log (they're driven exclusively by `chunkBoundary.test.ts`). The test passes `rejectOnSystemFonts: false` because some adapter bundles (notably anime.js's IIFE) embed CSS-shaped strings inside their JS source — `font-family: ui-monospace, monospace` for internal devtools styling — which `validateNoSystemFonts`'s document-wide regex would otherwise false-positive on every adapter fixture that loads such a bundle. The fixtures display no text, so the relaxed font validation doesn't affect the contract under test.

The 7th test case is a layout sanity check that asserts every expected `*-boundary` fixture directory exists.

## Testing

- `bun test packages/producer/src/services/distributed/chunkBoundary.test.ts` — 7 tests pass on host (6 adapters × byte-identical N=1 vs N=4 + the layout check, 41.6s)
- `bun test packages/producer/src/services/distributed/` — all 49 distributed unit tests pass (43.6s)
- `bun run --cwd packages/producer docker:test:distributed font-variant-numeric many-cuts gsap-letters-render-compat style-1-prod sub-composition-video mp4-h264-sdr png-sequence mov-prores mp4-h265-sdr -- --sequential` — full smoke set + all four prior stacked fixtures pass (9/9)
- `bunx oxlint` + `bunx oxfmt --check` clean
- `bunx tsc --noEmit` (producer package) clean

## After this stack lands

The Phase 4 fixture set is complete: PR 4.6 (#844) pins cross-worker idempotency; 4.2/4.3/4.4/4.5 (#845/#851/#847/#848) prove each format produces correct chunked output at the fixture's `minPsnr`; 4.3-pre (#850) added the codec knob H.265 needed; and this PR proves each first-party adapter's seek-determinism survives chunk seams. Phase 5 (CLI surface for `hyperframes plan/chunk/assemble`) and Phase 6 (AWS Lambda turnkey) are unblocked.

🤖 Generated with [Claude Code](https://claude.com/claude-code)
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.

3 participants