diff --git a/.github/workflows/regression.yml b/.github/workflows/regression.yml index c8dd04eb..98045c63 100644 --- a/.github/workflows/regression.yml +++ b/.github/workflows/regression.yml @@ -2,21 +2,10 @@ name: regression on: pull_request: - branches: [main] push: branches: - main -concurrency: - group: regression-${{ github.ref }} - cancel-in-progress: true - -# Least-privilege token: only reading code. Jobs that need more (e.g. GHA -# cache reads/writes from docker/build-push-action with `type=gha`) elevate -# their own permissions inline. -permissions: - contents: read - jobs: changes: name: Detect changes @@ -36,56 +25,11 @@ jobs: - "packages/engine/**" - "Dockerfile*" - # Build the regression Docker image once, export it as a tarball, and upload - # as an artifact. Each matrix shard then downloads + `docker load`s it instead - # of rebuilding from cache. Measured on PR #419: the Docker build step takes - # ~4 min per shard even with GHA cache, so 11 shards = ~44 min of redundant - # build time per run. This job replaces that with a single ~4 min build plus - # ~15s of artifact download per shard. - build-image: - name: Build regression test image - needs: changes - if: needs.changes.outputs.code == 'true' - runs-on: ubuntu-latest - timeout-minutes: 20 - permissions: - contents: read - actions: write # docker/build-push-action `type=gha` cache reads + writes - steps: - - name: Checkout - uses: actions/checkout@v4 - # No LFS needed here — Dockerfile.test only copies source + package manifests, - # not the golden baselines under packages/producer/tests/**/output. - - - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v3 - - - name: Build test image to tarball - uses: docker/build-push-action@v6 - with: - context: . - file: Dockerfile.test - tags: hyperframes-producer:test - cache-from: type=gha,scope=regression-test-image - cache-to: type=gha,mode=max,scope=regression-test-image - outputs: type=docker,dest=/tmp/regression-test-image.tar - - - name: Report image size - run: ls -lh /tmp/regression-test-image.tar - - - name: Upload image artifact - uses: actions/upload-artifact@v4 - with: - name: regression-test-image - path: /tmp/regression-test-image.tar - retention-days: 1 - compression-level: 1 - regression-shards: - needs: [changes, build-image] + needs: changes if: needs.changes.outputs.code == 'true' runs-on: ubuntu-latest - timeout-minutes: 40 + timeout-minutes: 60 strategy: fail-fast: false matrix: @@ -95,7 +39,7 @@ jobs: - shard: render-compat args: "--sequential gsap-letters-render-compat css-spinner-render-compat raf-ball-render-compat iframe-render-compat" - shard: hdr - args: "--sequential hdr-pq hdr-image-only" + args: "--sequential hdr-regression hdr-hlg-regression" - shard: styles-a args: "style-1-prod style-2-prod style-3-prod" - shard: styles-b @@ -130,16 +74,18 @@ jobs: fi done - - name: Download test image artifact - uses: actions/download-artifact@v4 - with: - name: regression-test-image - path: /tmp + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 - - name: Load test image - run: | - docker load -i /tmp/regression-test-image.tar - docker image ls hyperframes-producer:test + - name: Build test Docker image (cached) + uses: docker/build-push-action@v6 + with: + context: . + file: Dockerfile.test + load: true + tags: hyperframes-producer:test + cache-from: type=gha,scope=regression-test-image + cache-to: type=gha,mode=min,scope=regression-test-image - name: "Run regression shard: ${{ matrix.shard }}" run: | diff --git a/packages/engine/src/utils/ffprobe.test.ts b/packages/engine/src/utils/ffprobe.test.ts index 97bc1f69..20ebd588 100644 --- a/packages/engine/src/utils/ffprobe.test.ts +++ b/packages/engine/src/utils/ffprobe.test.ts @@ -55,7 +55,7 @@ describe("extractVideoMetadata", () => { it("reads HDR PNG cICP metadata when ffprobe color fields are absent", async () => { const fixturePath = resolve( __dirname, - "../../../producer/tests/hdr-image-only/src/hdr-photo.png", + "../../../producer/tests/hdr-regression/src/hdr-photo-pq.png", ); const metadata = await extractVideoMetadata(fixturePath); @@ -102,7 +102,7 @@ describe("extractPngMetadataFromBuffer", () => { it("continues to parse the checked-in HDR PNG fixture", () => { const fixture = readFileSync( - resolve(__dirname, "../../../producer/tests/hdr-image-only/src/hdr-photo.png"), + resolve(__dirname, "../../../producer/tests/hdr-regression/src/hdr-photo-pq.png"), ); expect(extractPngMetadataFromBuffer(fixture)?.colorSpace?.colorTransfer).toBe("smpte2084"); }); diff --git a/packages/producer/tests/hdr-hlg-regression/README.md b/packages/producer/tests/hdr-hlg-regression/README.md new file mode 100644 index 00000000..1ce0abdc --- /dev/null +++ b/packages/producer/tests/hdr-hlg-regression/README.md @@ -0,0 +1,52 @@ +# hdr-hlg-regression + +Regression test that locks down end-to-end **HDR HLG (BT.2020 ARIB STD-B67)** +video rendering. Companion to `hdr-regression` (PQ), kept as a separate suite +so the HLG-specific encoder/metadata path stays tested in isolation. + +## What it covers + +| Window | Time | Shape | Expected | +| ------ | ------------ | ------------------------------------- | -------- | +| A | 0.0 – 2.5 s | Baseline HLG video + DOM overlay | pass | +| B | 2.5 – 5.0 s | Wrapper opacity fade around HLG video | pass | + +The test pins the contract that: + +- `extractVideoMetadata` reports `bt2020/arib-std-b67/limited` for the HLG + source (i.e. HLG is detected and not silently coerced to PQ). +- `isHdrColorSpace` flips the orchestrator into the layered HDR path on the + HLG signal. +- The HLG source is decoded into `rgb48le` and blitted under the SDR DOM + overlay on every frame. +- Wrapper-opacity composition (window B) does not break HLG pass-through. +- `hdrEncoder` writes HEVC Main10 / `yuv420p10le` / BT.2020 HLG with the + correct color tags (no PQ mastering display metadata for HLG). + +The suite is intentionally short (5 s, two windows) — it exists to detect +regressions in the HLG-specific code path, not to enumerate every composition +shape (those live in `hdr-regression`). + +## Tolerance + +`maxFrameFailures` is **0** here. HLG is a pure pass-through path — no known +failures, no transcoder workarounds — and HEVC encoding against the rendered +`rgb48le` buffer is byte-deterministic on the same fixture. Any drift is a +real regression, not codec noise, so the budget is the strictest possible. + +## Fixture + +`src/hdr-hlg-clip.mp4` — last 5 seconds of a user-recorded HEVC HLG clip, +remuxed (no re-encode) so the HLG color tags survive verbatim. + +## Running + +```bash +cd packages/producer +bun run test hdr-hlg-regression + +bun run test:update hdr-hlg-regression +``` + +In CI it runs in the `hdr` shard alongside `hdr-regression` +(see `.github/workflows/regression.yml`). diff --git a/packages/producer/tests/hdr-hlg-regression/meta.json b/packages/producer/tests/hdr-hlg-regression/meta.json new file mode 100644 index 00000000..95c16379 --- /dev/null +++ b/packages/producer/tests/hdr-hlg-regression/meta.json @@ -0,0 +1,14 @@ +{ + "name": "hdr-hlg-regression", + "description": "Regression test for HDR HLG (BT.2020 ARIB STD-B67) video pass-through. Two windows: (A) baseline HLG video + SDR DOM overlay, (B) wrapper-opacity fade applied to an HLG video. Verifies that an HLG HEVC source drives the layered HDR pipeline end-to-end (extractVideoMetadata reports hlg, ffmpegFrameSource decodes correctly, hdrEncoder writes HEVC Main10 / yuv420p10le / BT.2020 HLG with the appropriate mastering metadata) and that opacity composition does not break HLG signal pass-through.", + "tags": ["regression", "hdr"], + "minPsnr": 28, + "maxFrameFailures": 0, + "minAudioCorrelation": 0, + "maxAudioLagWindows": 1, + "renderConfig": { + "fps": 30, + "workers": 1, + "hdr": true + } +} diff --git a/packages/producer/tests/hdr-pq/output/compiled.html b/packages/producer/tests/hdr-hlg-regression/output/compiled.html similarity index 54% rename from packages/producer/tests/hdr-pq/output/compiled.html rename to packages/producer/tests/hdr-hlg-regression/output/compiled.html index 7e6ea014..de20c611 100644 --- a/packages/producer/tests/hdr-pq/output/compiled.html +++ b/packages/producer/tests/hdr-hlg-regression/output/compiled.html @@ -24,7 +24,21 @@ font-display: block; } -