Skip to content

fix(producer): disk-headroom gate before hdr raw frame pre-extraction#2256

Merged
vanceingalls merged 2 commits into
mainfrom
07-11-fix_producer_disk-headroom-gate-before-hdr-pre-extraction
Jul 11, 2026
Merged

fix(producer): disk-headroom gate before hdr raw frame pre-extraction#2256
vanceingalls merged 2 commits into
mainfrom
07-11-fix_producer_disk-headroom-gate-before-hdr-pre-extraction

Conversation

@vanceingalls

@vanceingalls vanceingalls commented Jul 11, 2026

Copy link
Copy Markdown
Collaborator

What

Adds a disk-headroom gate before HDR raw-frame pre-extraction. estimateHdrExtractionBytes() computes the total rgb48le bytes the extraction will write (6 bytes/px × frame area × frame count); assertHdrExtractionDiskHeadroom() checks it against free space at the frames dir and throws with the --sdr escape hatch before FFmpeg starts writing, warning above 10 GB either way.

Why

Wild report: a plain iPhone HLG clip auto-detected as HDR triggered 16-bit raw-frame pre-extraction that filled a near-full disk before the user found --sdr; the composition used no HDR-specific features, so auto-detection was overeager and gave no warning.

Validation

3 new unit tests (estimateHdrExtractionBytes) covering byte math, multi-video accumulation, and negative-duration clamping. Full producer build clean.

Review history

  • Split the unrelated puppeteer-core symlink resync out into its own PR (chore(producer): resync stale committed puppeteer-core symlinks to lockfile version #2259) per review feedback — this PR now contains only the disk-headroom gate.
  • Addressed non-blocking review feedback: the original catch-and-rethrow-by-message-match discriminator (distinguishing a real headroom violation from a statfsSync failure via err.message.includes(...)) coupled control flow to exact error prose — a future message tweak would have silently failed open. Restructured so statfsSync failure returns early (skip the gate) and the headroom check/throw happens in plain control flow, no string matching.

🤖 Generated with Claude Code

@miga-heygen miga-heygen left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

#2256 — disk-headroom gate before hdr raw frame pre-extraction

Verdict: LGTM 🟢

Prevents HDR pre-extraction from filling the disk: estimateHdrExtractionBytes computes 6 bytes/pixel × frame area × frame count across HDR videos, assertHdrExtractionDiskHeadroom checks via statfsSync and throws if >90% of free space, warns >10 GB. Error message suggests --sdr as the escape hatch. statfsSync failures (unsupported platform) skip the gate silently — only the headroom violation itself propagates.

The re-throw pattern in the catch block works correctly: throw inside try is caught by the same catch, which checks err.message.includes("HDR pre-extraction needs") and re-throws only that. All other errors (statfsSync failures) are swallowed. Slightly unusual shape but functionally correct. Test covers the estimation math.

One note: the diff includes tracked node_modules symlink changes (puppeteer 24.43.1 → 25.3.0). These shouldn't be in the index — packages/producer/node_modules/ is a pre-existing tracked artifact that #2144 (in the other stack) would catch. Not a blocker for this PR.

Review by Miga

@miguel-heygen miguel-heygen left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Blocker: the PR diff includes tracked package-manager artifacts under packages/producer/node_modules/ (.bin/puppeteer, puppeteer, puppeteer-core symlinks) that point at a different Puppeteer/Bun installation. These are unrelated generated changes and make the branch non-hermetic. Remove them from the diff and add/verify ignore protection; keep only the source gate/tests. Re-run CI after cleanup.

@james-russo-rames-d-jusso james-russo-rames-d-jusso left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Reviewed at dec7c23.

Right layer, right escape hatch, right pre-flight ordering (throw BEFORE FFmpeg starts writing rather than mid-extraction). The byte math is straightforward, tests cover single-video math, multi-video accumulation, and negative-duration clamping.

Puppeteer symlink resync to 25.3.0 (semver-satisfies the lockfile's ^25.2.1) matches the CJS→ESM layout change in the bin symlink (lib/cjs/puppeteer/...lib/puppeteer/...). Unrelated to the gate but was blocking tsc --declaration — reasonable to bundle rather than land a stale-lockfile follow-up.

Two things, both non-blocking:

Nit — rethrow discriminator is fragile. assertHdrExtractionDiskHeadroom at packages/producer/src/services/render/stages/captureHdrResources.ts:145-147 uses err.message.includes("HDR pre-extraction needs") to rethrow the headroom violation while swallowing statfsSync errors. Works today, but couples the discriminator to the exact error prose — a future message tweak silently fails open (statfs unsupported takes the same code path as headroom violation → the gate goes quiet). Cleaner shape:

let freeBytes: number | null = null;
try {
  const stat = statfsSync(framesDir);
  freeBytes = stat.bavail * stat.bsize;
} catch { return; } // statfs unsupported → skip gate silently
// … now perform the check outside the try, throw plainly.

Question — observability of the reject path. Right now the gate throws with --sdr guidance; the throw propagates through extractHdrVideoFrames and shows up as a render failure. Is there a plan (either here or via Miguel's #2220 stalled-stage exposure) to emit a specific "hdr_extraction_disk_headroom_rejected" event before the throw? Distinguishing "user hit our pre-flight gate" from "FFmpeg died mid-write with ENOSPC" in aggregate telemetry is what lets you tune HDR_EXTRACTION_HEADROOM_FRACTION empirically.

LGTM from my side.

Review by Rames D Jusso

@vanceingalls vanceingalls force-pushed the 07-11-fix_producer_disk-headroom-gate-before-hdr-pre-extraction branch from dec7c23 to a9424d5 Compare July 11, 2026 20:46
…l flow to error-string matching

Addresses non-blocking review feedback on #2256: the previous shape used
err.message.includes(...) inside a catch to distinguish a real headroom
violation from a statfsSync failure — a future message tweak would silently
fail open (statfs-unsupported and headroom-violation would take the same
code path). Now statfsSync failure returns early (skip the gate) and the
headroom check/throw happens in plain control flow outside any try/catch.
@vanceingalls vanceingalls force-pushed the 07-11-fix_producer_disk-headroom-gate-before-hdr-pre-extraction branch from 0e69871 to c20e202 Compare July 11, 2026 21:18
@vanceingalls vanceingalls force-pushed the 07-11-feat_cli_preview_--browser-no-gpu_for_gpu-unstable_hosts branch from f3c3a15 to 3dc08c0 Compare July 11, 2026 21:18
Base automatically changed from 07-11-feat_cli_preview_--browser-no-gpu_for_gpu-unstable_hosts to main July 11, 2026 21:28
@vanceingalls vanceingalls merged commit 1dfb016 into main Jul 11, 2026
87 of 97 checks passed
@vanceingalls vanceingalls deleted the 07-11-fix_producer_disk-headroom-gate-before-hdr-pre-extraction branch July 11, 2026 21:38
miguel-heygen pushed a commit that referenced this pull request Jul 12, 2026
…l flow to error-string matching

Addresses non-blocking review feedback on #2256: the previous shape used
err.message.includes(...) inside a catch to distinguish a real headroom
violation from a statfsSync failure — a future message tweak would silently
fail open (statfs-unsupported and headroom-violation would take the same
code path). Now statfsSync failure returns early (skip the gate) and the
headroom check/throw happens in plain control flow outside any try/catch.
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.

4 participants