Commit Graph
3200 Commits
Author SHA1 Message Date
James 51cbbe6fc9 fix(regression): schedule plan v2 color fixture 2026-07-27 02:31:46 +00:00
James Russo f67012eb9f ci(regression): compute the shard matrix from recorded fixture timings (#2815)
* ci(regression): compute the shard matrix from recorded fixture timings

* ci(regression): refresh shard timings from a green post-PSNR run

* fix(ci): close two silent-skip holes in the shard schedule contract

* ci(regression): schedule the new static-volume-future-set fixture

* test(producer): regenerate static-volume-future-set golden in the pinned container
2026-07-26 19:16:39 -07:00
James Russo 0cc78c1d42 chore: release v0.7.74 (#2818) v0.7.74 2026-07-26 21:57:54 -04:00
James Russo 58869f0878 fix(producer): accept partial color metadata in plan v2 (#2814)
* fix(producer): accept partial color metadata in plan v2

* test(engine): make partial color probe hermetic

* fix(producer): validate plan v2 sentinels in fallback mode
2026-07-26 21:48:51 -04:00
James Russo 98a4cd70fd perf(producer): compute regression PSNR in one ffmpeg pass (#2813)
* perf(producer): compute regression PSNR in one ffmpeg pass

* fix(producer): fail loudly when one PSNR input runs out of frames
2026-07-26 18:14:53 -07:00
James Russo f03b7e0fcf Merge pull request #2817 from heygen-com/fix/2810-gcp-beginframe-contract
fix(gcp): enforce effective BeginFrame capture
2026-07-26 18:11:53 -07:00
James Russo 6c98e54064 Merge pull request #2816 from heygen-com/fix/2809-static-volume-live-seek
fix(core): avoid live volume probe during render
2026-07-26 18:11:12 -07:00
James 2a284a8e3a fix(gcp): enforce effective BeginFrame capture 2026-07-27 00:02:37 +00:00
James 477defc7e7 fix(core): avoid live volume probe during render 2026-07-26 22:39:58 +00:00
James Russo 2dddb4c463 Merge pull request #2812 from heygen-com/release/v0.7.73
chore: release v0.7.73
v0.7.73
2026-07-26 17:36:13 -04:00
James 527751c871 chore: release v0.7.73 2026-07-26 21:25:03 +00:00
James Russo 8efc47c21c fix(producer): align frame coverage with extraction rounding (#2770)
## What

- model expected video-frame counts using the same rounding contract as the extraction branch:
  - CFR `-vf fps=<fps>`: nearest output-frame boundary
  - VFR `-fps_mode cfr -r <fps>`: ceil
- retain fail-closed ceil behavior when extraction metadata is missing
- keep positive sub-frame clips at a minimum of one expected frame
- preserve the existing 95% truncation gate and source-duration credit

## Why

The coverage gate universally used `ceil(duration * fps)`, but FFmpeg's CFR fps filter rounds to the nearest boundary. This made successfully extracted short CFR clips such as 0.616666s at 30 fps look truncated (18 captured vs 19 expected).

In the dashboard window, 124 of 335 video-coverage failures were exactly one frame short. Historical logs do not include `isVFR`, so that is the maximum addressable cohort rather than a guaranteed reduction. Zero-frame and materially truncated extraction failures remain fail-closed.

## Safety

- VFR still uses ceil and the existing strict coverage threshold.
- Missing extraction metadata still uses ceil.
- No retry, fallback, Temporal workflow, or render-plan behavior changes.
- Intended rollout is through the producer sidecar canary with explicit internal in-process jobs before dev and production promotion.

## Test

- `bunx vitest run packages/producer/src/services/render/videoFrameCoverage.test.ts` (28 passed)
- `bun run --filter @hyperframes/producer typecheck`
- `bunx oxlint ...videoFrameCoverage.ts ...videoFrameCoverage.test.ts`
- `bunx oxfmt --check ...videoFrameCoverage.ts ...videoFrameCoverage.test.ts`
- `bunx fallow audit --base origin/main --fail-on-issues`
- repository pre-commit gates
2026-07-26 17:20:25 -04:00
James f0c2c7d233 fix(producer): align frame coverage with extraction rounding 2026-07-26 20:33:19 +00:00
James Russo f500a42d9e fix(producer): type video extraction failures (#2776)
## Summary
- classify per-source video download/probe/decode/extraction failures with a bounded taxonomy and safe producer-facing summaries
- add candidate-only, at-most-one transient retry with cleanup and retry telemetry
- preserve default engine/producer behavior when the policy is off
- carry allowlisted extraction error codes through blocking JSON and SSE responses

## Stack
Depends on #2774 for atomic remote downloads and its single owned download retry. This PR is intentionally based on `fix/atomic-video-download-retry`; rebase/change the base to `main` after #2774 merges.

## Default compatibility
`HF_VIDEO_EXTRACTION_FAILURE_MODE` defaults to `off` and forces `maxTransientRetries=0`.

With the feature off:
- metadata probe failures keep the legacy Promise rejection
- grouped extraction keeps the existing grouped-to-direct fallback
- no new producer failure gate is enforced
- render-plan schema, Plan v1 artifacts, chunk routing, and distributed execution are unchanged

Typed metadata aggregation is explicit and enabled only by the candidate enforce lane.

## Retry ownership
- remote downloads: exactly one retry owned by #2774
- metadata/FFmpeg extraction: at most one retry only when `HF_VIDEO_EXTRACTION_MAX_RETRIES=1`
- invalid, missing, rejected, out-of-range, zero-output, cancellation, and unknown/internal failures do not retry
- non-finite or invalid runtime retry budgets fail closed to zero
- the superset optimization is never retried; on failure it preserves direct-member fallback, and only the individual ranges can use the bounded retry
- retry counters increment when a retry is scheduled, including exhausted retries

The internal sidecar and Experiment Framework must treat both exhausted stage codes as workflow-terminal after the producer-local budget. Candidate enforcement must not be enabled until those companion mappings are deployed, or Temporal can multiply producer attempts.

## Failure contract
- `VIDEO_SOURCE_UNRENDERABLE`: at least one deterministic/unknown source failure
- `VIDEO_EXTRACTION_FAILED`: all source failures are transient but the producer-local budget is exhausted

Only the allowlisted code and kind/count summaries cross JSON/SSE. Raw diagnostics remain engine-local because they may contain signed URLs or local paths.

## Rollout
1. merge and deploy with stable/candidate both `off`
2. candidate `observe`, retries 0
3. candidate `observe`, retries 1
4. deploy internal + EF terminal transport mappings
5. candidate `enforce`, retries 1
6. keep stable off until success delta, retry counts, extraction latency, CPU/disk, and queue backlog are acceptable

## Validation
- engine focused suites: 105 passed
- producer focused suites: 15 passed
- full engine suite: 1,176 passed, 3 skipped
- full producer unit lane: 32 Vitest files / 393 tests plus all classified Bun unit tests
- engine and producer typechecks passed
- oxlint, oxfmt, Fallow, tracked-artifact, and commit hooks passed
- independent review: approved for merge default-off; candidate enforcement held on companion transport rollout
2026-07-26 16:33:00 -04:00
James 33ca1de063 fix(render): aggregate extraction launch failures 2026-07-26 19:47:33 +00:00
James c01e1a5f96 fix(producer): narrow extraction error shapes honestly 2026-07-26 19:47:33 +00:00
James 9b63646c8a fix(producer): type video extraction failures 2026-07-26 19:47:33 +00:00
James Russo 814f9cd977 fix(engine): make remote video downloads atomic (#2774)
## Summary
- stage remote video downloads in private per-attempt directories and atomically publish only complete non-empty files
- keep the deadline active through response-body streaming and retry one bounded transient failure
- preserve render cancellation without sharing abort ownership across independent callers
- manually follow at most five redirects, validating HTTPS/public-host policy before every hop
- remove stale zero-byte finals and avoid a permanent render-scoped cache map

## Root cause
The previous downloader wrote directly to the final cache path and cleared its timeout as soon as response headers arrived. A body timeout or mid-stream socket reset could therefore leave a truncated file at a path that later extraction treated as complete. The downstream symptom was zero extracted frames followed by a generic video coverage failure.

## Retry policy
Exactly one retry is allowed for 408, 429, 5xx, timeouts, empty successful bodies, and network/socket failures including nested Undici errors. Cancellation, 404/410, other 4xx, URL/redirect validation errors, and filesystem errors are not retried.

## Security and portability
- `mkdtempSync` creates an unguessable same-filesystem staging directory; exclusive writes plus atomic rename prevent symlink planting and partial publication
- redirects use `redirect: "manual"` and every resolved `Location` is revalidated before the next request, blocking redirect-to-private/IMDS bypasses
- the partial file is opened read/write for `fsync`, which preserves flush semantics and avoids Windows `EPERM`

## Rollout safety
This does not change render-plan schema, Plan v1 artifacts, chunk routing, or distributed rendering semantics. It is suitable for the candidate sidecar lane first; stable can remain pinned while we compare video extraction and coverage failures.

## Validation
- focused urlDownloader suite: 28 passed
- full engine suite: 1,169 passed, 3 skipped
- engine typecheck passed
- oxlint and oxfmt passed
- fallow audit passed
- independent code review: approved, no blockers
2026-07-26 15:45:50 -04:00
James 2e84faeb28 fix(engine): block future-use IPv4 downloads 2026-07-26 19:00:41 +00:00
James 4b81f78586 fix(engine): close downloader trust-boundary gaps 2026-07-26 19:00:41 +00:00
James 5ce2eb879d fix(engine): narrow network error shapes honestly 2026-07-26 19:00:41 +00:00
James c01f6b4468 fix(engine): make video downloads atomic and retry transient failures 2026-07-26 19:00:41 +00:00
James Russo a8ee81f3d8 fix(producer): attribute and stop oversized plans early (#2773)
## What

- add an exact, symlink-safe plan-size breakdown with fixed or hashed component labels
- reject oversized plans after the compiled tree stabilizes, before video extraction
- reject again after artifact promotion but before the full freeze/hash read
- retain the exact post-freeze ceiling check and existing `PLAN_TOO_LARGE` contract/message prefix
- remove only freeze-owned stale metadata before the preliminary check when callers reuse a plan directory

## Why

The existing ceiling only runs after a multi-GiB plan has been fully materialized and hashed. Production examples range from roughly 3 GiB to 12.6 GiB. This gives us enough attribution to design Plan v2 from real data while avoiding obviously wasted extraction and hashing work.

## Compatibility and rollout

- no v1 plan artifact or `plan.json` format changes
- no queue, routing, retry, worker-count, or steady-state render changes
- under-limit plan bytes/hashes remain governed by the existing freeze path
- intended for the candidate sidecar and canary lane before broader rollout

This does not interrupt a single FFmpeg extraction once it is running. A canaried extraction-budget monitor is a separate follow-up.

## Validation

- focused distributed-plan tests: 54 passed
- full producer unit lane: 31 Vitest files / 384 tests plus all classified Bun lanes passed
- typecheck, lint, format, Fallow, tracked-artifact checks passed
- independent code review approved
2026-07-26 15:00:14 -04:00
James ebb02cafe7 fix(producer): reset distributed plan scratch state 2026-07-26 18:12:15 +00:00
James d699cbf014 fix(producer): attribute and stop oversized plans early 2026-07-26 18:12:15 +00:00
Ular Kimsanov 5bfda4e087 Merge pull request #2797 from heygen-com/feat/studio-professional-color-grading
feat(studio): add professional grading controls
2026-07-26 10:45:43 -07:00
Ular Kimsanov e2e61b0767 Merge pull request #2798 from heygen-com/feat/agent-native-color-grading
feat(cli): expose agent-native color grading
2026-07-26 03:23:29 -07:00
Ular Kimsanov 7fa85fb057 Merge pull request #2796 from heygen-com/feat/professional-color-grading-core
feat(core): add professional color grading controls
2026-07-26 02:38:42 -07:00
ukimsanov 794930a075 fix(studio): align professional grading contracts 2026-07-26 01:47:06 -07:00
ukimsanov c1fcf7534f fix(studio): clear stale color scopes 2026-07-26 01:29:32 -07:00
ukimsanov 20ef48abcb feat(studio): add professional grading controls 2026-07-26 01:29:32 -07:00
ukimsanov 20f4bde46a test(cli): harden media treatment parity 2026-07-26 01:29:05 -07:00
ukimsanov 9b504045f7 fix(core): register media analyzer subpath 2026-07-26 01:25:42 -07:00
ukimsanov c1dde28980 fix(cli): address media treatment review findings 2026-07-26 01:25:42 -07:00
ukimsanov 6d5961b802 feat(cli): expose agent-native color grading 2026-07-26 01:25:42 -07:00
ukimsanov e446de6023 fix(core): align secondary mask contracts 2026-07-26 01:25:16 -07:00
James Russo 5c5179bb12 feat(gcp-cloud-run): publish plan v2 directly to GCS (#2799)
## What

- publishes Plan v2 content-addressed artifacts directly from the Cloud Run planner's private staging directory to GCS
- commits the Plan v2 manifest only after every referenced artifact is durable
- removes the second local Plan v2 CAS directory and preserves the existing Cloud Workflows wire contract
- exports a reusable GCS publisher adapter

## Why

Cloud Run planner, chunk, and assembler requests are independent containers and do not share a filesystem. The distributed contract must contain only durable GCS locators.

This layer makes the Plan v2 publication path object-store-native. Like the AWS parent PR, it still relies on one planner-local frozen v1 tree inside the producer; eliminating that remaining staging tree requires direct Plan v2 emission in a later layer.

## Design invariants

- local paths never cross a request or worker boundary
- manifest and artifact locators derive from one validated GCS output prefix
- immutable objects use generation-zero conditional creation and exact digest/size verification
- retries may reuse exact objects but never overwrite conflicts
- the manifest is the final publication commit point
- chunk and assembler requests independently download and verify only their target artifacts

## Test plan

- [x] all 95 GCP Cloud Run package tests pass
- [x] package typecheck passes
- [x] package build passes
- [x] changed-file lint, format, fallow, and repository commit gates pass
- [x] end-to-end adapter test covers plan, target-scoped chunk, and assemble through Fake GCS with no shared local directory
2026-07-26 04:12:50 -04:00
ukimsanov 9a515858c9 fix(core): preserve curve compiler subpath exports 2026-07-25 23:38:32 -07:00
James Russo a06973064a Merge pull request #2795 from heygen-com/feat/plan-v2-aws-direct-publisher
feat(aws-lambda): publish plan v2 directly to S3
2026-07-26 02:23:35 -04:00
ukimsanov 1ffef9a262 fix(core): address grading review findings 2026-07-25 23:16:50 -07:00
James Russo 72ae39e3d0 chore: release v0.7.72 (#2800) v0.7.72 2026-07-26 02:01:10 -04:00
James 74d7bfde48 feat(gcp-cloud-run): publish plan v2 directly to GCS 2026-07-26 05:48:38 +00:00
James 09998789b5 feat(aws-lambda): publish plan v2 directly to S3 2026-07-26 05:47:56 +00:00
ukimsanov f99fc4e568 feat(core): add professional color grading controls 2026-07-25 22:15:30 -07:00
James Russo 07f9a3de95 refactor(producer): add remote-ready plan v2 publisher (#2792) 2026-07-26 00:53:50 -04:00
James Russo 0499a5cbcb fix(gcp-cloud-run): normalize v2 integrity codes (#2790) 2026-07-25 23:59:36 -04:00
James Russo 5bf61d6df0 feat(aws-lambda): support plan protocol v2 (#2789)
* feat(aws-lambda): support plan protocol v2

* fix(aws-lambda): align SAM v2 terminal errors
2026-07-25 23:42:51 -04:00
James Russo c6fdd9c015 fix(producer): document read-only plan hashing (#2788) 2026-07-25 23:20:36 -04:00
James Russo f9f00b0efc feat(producer): version distributed plan protocol (#2777) 2026-07-25 19:17:07 -04:00
Miguel Ángel 5ac3a7a3d0 fix(render): trim AAC packet padding exactly (#2531)
## What

Normalize both padded and trimmed render audio on the decoded sample timeline, encode the result as AAC in M4A, and keep the no-op path on stream copy. Final video muxing remains stream-copy only.

## Why

AAC packet-copy operations cannot guarantee the requested presentation duration. Trimming could retain a packet-boundary tail, while padding by concatenating a separately encoded raw-ADTS silence segment could create a timestamp/bitrate discontinuity that surfaced as roughly 606 ms of apparent audio drift in the production-style regression.

## How

- Trim with `atrim` plus `asetpts`, then AAC-encode into M4A.
- Pad with `apad=whole_dur`, cap the output at the target duration, and AAC-encode the continuous sample timeline into M4A.
- Preserve the M4A encoder-delay edit list when the normalized audio is copied into the final MP4.
- Use the normalized M4A path in both local and distributed assembly; leave already-correct audio unchanged.
- Remove the obsolete raw-ADTS concat helpers and the disproven final-mux duration workaround.

## Test plan

- [x] 18 focused pad/trim unit tests
- [x] Real-media integration regression covering the packet-timeline boundary
- [x] Producer typecheck and repository commit hooks
- [x] Faithful Docker `style-3-prod` regression: video/audio approximately 16.07 s, 1 ms drift, zero visual failures
- [x] Exact-head required CI was green before the review-cleanup commit; fresh exact-head CI is running
- [ ] Documentation updated (not applicable)

The regression was reproduced before the fix with 0.563416 s of reported audio/video drift. The sample-timeline normalization removes the malformed tail while preserving stream-copy final muxing and preview behavior.
2026-07-26 00:02:52 +02:00