feat(producer): enable webm in distributed mode via concat-copy#951
Conversation
miguel-heygen
left a comment
There was a problem hiding this comment.
REQUEST CHANGES — one alpha-loss bug, everything else is solid.
Blocker: missing needsAlpha for webm in plan.ts
At plan.ts:603:
const needsAlpha = config.format === "png-sequence" || config.format === "mov";WebM is not included, but the distributed pipeline configures webm to use yuva420p (alpha pixel format). This flag controls forceScreenshot — on Linux headless-shell, only screenshot capture preserves alpha (BeginFrame does not). Without needsAlpha = true, the compile stage freezes forceScreenshot: false into the plan, and every chunk worker captures without alpha.
Result: webm chunks would encode yuva420p frames with uniformly-opaque or garbage alpha instead of the composition's actual transparency.
Fix:
const needsAlpha = config.format === "png-sequence" || config.format === "mov" || config.format === "webm";Note: renderChunk.ts:550 already has the correct logic (plan.dimensions.format !== "mp4"), but it only affects the within-chunk capture stage — the plan-time forceScreenshot decision is already frozen incorrectly.
Smoke tests don't catch this because testsrc2 is fully opaque and doesn't exercise the capture pipeline.
Everything else looks good
resolveEncoderTriple()returns correct VP9 triplerejectUnsupportedDistributedFormat()correctly removes webm banLockedRenderConfig.encoderunion gains"libvpx-vp9-software"- Concat-copy (Path A) is the right architectural choice
- Tests correctly pivot from "rejects webm" to "accepts webm" + new HDR+webm combo test
- All CI green
vanceingalls
left a comment
There was a problem hiding this comment.
REQUEST CHANGES — agreeing with Miguel on the alpha blocker; flagging the test-coverage gap that hid it.
Blocker (already filed by Miguel; confirming)
packages/producer/src/services/distributed/plan.ts:659:
const needsAlpha = config.format === "png-sequence" || config.format === "mov";WebM rides the yuva420p pixel-format path (resolveEncoderTriple at L565), but needsAlpha does not include "webm". That gate sets forceScreenshot in compileStage — and the frozen LockedRenderConfig captures whatever decision the plan makes. On Linux headless-shell, only screenshot capture preserves alpha (BeginFrame does not). So for format: "webm" we'd freeze forceScreenshot: false into meta/encoder.json, every chunk worker captures opaque RGB(A), and the libvpx-vp9 alpha sub-stream encodes garbage / uniform alpha — silently producing un-keyable webm output.
renderChunk.ts:572 (needsAlpha: plan.dimensions.format !== "mp4") only covers the within-chunk encode-stage branch; it does not undo the plan-time freeze.
Fix is the one-liner Miguel suggested: include "webm" in the needsAlpha disjunction. Land before merge.
Important — test coverage hid this
The yuva420p smoke block (webm-concat-copy.test.ts) doesn't exercise alpha end-to-end:
- The source is
testsrc2piped throughformat=rgba.testsrc2is uniformly opaque — thergbafilter just adds an opaque alpha plane. There is no transparency in the pixel data. - The decode-test assertion accepts
pix_fmt=yuva?420p(i.e., yuv420p OR yuva420p) because "libvpx-vp9 may downgrade uniformly-opaque alpha to yuv420p." That comment is honest, but it concedes the test cannot distinguish "alpha-track survived concat-copy" from "encoder dropped the redundant alpha plane entirely."
So the smoke "proves" the encoder args don't crash on yuva420p input — not that meaningful alpha survives the chunk → concat → mux chain. The capture-stage alpha bug above is exactly the failure mode this test should have caught.
Suggested fix (non-blocking but strong recommendation before declaring this contract proven): replace testsrc2 + format=rgba with a source that actually has spatially-varying alpha — e.g. color=c=red@0.5 overlaid on color=c=blue@0.0, or a geq filter producing a per-pixel alpha gradient. Then assert pix_fmt=yuva420p strictly and probe one pixel near the center of the assembled output to confirm the alpha value is non-trivial. PR 8.3's E2E fixture (#952) can also cover this — but the unit-level smoke should not silently accept the no-alpha codepath when alpha is the whole reason webm exists in this pipeline.
Stack-PR CI gap (process note)
Base is feat/engine-vp9-closed-gop-args, not main. The repo's ci.yml workflow is gated on pull_request: branches: [main], so Build / Test / Typecheck / CLI smoke did NOT run on this head SHA. The rollup shows only regression, preview-regression, Player perf, and Graphite / mergeability_check. The author's PR-body claims (bun test ... — 4/4 pass, bunx tsc --noEmit — clean, oxlint clean) are local-only and not CI-verified for this head.
Not a blocker on its own, but worth flagging: once the alpha fix lands, restack onto main (or wait until #950 merges) so the main CI workflow actually fires on this head before merge.
What's solid (no action)
rejectUnsupportedDistributedFormat()cleanly removes the webm reject while keeping the HDR gate untouched — the new "HDR + webm" combo test pins that the HDR throw fires regardless of format.resolveEncoderTriple()webm branch correctly returnslibvpx-vp9-software+yuva420p+preset=good, andgetEncoderPreset(_, "webm")in the engine returns matchingcodec=vp9+pixelFormat=yuva420p. The non-mp4codecreject also has the correct updated error message.LockedRenderConfig.encoderunion gain of"libvpx-vp9-software"matches the existing per-encoder discriminant pattern (libx264 / libx265 / prores / png-sequence).renderChunk.tscast tightening ("mp4" | "mov" | "webm") is correct — the prior cast that excluded webm would have silently fallen back to mp4 preset shape and produced libx264 output, so this fix matters.- Concat-copy path in
assemble.tsis genuinely format-agnostic:concat/mux/applyFaststartall key off the output extension;muxVideoWithAudioalready routes.webmtolibopus;applyFaststartshort-circuits tocopyFileSyncfor.webmand.mov. The audio-pad input path produces.aaccontent butmuxVideoWithAudiotranscodes to Opus anyway, so the file extension mismatch (audio-padded.aacfeeding a webm mux) is harmless. planHashcorrectly includesformat: "webm"viadimensions.formatflowing intofreezePlan— webm-specific knobs invalidate cache as expected.closedGop=true+gopSize=chunkSize+ libvpx-vp9 closed-GOP args (-g,-keyint_min,-auto-alt-ref 0,-cpu-used 2inengine/chunkEncoder.ts:289-298) are correctly mandatory for concat-copy seam independence. Alt-ref disable is the load-bearing piece — verified.planFormatBanlist.test.tspivots are well-scoped; webm-reject tests deleted cleanly, accept-webm + HDR+webm-combo added.
Review by Vai
4573e4e to
1865b39
Compare
fd43c14 to
c44b130
Compare
|
Thanks for catching the alpha bug — that was a real blocker and ours to miss. Pushed the fix as a follow-up commit on this branch (
|
miguel-heygen
left a comment
There was a problem hiding this comment.
Re-reviewed — APPROVE. Blocker resolved.
needsAlpha now includes "webm" — forceScreenshot: true is correctly frozen into the plan for webm distributed renders.
Smoke test also strengthened to catch this exact class of bug:
- Real alpha gradient source (
geq=a='X*255/W') instead of uniformly-opaque testsrc2 TAG:ALPHA_MODE=1assertion proves encoder was configured for alpha- Alpha plane variance check (
YMAX - YMIN > 100) confirms real alpha survives concat-copy - Exit-code-only decode gate (no stderr flake risk)
These four checks would have caught the needsAlpha omission pre-review. Good hardening.
No new concerns. Wait for regression shards before merging.
vanceingalls
left a comment
There was a problem hiding this comment.
APPROVE — re-review at c44b130f. The blocker is addressed end-to-end and the test-coverage gap is closed.
Blocker resolved
packages/producer/src/services/distributed/plan.ts:665-666:
const needsAlpha =
config.format === "png-sequence" || config.format === "mov" || config.format === "webm";"webm" is now in the disjunction. Traced end-to-end:
needsAlpha=true→runCompileStage({ needsAlpha, … })(L669-682)compileStagereturnsforceScreenshot(L685)forceScreenshotflows intobuildLockedRenderConfig({ forceScreenshot, … })(L823-831)buildLockedRenderConfigwritescaptureMode: "screenshot"andforceScreenshot: trueintoLockedRenderConfig(L484-488)- That freezes into
meta/encoder.jsonviafreezePlan, so every chunk worker captures via the alpha-aware screenshot path on Linux headless-shell instead of BeginFrame.
Also nice: the inline comment at L656-664 explains why the disjunction matches renderOrchestrator.ts's needsAlpha shape and what specifically breaks (BeginFrame doesn't preserve alpha on Linux headless-shell, libvpx-vp9 silently emits un-keyable output). Good guard against this regressing again.
Important resolved
The yuva420p smoke (webm-concat-copy.test.ts:308-535) is now hardened against the "uniformly-opaque alpha gets silently dropped" failure mode:
- Source frames now use
format=rgba,geq=r='r(X,Y)':g='g(X,Y)':b='b(X,Y)':a='X*255/W'— a horizontal alpha gradient on top of testsrc2 RGB. Spatially-varying alpha that libvpx-vp9 cannot downgrade as uniform/redundant (L348). - New assertion
TAG:ALPHA_MODE=1on the muxed output's stream tags (L478-485) — the right signal that alpha encoding survived concat-copy (libvpx-vp9 stores alpha as a MatroskaBlockAdditionalsidecar, sopix_fmtalone can't tell you the alpha track exists). - New
signalstats YMIN/YMAXassertion on the extracted alpha plane via-c:v libvpx-vp9decoder +-pix_fmt rgba(L487-535) — gradient source producesYMIN ≈ 0 / YMAX ≈ 255, spread > 100 confirms real per-pixel alpha content survives the chunk → concat → mux chain. Uniform alpha would giveYMIN == YMAX.
The comment at L491-494 explicitly calls out that this is what would have caught the needsAlpha plan-time bug. Test now exercises the failure mode it's meant to cover — good.
Stack-PR CI gap — still open (process note, not blocking)
Base is still feat/engine-vp9-closed-gop-args, not main. Confirmed at head c44b130f:
Build,Test,Typecheck,CLI smoke— did NOT run (workflow gated onpull_request: branches: [main])Preflight (lint + format)—skippedPreview parity—skippedPerf: ${{ matrix.shard }}—skipped- Ran:
Detect changes,player-perf,preview-regression(all pass),regression-shards1-8 (in progress) - Pending:
Graphite / mergeability_check
Same gap I flagged last round. Not blocking the approval — Graphite restacks onto main on merge, and Miguel has independently approved. But the author's PR-body typecheck/test/lint claims remain CI-unverified for this head. Worth fixing systemically by changing ci.yml's pull_request: branches: filter to include the long-lived feature branches, or just confirming with the team that the policy is "main-only CI on stacks, trust local for stacked-PR heads."
Verdict
Ship. The load-bearing fix is correct, the test that should have caught it now would, and Miguel has independently approved at the same head SHA.
Review by Vai (re-review)
vanceingalls
left a comment
There was a problem hiding this comment.
Re-review at HEAD c44b130f. Flipping CHANGES_REQUESTED → APPROVE — both findings cleanly addressed.
Status of prior findings
- Blocker (
needsAlphaexcludes webm → silent garbage-alpha output) — ADDRESSED.plan.ts:665-666now readsneedsAlpha = format === "png-sequence" || format === "mov" || format === "webm". Traced end-to-end:needsAlpha→runCompileStagereturnsforceScreenshot→buildLockedRenderConfigfreezescaptureMode: "screenshot"+forceScreenshot: trueintometa/encoder.json. Inline comment at:656-664documents the BeginFrame/headless-shell rationale. - Important (smoke can't catch this) — ADDRESSED.
webm-concat-copy.test.tsnow uses spatially-varying alpha (geq=a='X*255/W'), assertsTAG:ALPHA_MODE=1on stream tags, AND runssignalstatson the extracted alpha plane checkingYMIN/YMAXspread > 100. Would catch the original failure mode pre-review. - Stacked-PR CI gap — STILL OPEN. Base is still
feat/engine-vp9-closed-gop-args. Build/Test/Typecheck/CLI smoke didn't run on this head; closes incidentally when #950 lands.
CI on c44b130f: 0 failed; player-perf + preview-regression SUCCESS; 8 regression-shards in_progress; Preflight/Preview parity/Perf SKIPPED.
Verdict: APPROVE. The load-bearing fix for the whole webm stack.
Re-review by Vai
…a smoke PR review feedback from Miguel and Vai on #951 caught a real bug: `plan.ts`'s `needsAlpha` disjunction excluded `"webm"`, so the plan stage froze `forceScreenshot: false` into the `LockedRenderConfig` even though distributed webm uses `yuva420p`. Every chunk worker captured opaque RGB via BeginFrame (which doesn't preserve alpha on Linux headless-shell), and libvpx-vp9 encoded uniformly-opaque alpha that the encoder then dropped — producing un-keyable webm. Two changes: 1. **plan.ts**: include `"webm"` in `needsAlpha`. Matches the in-process renderer's logic at `renderOrchestrator.ts:1469` (`const needsAlpha = isWebm || isMov || isPngSequence`); the two sites must stay in sync since the distributed pipeline's PSNR regression compares against the in-process baseline. 2. **Smoke test (yuva420p describe)**: source frames now use a real alpha gradient (`geq=a='X*255/W'` on top of `testsrc2`) instead of `testsrc2 + format=rgba` which was uniformly opaque. The decode- pix_fmt assertion is dropped (ffprobe reports `yuv420p` for VP9-with-alpha because the alpha lives in a Matroska `BlockAdditional` sidecar) and replaced with two stronger checks: - `TAG:ALPHA_MODE=1` is present on the stream — proves the encoder was actually configured for alpha - alpha plane variance after `-c:v libvpx-vp9 -i ... -pix_fmt rgba -vf extractplanes=a,signalstats` — proves the alpha sub-stream round-trips through concat-copy with spatially-varying content, not uniform/dropped alpha - decode-test gate is now exit-code-only (was `exitCode || stderr` which would flake on chatty ffmpeg `-v error` builds emitting non-fatal DTS/container notes) These checks would have caught the `needsAlpha` bug before review. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1865b39 to
07de7e6
Compare
c44b130 to
fcfd330
Compare
The base branch was changed.
…a smoke PR review feedback from Miguel and Vai on #951 caught a real bug: `plan.ts`'s `needsAlpha` disjunction excluded `"webm"`, so the plan stage froze `forceScreenshot: false` into the `LockedRenderConfig` even though distributed webm uses `yuva420p`. Every chunk worker captured opaque RGB via BeginFrame (which doesn't preserve alpha on Linux headless-shell), and libvpx-vp9 encoded uniformly-opaque alpha that the encoder then dropped — producing un-keyable webm. Two changes: 1. **plan.ts**: include `"webm"` in `needsAlpha`. Matches the in-process renderer's logic at `renderOrchestrator.ts:1469` (`const needsAlpha = isWebm || isMov || isPngSequence`); the two sites must stay in sync since the distributed pipeline's PSNR regression compares against the in-process baseline. 2. **Smoke test (yuva420p describe)**: source frames now use a real alpha gradient (`geq=a='X*255/W'` on top of `testsrc2`) instead of `testsrc2 + format=rgba` which was uniformly opaque. The decode- pix_fmt assertion is dropped (ffprobe reports `yuv420p` for VP9-with-alpha because the alpha lives in a Matroska `BlockAdditional` sidecar) and replaced with two stronger checks: - `TAG:ALPHA_MODE=1` is present on the stream — proves the encoder was actually configured for alpha - alpha plane variance after `-c:v libvpx-vp9 -i ... -pix_fmt rgba -vf extractplanes=a,signalstats` — proves the alpha sub-stream round-trips through concat-copy with spatially-varying content, not uniform/dropped alpha - decode-test gate is now exit-code-only (was `exitCode || stderr` which would flake on chatty ffmpeg `-v error` builds emitting non-fatal DTS/container notes) These checks would have caught the `needsAlpha` bug before review. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
fcfd330 to
f8ffe9f
Compare
miguel-heygen
left a comment
There was a problem hiding this comment.
Re-approving at f8ffe9f — same fixup commit (needsAlpha + alpha smoke hardening) I reviewed earlier. No new changes.
vanceingalls
left a comment
There was a problem hiding this comment.
Re-review at f8ffe9faf30c2d66fdc3f74598e7bb73b53ca909 (round-2 approve was at c44b130, since dismissed).
Round-2 findings remain addressed. Verified on the new HEAD:
- Blocker (needsAlpha):
packages/producer/src/services/distributed/plan.ts:666-667still hasconfig.format === "webm"in the disjunction. - Important (alpha smoke):
webm-concat-copy.test.tsstill drivesgeq=a='X*255/W', assertsTAG:ALPHA_MODE=1, and validatessignalstatsYMIN/YMAX variance.
But CI on this HEAD is failing on changes that block merge, and round-2's full CI workflow never actually ran — so this is fresh information, not a regression.
New blocker — @hyperframes/aws-lambda package does not compile against the widened DistributedFormat
Three typecheck errors in packages/aws-lambda/ against the "webm" widening:
src/handler.ts(277,7): error TS2322: Type '"mp4" | "webm" | "mov" | "png-sequence"' is not assignable to type '"mp4" | "mov" | "png-sequence"'.
src/sdk/renderToLambda.ts(87,31): error TS2345: Argument of type '"mp4" | "webm" | "mov" | "png-sequence"' is not assignable to parameter of type 'DistributedFormat'.
src/sdk/validateConfig.ts(69,33): error TS2345: Argument of type '"mp4" | "webm" | "mov" | "png-sequence"' is not assignable to parameter of type '"mp4" | "mov" | "png-sequence"'.
Two root sites in packages/aws-lambda/:
src/handler.ts:436—downloadChunkObjects(..., format: "mp4" | "mov" | "png-sequence")— hard-coded narrow string union, not derived fromDistributedFormat. Callers passresult.format/event.Formatwhich now carry"webm".src/sdk/validateConfig.ts:34—const ALLOWED_FORMATS = ["mp4", "mov", "png-sequence"] as const;— a runtime allowlist that ALSO drops webm. Even if you only widen the TS type, this is a runtime-correctness hole: any Lambda-mode caller that passesformat: "webm"will be rejected at validation withmust be one of mp4, mov, png-sequence. The distributed-webm feature this PR ships is not reachable through the Lambda SDK.
Why this slipped past round 2: at c44b130 the CI workflow (where Typecheck / Build / CLI smoke (required) live) never ran on this PR — only regression + player-perf jobs report. On f8ffe9fa, full CI is triggering against main and three required jobs are failing:
Build FAILURE (aws-lambda tsc -p tsconfig.build.json --emitDeclarationOnly)
Typecheck FAILURE (same — TS2322/TS2345 above)
CLI smoke (required) FAILURE (Build monorepo step; cascades from the same tsc errors)
Other required-equivalent CI on f8ffe9fa: Test SUCCESS, Test: runtime contract SUCCESS, Lint SUCCESS, Format SUCCESS, Fallow audit SUCCESS, Semantic PR title SUCCESS, regression IN_PROGRESS, Windows render verification IN_PROGRESS.
Required changes
- Blocker — make
aws-lambdaaccept webm at both type-level and runtime-level. Two minimum edits:packages/aws-lambda/src/handler.ts:436— replace the hard-coded"mp4" | "mov" | "png-sequence"parameter type withDistributedFormatimported from@hyperframes/producerso the two stay in sync by construction (or withExclude<DistributedFormat, ...>if a subset is intended — but for downloadChunkObjects, webm uses concat-copy the same way mp4 does, so the full set is right).packages/aws-lambda/src/sdk/validateConfig.ts:34— add"webm"toALLOWED_FORMATS. (Or, better, deriveALLOWED_FORMATSfromDistributedFormatonce, since this is the third site I've now seen with a manual hand-maintained allowlist of distributed formats.)
- Important — add a
bun run --filter '@hyperframes/{...,aws-lambda}' buildor equivalent typecheck step to the local pre-push contract, or apackages/aws-lambda/src/sdk/validateConfig.test.tscase that pins the allowlist ==DistributedFormat. The hand-maintained mirror of the format union is exactly the class of bug round 2 caught forneedsAlpha, and it'll keep recurring across the PR-series fanout (PR 8.3 / 8.4 will both touch this surface) until the source of truth is single. - Nit — once 1 lands, please re-trigger CI and confirm
Build/Typecheck/CLI smoke (required)go green before re-requesting review. Round-2's approve dismissed on force-push; my re-review depends on a fresh full-CI signal againstmain.
Process note for next round
I will re-verify the two prior findings + the three new failing CI jobs on the next HEAD. If aws-lambda lands cleanly and CI is green, no further review iteration is needed — drop a comment with the resolved fix and I'll re-stamp.
Review by Vai (re-review round 3)
PR 8.2 of the WebM distributed-rendering plan (v1.5 backlog #1; see DISTRIBUTED-RENDERING-PLAN.md §7.2). Wires libvpx-vp9 webm through the distributed pipeline now that PR 8.1 proved concat-copy works. Architectural decision: Path A (concat-copy) — based on PR 8.1's smoke test result (9/9 tests pass for both yuv420p and yuva420p VP9 streams). The simpler architecture wins; no re-encode in assemble, no encode- parallelism loss. Changes: - plan.ts: - DistributedRenderConfig.format and PlanResult.format now include "webm" — type-level acceptance matches the runtime gate. - rejectUnsupportedDistributedFormat() no longer trips on webm. HDR mp4 remains the only refused configuration. - resolveEncoderTriple() returns libvpx-vp9-software + yuva420p + preset="good" for format="webm". yuva420p preserves alpha — the format's main reason for existing for web delivery. - codec= remains rejected for non-mp4 formats (mov is always ProRes 4444; webm is always libvpx-vp9). The error message lists all four distributed-supported formats. - FormatNotSupportedInDistributedError docstring updated to reflect the new reality (only HDR is unsupported). - freezePlan.ts: LockedRenderConfig.encoder gains "libvpx-vp9-software". Mirrors libx265-software / prores-software / png-sequence in shape; the chunk worker reads this discriminant to decide encode args. - renderChunk.ts: drops the now-incorrect cast that excluded webm from buildSyntheticRenderJob's format input; tightens the preset-format cast to include webm. - assemble.ts: docstring + comment updates. The mp4/mov concat-copy path is format-agnostic — webm uses the exact same code (applyFaststart is a no-op for webm via the existing chunkEncoder.ts gate; muxVideoWithAudio already routes webm to libopus audio). - planFormatBanlist.test.ts: webm-rejection tests removed; replaced with "accepts webm" tests + a HDR+webm combo test that verifies HDR is the trip regardless of format. - plan.test.ts: new describe block pins the webm wiring contract: format="webm" produces an encoder=libvpx-vp9-software / pixelFormat=yuva420p planDir with closedGop=true and gopSize=chunkSize. - webm-concat-copy.test.ts (smoke): extended with a yuva420p variant that proves the alpha pixel format the distributed pipeline actually emits also round-trips through concat-copy. 9/9 tests pass locally. §8 format support matrix in DISTRIBUTED-RENDERING-PLAN.md is intentionally left unchanged at this PR — it flips to ✓ in PR 8.4 once the end-to-end fixture (PR 8.3) is green. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…a smoke PR review feedback from Miguel and Vai on #951 caught a real bug: `plan.ts`'s `needsAlpha` disjunction excluded `"webm"`, so the plan stage froze `forceScreenshot: false` into the `LockedRenderConfig` even though distributed webm uses `yuva420p`. Every chunk worker captured opaque RGB via BeginFrame (which doesn't preserve alpha on Linux headless-shell), and libvpx-vp9 encoded uniformly-opaque alpha that the encoder then dropped — producing un-keyable webm. Two changes: 1. **plan.ts**: include `"webm"` in `needsAlpha`. Matches the in-process renderer's logic at `renderOrchestrator.ts:1469` (`const needsAlpha = isWebm || isMov || isPngSequence`); the two sites must stay in sync since the distributed pipeline's PSNR regression compares against the in-process baseline. 2. **Smoke test (yuva420p describe)**: source frames now use a real alpha gradient (`geq=a='X*255/W'` on top of `testsrc2`) instead of `testsrc2 + format=rgba` which was uniformly opaque. The decode- pix_fmt assertion is dropped (ffprobe reports `yuv420p` for VP9-with-alpha because the alpha lives in a Matroska `BlockAdditional` sidecar) and replaced with two stronger checks: - `TAG:ALPHA_MODE=1` is present on the stream — proves the encoder was actually configured for alpha - alpha plane variance after `-c:v libvpx-vp9 -i ... -pix_fmt rgba -vf extractplanes=a,signalstats` — proves the alpha sub-stream round-trips through concat-copy with spatially-varying content, not uniform/dropped alpha - decode-test gate is now exit-code-only (was `exitCode || stderr` which would flake on chatty ffmpeg `-v error` builds emitting non-fatal DTS/container notes) These checks would have caught the `needsAlpha` bug before review. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
f8ffe9f to
4aecc36
Compare
CI on PR #951 was failing at typecheck/build because the producer's `DistributedRenderConfig.format` widened to include webm in this PR but the aws-lambda package's narrow `"mp4" | "mov" | "png-sequence"` type literals in `events.ts`, `handler.ts`, and `validateConfig.ts` hadn't kept up. `renderToLambda.ts:87` passed `config.format` (now including webm) into a parameter typed against the narrow union, producing TS2345. This widening originally landed in PR #952 (test fixture PR) but needs to be atomic with the producer's widening here to keep each PR independently typecheck-clean. Also refactor `formatExtension` from a switch dispatch to a `Record<DistributedFormat, string>` lookup. Adding the webm case tipped the switch's CRAP to the 30.0 fallow threshold; the lookup table drops cyclomatic from 5 to 1 with the same compile-time exhaustiveness guarantee (TS errors on missing entries when `DistributedFormat` adds a new format). The runtime `_exhaustive: never` throw was only protecting against a string slipping past TS; `validateConfig.ts`'s `ALLOWED_FORMATS` already gates untrusted input at the SDK boundary. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
4aecc36 to
7f8a332
Compare
miguel-heygen
left a comment
There was a problem hiding this comment.
Re-reviewed (round 3) — APPROVE. All three TS blockers resolved.
Verified at 7f8a332f35:
events.ts: RenderChunkEvent, AssembleEvent, PlanLambdaResult format fields widened to include"webm"handler.ts:436:downloadChunkObjectsparameter type widenedvalidateConfig.ts:34:ALLOWED_FORMATSruntime allowlist gains"webm"— was also a runtime gate, not just a type issueformatExtension.ts: refactored toRecord<DistributedFormat, string>— compile-time exhaustivenessvalidateConfig.test.ts: negative case changed from"webm"to"gif"
CI: Build ✓, Typecheck ✓, CLI smoke ✓, Test ✓, Lint ✓, Format ✓, Fallow ✓, Windows ✓, CodeQL ✓. Regression shards still running.
Prior fixes remain intact: needsAlpha includes webm, alpha smoke hardened with real gradient + ALPHA_MODE + signalstats.
vanceingalls
left a comment
There was a problem hiding this comment.
Re-review (round 4) — round-3 blocker addressed; approving.
Calibrated strengths:
packages/aws-lambda/src/formatExtension.ts:9-25— picked the right shape: a singleDistributedFormatexport +Record<DistributedFormat, string>lookup table, plus an honest commit message explaining why the lookup replaces the switch (CRAP/cyclomatic on the new arm vs. exhaustiveness preserved by theRecordtype). Every other narrow-format site inaws-lambdawas widened in lockstep — no stragglers.- Commit message ("widen narrow format types") explicitly calls out the cross-PR atomicity issue with #952 — exactly the kind of context that pays off in
git blamesix months from now.
Round-3 blockers — verified ADDRESSED:
handler.ts:277Format: result.format(TS2322) → producer'sPlanResult.formatwidened in this same PR;PlanLambdaResult.Formatatevents.ts:68,83,109now"mp4" | "mov" | "png-sequence" | "webm". Compiles.renderToLambda.ts:87formatExtension(opts.config.format)(TS2345) →formatExtension.ts:9DistributedFormatincludes"webm";FORMAT_EXTENSIONShas thewebm: ".webm"entry.validateConfig.ts:69(TS2345) →validateConfig.ts:34ALLOWED_FORMATS = ["mp4", "mov", "png-sequence", "webm"] as const— runtime allowlist now accepts webm at the SDK boundary.handler.ts:436downloadChunkObjects(..., format: ...)narrow union → widened to include"webm". Theformat === "png-sequence"branch is preserved (untar) and webm falls through to the file-copy branch correctly (concat-copy assemble handles webm identically to mp4/mov per PR 8.1's smoke).
Cross-checked: grep -rn '"mp4" | "mov" | "png-sequence"' packages/aws-lambda/src/ — every match also contains "webm". Zero straggler sites.
Round-2 fixes still present:
plan.ts:665-666needsAlphadisjunction includesconfig.format === "webm".webm-concat-copy.test.ts:484, 513—ALPHA_MODE=1stream-tag assertion +extractplanes=a,signalstatsalpha-variance check are in place.
CI at 7f8a332f — required checks:
Build: SUCCESSTypecheck: SUCCESSCLI smoke (required): SUCCESSTest: SUCCESSTest: runtime contract: SUCCESSRender on windows-latest: SUCCESSTests on windows-latest: SUCCESSSemantic PR title: SUCCESSregression: shards 1-8 IN_PROGRESS (not a regression introduced by this PR; the structural typecheck gates are all green)
No new findings. The fix took the manual-widen route rather than the import-from-producer route, but the choice is defensible: it keeps aws-lambda self-describing at its public-API boundary (events.ts literal union doubles as the wire-protocol contract for Step Functions), and the DistributedFormat export in formatExtension.ts is now the single internal source of truth. A future PR consolidating on import { DistributedFormat } from "@hyperframes/producer/distributed" would be a clean cleanup, but not a blocker today.
Verdict: APPROVE
Reasoning: Round-3 aws-lambda typecheck blocker is cleanly addressed at every site; round-2 fixes (needsAlpha + hardened alpha smoke) remain intact; all structural CI gates that were failing are now green. Regression shards still running but those are not the gate the round-3 blocker raised.
Review by Vai (re-review round 4)
vanceingalls
left a comment
There was a problem hiding this comment.
Re-review at HEAD 7f8a332f. Flipping CHANGES_REQUESTED → APPROVE — all 3 round-3 TS blockers addressed cleanly.
Status of prior blockers
handler.ts:277TS2322 → ADDRESSED via producer's widenedPlanResult.format+events.ts:68,83,109union now includes"webm".renderToLambda.ts:87TS2345 → ADDRESSED viaformatExtension.ts:9DistributedFormat = "mp4" | "mov" | "png-sequence" | "webm".validateConfig.ts:69TS2345 → ADDRESSED viavalidateConfig.ts:34ALLOWED_FORMATS = [..., "webm"].handler.ts:436runtime narrow union → widened to include"webm". Zero straggler narrow-format sites in aws-lambda.
James took the manual-widen route (not the import-from-producer single-source-of-truth route I suggested). To prevent recurrence, he also re-exported DistributedFormat from producer in aws-lambda and refactored formatExtension.ts switch → Record<DistributedFormat, string> for compile-time exhaustiveness. Defensible — manual widen + re-export pattern catches drift via TS errors on missed sites.
CI status (verbatim) at 7f8a332f
Required checks all SUCCESS: Build, Typecheck, CLI smoke (required), Test, Test: runtime contract, Render on windows-latest, Tests on windows-latest, Semantic PR title. regression shards 1-8 IN_PROGRESS (non-gating).
Verdict: APPROVE.
Re-review by Vai (round 4)
* feat(producer): enable webm in distributed mode via concat-copy PR 8.2 of the WebM distributed-rendering plan (v1.5 backlog #1; see DISTRIBUTED-RENDERING-PLAN.md §7.2). Wires libvpx-vp9 webm through the distributed pipeline now that PR 8.1 proved concat-copy works. Architectural decision: Path A (concat-copy) — based on PR 8.1's smoke test result (9/9 tests pass for both yuv420p and yuva420p VP9 streams). The simpler architecture wins; no re-encode in assemble, no encode- parallelism loss. Changes: - plan.ts: - DistributedRenderConfig.format and PlanResult.format now include "webm" — type-level acceptance matches the runtime gate. - rejectUnsupportedDistributedFormat() no longer trips on webm. HDR mp4 remains the only refused configuration. - resolveEncoderTriple() returns libvpx-vp9-software + yuva420p + preset="good" for format="webm". yuva420p preserves alpha — the format's main reason for existing for web delivery. - codec= remains rejected for non-mp4 formats (mov is always ProRes 4444; webm is always libvpx-vp9). The error message lists all four distributed-supported formats. - FormatNotSupportedInDistributedError docstring updated to reflect the new reality (only HDR is unsupported). - freezePlan.ts: LockedRenderConfig.encoder gains "libvpx-vp9-software". Mirrors libx265-software / prores-software / png-sequence in shape; the chunk worker reads this discriminant to decide encode args. - renderChunk.ts: drops the now-incorrect cast that excluded webm from buildSyntheticRenderJob's format input; tightens the preset-format cast to include webm. - assemble.ts: docstring + comment updates. The mp4/mov concat-copy path is format-agnostic — webm uses the exact same code (applyFaststart is a no-op for webm via the existing chunkEncoder.ts gate; muxVideoWithAudio already routes webm to libopus audio). - planFormatBanlist.test.ts: webm-rejection tests removed; replaced with "accepts webm" tests + a HDR+webm combo test that verifies HDR is the trip regardless of format. - plan.test.ts: new describe block pins the webm wiring contract: format="webm" produces an encoder=libvpx-vp9-software / pixelFormat=yuva420p planDir with closedGop=true and gopSize=chunkSize. - webm-concat-copy.test.ts (smoke): extended with a yuva420p variant that proves the alpha pixel format the distributed pipeline actually emits also round-trips through concat-copy. 9/9 tests pass locally. §8 format support matrix in DISTRIBUTED-RENDERING-PLAN.md is intentionally left unchanged at this PR — it flips to ✓ in PR 8.4 once the end-to-end fixture (PR 8.3) is green. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * fix(producer): include webm in plan-time needsAlpha + strengthen alpha smoke PR review feedback from Miguel and Vai on #951 caught a real bug: `plan.ts`'s `needsAlpha` disjunction excluded `"webm"`, so the plan stage froze `forceScreenshot: false` into the `LockedRenderConfig` even though distributed webm uses `yuva420p`. Every chunk worker captured opaque RGB via BeginFrame (which doesn't preserve alpha on Linux headless-shell), and libvpx-vp9 encoded uniformly-opaque alpha that the encoder then dropped — producing un-keyable webm. Two changes: 1. **plan.ts**: include `"webm"` in `needsAlpha`. Matches the in-process renderer's logic at `renderOrchestrator.ts:1469` (`const needsAlpha = isWebm || isMov || isPngSequence`); the two sites must stay in sync since the distributed pipeline's PSNR regression compares against the in-process baseline. 2. **Smoke test (yuva420p describe)**: source frames now use a real alpha gradient (`geq=a='X*255/W'` on top of `testsrc2`) instead of `testsrc2 + format=rgba` which was uniformly opaque. The decode- pix_fmt assertion is dropped (ffprobe reports `yuv420p` for VP9-with-alpha because the alpha lives in a Matroska `BlockAdditional` sidecar) and replaced with two stronger checks: - `TAG:ALPHA_MODE=1` is present on the stream — proves the encoder was actually configured for alpha - alpha plane variance after `-c:v libvpx-vp9 -i ... -pix_fmt rgba -vf extractplanes=a,signalstats` — proves the alpha sub-stream round-trips through concat-copy with spatially-varying content, not uniform/dropped alpha - decode-test gate is now exit-code-only (was `exitCode || stderr` which would flake on chatty ffmpeg `-v error` builds emitting non-fatal DTS/container notes) These checks would have caught the `needsAlpha` bug before review. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * fix(aws-lambda): widen narrow format types to include webm CI on PR #951 was failing at typecheck/build because the producer's `DistributedRenderConfig.format` widened to include webm in this PR but the aws-lambda package's narrow `"mp4" | "mov" | "png-sequence"` type literals in `events.ts`, `handler.ts`, and `validateConfig.ts` hadn't kept up. `renderToLambda.ts:87` passed `config.format` (now including webm) into a parameter typed against the narrow union, producing TS2345. This widening originally landed in PR #952 (test fixture PR) but needs to be atomic with the producer's widening here to keep each PR independently typecheck-clean. Also refactor `formatExtension` from a switch dispatch to a `Record<DistributedFormat, string>` lookup. Adding the webm case tipped the switch's CRAP to the 30.0 fallow threshold; the lookup table drops cyclomatic from 5 to 1 with the same compile-time exhaustiveness guarantee (TS errors on missing entries when `DistributedFormat` adds a new format). The runtime `_exhaustive: never` throw was only protecting against a string slipping past TS; `validateConfig.ts`'s `ALLOWED_FORMATS` already gates untrusted input at the SDK boundary. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * test(producer): add webm-vp9 distributed regression fixture PR 8.3 of the WebM distributed-rendering plan (v1.5 backlog #1; see DISTRIBUTED-RENDERING-PLAN.md §7.2). End-to-end regression coverage for the webm distributed path PRs 8.1 and 8.2 wired up. Adds packages/producer/tests/distributed/webm-vp9/ matching the mp4-h264-sdr fixture pattern: a 2-second composition (60 frames @ 30fps) with text, a crossfade across the frame-30 chunk seam, and a continuous icon rotation — exercises chunk-boundary continuity for both display contents and VP9 closed-GOP alpha encoding. `chunkSize: 15` produces 4 chunks so 3 seams are tested, and the crossfade straddles the middle seam to surface alpha-plane discontinuities introduced by alt-ref drift. Baseline regenerated inside Dockerfile.test via `bun run --cwd packages/producer docker:test:update webm-vp9`. Runs in: - in-process mode: byte-identical match against baseline ✓ - distributed-simulated mode: PSNR 56.88-63.49 dB across 100 checkpoints, well above the 30 dB threshold ✓ Wiring updates required to let webm flow through the harness: - regression-harness-distributed.ts: - checkDistributedSupport() no longer rejects webm. HDR mp4 + NTSC fps + non-{24,30,60} fps remain rejected. - RunDistributedSimulatedInput.format widened to include webm. - Docstring + comments updated. - regression-harness-distributed.test.ts: webm-rejection test replaced with "accepts format=webm" test. - regression-harness.ts: the now-incorrect format cast at the distributed-input call site is dropped; comment about why webm was excluded is replaced with "webm is now distributed-supported". - regression-harness-lambda-local-types.ts: RunLambdaLocalInput.format widened to include webm so lambda-local mode can also exercise webm fixtures end-to-end. - aws-lambda webm support (Path A through the Lambda handler): - formatExtension.ts: DistributedFormat gains "webm" → ".webm" case. - events.ts: RenderChunkEvent / AssembleEvent / PlanLambdaResult Format widened to include webm. - sdk/validateConfig.ts: ALLOWED_FORMATS gains "webm". - handler.ts: downloadChunkObjects format param widened. The Lambda handler delegates to the producer's assemble() primitive which PR 8.2 already taught to handle webm (concat-copy + applyFaststart no-op + muxVideoWithAudio with libopus); no Lambda-side rendering changes are needed beyond the type/validation surfaces above. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * docs(aws-lambda): drop stale webm rejection from validateConfig docblock PR #952 review nit (Miguel): the validateConfig.ts file-header comment still claimed the SDK rejects webm, but the runtime check no longer does (ALLOWED_FORMATS now includes 'webm'). Update the docblock to reflect that only force-hdr remains an SDK-side rejection. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * ci(regression): add webm-vp9 to shard-3 + refactor formatExtension Three follow-ups bundled together (Vai's review feedback on PR #952 plus the fallow audit finding that surfaced when the webm case was added): 1. **Wire webm-vp9 into CI regression.** The fixture was added in this PR but never appeared in any `.github/workflows/regression.yml` shard's args allowlist, so the regression harness's positional-args gate skipped it in CI. Append `webm-vp9` to shard-3 (which already carries `mp4-h264-sdr` + `webm-transparency`) so the fixture runs. 2. **Fix stale "four hard gates" prose in checkDistributedSupport docstring.** Earlier in the stack I removed the webm bullet but didn't update the count. Two gates remain (fps + hdr). 3. **Refactor `formatExtension` from switch to lookup table.** Adding the webm case made the switch dispatch's CRAP score hit 30.0 (cyclomatic = 5, plus the function's small body). Replaced with a `Record<DistributedFormat, string>` lookup, which: - drops cyclomatic from 5 → 1, - keeps exhaustiveness enforcement at compile time (TS errors if a new format gets added to `DistributedFormat` without a matching key in the Record literal), - drops the runtime `_exhaustive: never` throw, which was only guarding against an arbitrary string slipping past TS — a caller-side concern, not this function's job. The function now reads as a table lookup, which matches what it actually does, and the fallow audit now reports zero new complexity findings (down from 1). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

Description
PR 2 of 4 in the WebM distributed-rendering series. Wires libvpx-vp9
webm through the
plan() → renderChunk() × N → assemble()pipelinenow that PR #950's smoke proved Path A (concat-copy) works.
Changes:
plan.ts:DistributedRenderConfig.formatandPlanResult.formatnowinclude
"webm".rejectUnsupportedDistributedFormat()no longer trips on webm.HDR mp4 remains the only refused configuration.
resolveEncoderTriple()returnslibvpx-vp9-software+yuva420p+preset="good"forformat: "webm".codec=remains rejected for non-mp4 formats. Error messagelists all four distributed-supported formats.
freezePlan.ts:LockedRenderConfig.encodergains"libvpx-vp9-software".renderChunk.ts: drops the now-incorrect cast that excluded webmfrom
buildSyntheticRenderJob's format input; tightens thepreset-format cast to include webm.
assemble.ts: docstring + comment updates. The mp4/mov concat-copypath is format-agnostic — webm uses the exact same code
(
applyFaststartis a no-op for webm via the existingchunkEncoder.tsgate;muxVideoWithAudioalready routes webm tolibopus audio).
planFormatBanlist.test.ts: webm-rejection tests removed; replacedwith "accepts webm" tests + an HDR-with-webm combo test that
verifies HDR is the trip regardless of format.
plan.test.ts: new describe block pins the webm wiring contract:format="webm"produces anencoder=libvpx-vp9-software/pixelFormat=yuva420pplanDir withclosedGop=trueandgopSize=chunkSize.webm-concat-copy.test.ts(smoke): extended with a yuva420p variantthat proves the alpha pixel format the distributed pipeline actually
emits also round-trips through concat-copy.
Fixup commit
fix(producer): include webm in plan-time needsAlpha + strengthen alpha smokeAddresses the blocker review feedback from Miguel and Vai:
plan.ts'sneedsAlphadisjunction excluded"webm", so the plan stage frozeforceScreenshot: falseinto theLockedRenderConfigeven though distributed webm usesyuva420p.Every chunk worker would have captured opaque RGB via BeginFrame
(which doesn't preserve alpha on Linux headless-shell), producing
un-keyable webm. Fixed to match the in-process renderer's
needsAlphalogic.only Y/U/V planes (no
psnr_a), so a perfectly-broken alpha planeregistered as 0 dB difference; the smoke test's
testsrc2 + format=rgbasource was uniformly opaque so the encoder downgradewas harmless; the
pix_fmt=yuva?420pregex accepted yuv420p output.forward: source frames now use
geq=a='X*255/W'(a real alphagradient), the test asserts
TAG:ALPHA_MODE=1on the stream, anddecodes the alpha plane via
-c:v libvpx-vp9 -pix_fmt rgbatosignalstats-check the variance.
Testing
bun test packages/producer/src/services/distributed/planFormatBanlist.test.ts— passesbun test packages/producer/tests/distributed/_smoke/webm-concat-copy.test.ts— passes (now exercises real alpha)bunx tsc --noEmit -p packages/producer/tsconfig.json— clean🤖 Generated with Claude Code