Commit Graph
100 Commits
Author SHA1 Message Date
James Russo ed3ff98ce0 fix(cli): stop skills update deleting skills the manifest never covered (#3118)
`hyperframes skills update` deleted skills that the same command had just
installed, from every agent directory on the machine, and reported them as
"no longer published".

`skills add --skill '*'` installs every skill in the repo — including the
repo-native ones under `.claude/skills/` and `.agents/skills/` — and the
upstream lock attributes all of them to `heygen-com/hyperframes`. The published
manifest is generated from `<repoRoot>/skills` only (gen-skills-manifest.ts), so
it never lists those. detectRemoved read that silence as "removed upstream" and
pruned them, so `check || update` could not converge: `add` reinstalled them and
the next `update` deleted them again.

Scope removed-detection to skills the manifest is actually authoritative for,
using the lock's `skillPath` — the only field that separates a skill installed
from `skills/` from one installed out of the same repo's other skill roots
(`source` is identical for both). An entry with no `skillPath` is treated as not
covered: this is a delete path, so unknown provenance fails safe.

Also resolve the prune's manifest canonically. Its notion of "still published"
could otherwise come from any `skills-manifest.json` within 16 parent
directories of cwd, which — since HyperFrames' own manifest declares
`source: heygen-com/hyperframes` — matches lock attribution and drives deletion.
The install-side check already did this (#2176); the deleting path did not, and
the comment claiming that was deliberate and "tested separately" had no such
test. An explicit `--source` still wins.

Verified end to end against the real CLI in a sandboxed HOME. Before: `add`
installed 25 skills, `update` printed "Removing 6 skill(s) no longer published:
captions-overlay, changelog-video, cut-the-curve, motion-doctrine,
oversized-cursor, seam-craft" and deleted all six (27 dirs -> 21). After: no
removal line, 27 -> 27. Both new regression tests fail on the pre-fix source.

Fixes #3111
2026-08-08 12:43:53 -07:00
James 7640adc5f2 fix(cli): refresh identity persistence classification 2026-08-07 09:31:59 -07:00
James Russo 27d113e56c docs: add user interview booking links (#3059) 2026-08-05 12:35:58 -07:00
James Russo bbdfee1166 fix(engine): validate remote download integrity (#2938) 2026-08-04 18:02:01 -07:00
James Russo 127eb19371 fix(producer): correct short VFR frame coverage (#2936)
* fix(producer): correct short VFR frame coverage

* fix(engine): keep VFR extraction seek-local

* fix(engine): match ffmpeg decimal frame boundaries

* fix(engine): preserve exact extraction frame rates

* fix(engine): key frame cache by exact rate
2026-08-03 18:42:03 -07:00
James Russo 9792c32950 fix(producer): reject asset media type mismatches (#2937)
* fix(producer): reject asset media type mismatches

* fix(engine): document read-only AVIF probe

* fix(engine): bound read-only AVIF brand probe

* fix(producer): make media preflight lifecycle-safe

* fix(producer): reconcile runtime media before preflight

* fix(engine): avoid writable file-open detection

* fix(producer): close runtime media preflight gaps
2026-08-03 18:16:41 -07:00
James Russo 1d0d4d8939 docs(changelog): weekly digest 2026-07-27–2026-08-03 (#2969)
* docs(changelog): weekly digest 2026-07-27–2026-08-03

* docs(changelog): embed weekly video for 2026-07-27 to 2026-08-03
2026-08-03 15:08:01 -04:00
James Russo 1e51eaec2c chore: release v0.7.90 (#2958) 2026-08-02 21:57:19 -07:00
James Russo d6191965cf fix: pin release publishing to merge commit (#2959) 2026-08-02 21:32:08 -07:00
James Russo 2339757377 fix: bound HDR and video extraction resources (#2955)
* fix: bound HDR and video extraction resources

* fix: trim negative video extraction preroll

* fix: skip invisible video extraction windows

* fix: preserve negative-start loop and held tails

* fix: cap finite video slots to source duration

* fix: bound held-tail frame extraction

* fix: plan from playable video duration

* fix: preserve open-ended held video tails

* fix: resolve held tails from decoded frames

* fix: normalize final-frame probe timestamps

* fix: handle unseekable final-frame sources

* fix: dedupe final-frame probes per render

* refactor: clarify output dynamic range contract
2026-08-02 20:21:54 -07:00
James Russo 3a6b7f0612 fix: align local WebGPU capture behavior (#2907)
* fix: align local WebGPU capture behavior

* fix: address WebGPU capture review feedback

* fix: retain overlapping GPU seek work

* fix: satisfy runtime seek completion types

* fix: drain concurrent GPU seek work

* fix: prevent WebGPU capture barrier starvation

* fix: keep WebGPU presentation active during render seeks
2026-07-30 21:52:30 -07:00
James Russo 1d636f603c refactor(producer): share plan execution builder (#2906)
## What

Refactor distributed planning around one shared local execution-plan builder:

- `buildLocalExecutionPlan()` now owns compile/probe/extract/audio/freeze.
- Legacy `plan()` remains a deprecated v1 transport wrapper.
- Plan v2 calls the shared builder directly and publishes through the existing manifest/CAS contract.
- Add neutral `createPlanV2FromExecutionPlan()`, `publishPlanV2FromExecutionPlan()`, `getPlanV2ExecutionPlanHash()`, and `PLAN_PROTOCOL_V1` names.
- Retain deprecated v1-named exports and wire aliases.
- Recommend explicit Plan v2 opt-in for new producer, Lambda, and Cloud Run integrations.

## Why

Plan v2 previously looked like it invoked a v1 planner even though v1 and v2 share the same frozen local execution representation. This removes that migration-era coupling while preserving the public minor-version compatibility contract.

## How

The shared builder returns neutral internal execution-plan fields. The v1 wrapper maps those fields back to the existing `PlanResult`; the v2 publisher consumes them directly.

Compatibility is intentional and covered by exact shape tests:

- omitted `planProtocol` still serializes/selects `"v1"`;
- v1 layouts, descriptor-less decoding, event unions, workflow branches, and exports remain;
- the v1 descriptor JSON is byte-identical and `CURRENT_PLAN_PROTOCOL` is an identity-preserving alias;
- v2 manifest bytes, key order, hash framing, and `sourcePlanV1Hash` wire key remain unchanged;
- no enumerable neutral hash field was added to manifests or returned result objects;
- v1/v2 result objects, cloud event payloads, and SDK handle key sets remain unchanged.

## Test plan

- Focused Plan v1/v2/protocol/export/size compatibility: 141 passed
- `@hyperframes/core`: 1,419 passed
- `@hyperframes/producer` unit lane: 990 passed
- `@hyperframes/aws-lambda`: 140 passed
- `@hyperframes/gcp-cloud-run`: 101 passed
- Producer, Lambda, and Cloud Run typechecks
- Repository-wide lint, format check, workspace/package-subpath checks
- Full workspace build
- `git diff --check`

- [x] Unit tests added/updated
- [ ] Manual testing performed
- [x] Documentation updated (if applicable)
2026-07-30 17:41:02 -07:00
James Russo 7b3d3db8ad test(pr-to-video): pin the code-vocabulary section of the frame packet (#2900)
Adds three test cases pinning the code-vocabulary section that frame-packets.mjs appends to code frames. Deleting codeVocabularySection outright left all 455 skills tests green before this change; the only assertion touching it was a doesNotMatch that passes trivially when the section is empty.
2026-07-30 11:40:51 -07:00
James 0d42d65525 chore: release v0.7.81 2026-07-29 06:11:11 +00:00
James Russo 20f4f8f49c fix(producer): retry transient deterministic font fetches (#2865)
* fix(producer): retry transient deterministic font fetches

* fix(producer): secure Lambda font cache directory
2026-07-28 22:49:03 -07:00
James Russo 557d82b6a9 fix(producer): validate distributed video metadata (#2839)
## What

- enforce a finite, validated `meta/videos.json` contract shared by Plan v1 and Plan v2
- preserve authored finite ends and source-derived trim-aware ends; bound any still-open end at the validated composition end
- fail distributed planning when any declared video source did not extract instead of publishing a blank-capable plan
- make the v1 chunk reader reject malformed/null video timing before frame injection
- route deterministic video-source/metadata failures as non-retryable in AWS and GCP while retaining retries for transient extraction failures

## Why

An open-ended video whose remote source could not be resolved retained `Infinity` through planning. Plan v2 correctly rejected that value, while Plan v1 serialized it as `null`; the v1 frame lookup could then suppress injected frames and silently produce incorrect output.

The invariant belongs at the shared metadata boundary. Both protocols must receive identical finite timing, and unavailable sources must fail closed before plan publication.

## Test plan

- [x] producer distributed planning, metadata, v1 chunk boundary, Plan v2 conversion/materialization, and public exports
- [x] core runtime media semantics (authored slots, natural duration, looping, non-looping hold)
- [x] engine video extraction and frame lookup
- [x] AWS Lambda/CDK/SAM and GCP Cloud Run error normalization/retry classification
- [x] producer, core, engine, AWS, and GCP typechecks/builds
- [x] formatting, oxlint, tracked-artifact, fallow, and commit hooks
- [x] exact incident composition replayed through the AWS Lambda handler's Lambda-local path in a Lambda-like container; Plan v1 and Plan v2 both fail closed as `VIDEO_SOURCE_UNRENDERABLE` during planning, before plan publication
- [x] full PR CI, including all nine regression shards and Windows render/tests

No production flags or deployment/release workflows are changed.
2026-07-28 00:42:36 -07:00
James Russo 49cfc1c80c refactor(cli): extract telemetry delivery into transport.ts (#2344)
## What

Extracts the reliability-critical telemetry **delivery layer** — the in-memory event queue, async `flush()`, and the exit-time detached-child `flushSync()` — out of `packages/cli/src/telemetry/client.ts` into a new `transport.ts`.

`client.ts` stays the CLI-facing **policy** layer:
- `shouldTrack()` opt-out checks (dev mode, `DO_NOT_TRACK`, `HYPERFRAMES_NO_TELEMETRY`, config)
- `trackEvent()` system-metadata enrichment
- `showTelemetryNotice()` first-run disclosure

…and re-exports `flush` / `flushSync`, so `events.ts`, `index.ts`, and the `cli.ts` exit handlers keep importing from `./client.js` **unchanged**.

## Why

This is the code path that had the process-exit data-loss bug fixed in #2105 — render telemetry was ~6× undercounted and geographically US-skewed because the old drain-first flush emptied the queue before delivery confirmed, and the render command's `process.exit()` teardown killed the in-flight request. Isolating the delivery mechanism into its own focused, dependency-light module (only `./config` + node builtins) keeps that subtle, reliability-critical path in one place and reduces `client.ts` to just policy.

Follow-up to the render-telemetry-gap investigation. A delivery-health canary was also added to the [CLI Observability dashboard](https://us.posthog.com/project/356858/dashboard/1634055) — `render_complete ÷ successful render commands`, which should sit ~1.0 and would surface any regression of this class immediately.

## How

Pure code motion — **no behavior change, public API identical**. `transport.ts` owns the queue and stamps each event's dedup `uuid` + ISO timestamp in a new `enqueue()`; `trackEvent()` enriches with system metadata then calls `enqueue()`. `buildPayload`/`flush`/`flushSync` bodies are moved verbatim.

## Test plan

- [x] `vitest run src/telemetry/client.test.ts src/telemetry/events.test.ts` → **38/38 pass** (client.test.ts still validates queue-retention, uuid idempotency, and the detached-child flushSync path through the public API — unchanged)
- [x] `oxlint` clean, `oxfmt --check` clean
- [x] `tsc --noEmit` — no new type errors in `telemetry/`
- [x] `bun run build` succeeds

🤖 Generated with [Claude Code](https://claude.com/claude-code)
2026-07-27 18:32:49 -07:00
James Russo 4b75eb1f25 docs(changelog): weekly digest 2026-07-20–2026-07-27 (#2833)
## What

Adds the weekly digest entry for July 20 to July 27, 2026 to `docs/weekly-updates.mdx`.

Generated with `bun run changelog:weekly --from 2026-07-20 --to 2026-07-27 --write`, then rewritten to publish quality: entries grouped under Features, Fixes, and Docs, prose rewritten to describe user impact, and the `<!-- TODO: review -->` marker removed.

## Why

Keeps the public weekly-updates page current. The digest is the RSS-backed summary readers get between versioned releases.

## How

- Ran the generator over the July 20 to July 27 range.
- Rewrote the new `<Update>` block: 11 Features, 15 Fixes, 3 Docs bullets.
- Every commit and PR link the generator produced for these entries is retained. No link was invented; all references trace back to `updates/weekly/2026-07-27.md`.
- Headline items: professional color grading across core, Studio, and the CLI; a versioned distributed plan protocol with direct S3 and GCS publishing; the Studio keyframe ease editor; data-driven registry caption components.
- `renderStretch` (#2676) is deliberately omitted, since it was reverted in the same window by #2730 and is not present at HEAD.
- CI-only performance and internal refactor entries are omitted as not user-facing.

## Test plan

Docs-only change. No runtime code touched.

- [ ] Unit tests added/updated
- [x] Manual testing performed
- [x] Documentation updated (if applicable)

Verification performed:
- `git diff origin/main --stat` shows only `docs/weekly-updates.mdx`, 49 insertions and 0 deletions (purely additive, the prior week's entry is untouched).
- Confirmed the TODO marker is gone from the file.
- Confirmed every commit SHA and PR number in the new block appears in the generator's own draft, and that each link label matches its href.
- Confirmed the block contains no em-dashes and no stray JSX-unsafe characters outside inline code.
- `node scripts/check-tracked-artifacts.mjs` passes.
2026-07-27 16:41:39 -07:00
James Russo 3a0590925c perf(ci): run the two heaviest fixtures in distributed mode (#2825)
* perf(ci): run the two heaviest fixtures in distributed mode

* test(ci): pin distributed-mode fixtures to harness support
2026-07-26 22:42:12 -07:00
James Russo d8a8f8e044 perf(ci): order Dockerfile.test layers so producer changes do not rebuild core (#2822) 2026-07-26 22:11:31 -07:00
James 5cad2bc312 chore: release v0.7.76 2026-07-27 05:08:40 +00:00
James Russo 28a340aa6d Merge pull request #2823 from heygen-com/fix/plan-v2-sparse-inactive-videos
fix(producer): materialize sparse video directories
2026-07-26 21:59:48 -07:00
James ddb59d3567 fix(producer): materialize sparse video directories 2026-07-27 04:22:26 +00:00
James 45b458c007 chore: release v0.7.75 2026-07-27 03:38:16 +00:00
James Russo c72ba7ee01 Merge pull request #2821 from heygen-com/fix/distributed-beginframe-fallback
fix(producer): fallback distributed capture safely
2026-07-26 20:32:10 -07:00
James 96cafb47c6 fix(producer): fallback distributed capture safely 2026-07-27 03:08:40 +00:00
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) 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 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
2026-07-26 17:36:13 -04:00
James 527751c871 chore: release v0.7.73 2026-07-26 21:25:03 +00:00
James f0c2c7d233 fix(producer): align frame coverage with extraction rounding 2026-07-26 20:33:19 +00: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 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 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
James Russo 72ae39e3d0 chore: release v0.7.72 (#2800) 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
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
James Russo 8c50770684 fix(engine): preserve bounded ffprobe diagnostics (#2772)
* fix(engine): preserve bounded ffprobe diagnostics

* test(engine): harden ffprobe diagnostic redaction
2026-07-25 17:12:43 -04:00
James Russo 37b88688e7 fix(audio): preserve causes and use portable padding (#2769)
* fix(audio): preserve causes and use portable padding

* fix(audio): address failure taxonomy review
2026-07-25 17:12:31 -04:00
James d07d1874b6 chore: release v0.7.71 2026-07-24 19:03:16 +00:00
James Russo adb149b869 fix(lint): allow bounded GSAP infinite repeats (#2763) 2026-07-24 14:56:03 -04:00
James Russo 7778c093b6 fix(preview): serve external symlink assets (#2764)
## What

Allow Studio Preview to serve an asset reached through a project-local symlink whose target is in a shared directory outside the project, including browser-hostile video assets that need an authoring proxy.

## Why

Preview rejected these assets with a 404 while the renderer accepted the same path. The initial static-route fix still failed for HEVC, ProRes, AV1, and VP9 assets because the proxy transcoder rejected the external target.

## How

Use lexical project-root containment for the read-only static asset route and proxy source request. The transcoder canonicalizes the target for ffmpeg and includes that identity in its cache key, while keeping the proxy cache inside the project. Composition source paths retain canonical containment because preview can persist their data-hf-id values.

## Test plan

- [x] Unit tests added/updated
- [x] `bun run --cwd packages/studio-server test` (397 tests)
- [x] Studio Server typecheck, oxlint, and oxfmt
- [x] External-symlinked hostile-video proxy route regression
- [x] Static-route traversal regression
- [ ] Documentation updated (not applicable)
2026-07-24 13:35:10 -04:00
James f0034228f5 chore: release v0.7.69 2026-07-23 12:03:36 -07:00
James Russo 7a294f1956 fix(lint): address render preflight review feedback (#2739) 2026-07-22 22:59:12 -04:00
James Russo 948264d6b2 fix(producer): resolve residual font and probe failures (#2738) 2026-07-22 21:17:52 -04:00
James 71d84ff27f chore: release v0.7.68 2026-07-22 04:41:54 +00:00
James RussoandClaude Opus 4.7 1e2c7d673f fix(core): preserve nested-rule selectors in composition CSS scoping (#2721) (#2733)
Chrome 112+ / Firefox 117+ / Safari 16.5+ support native CSS Nesting.
A nested rule like '.title { … }' inside '[data-composition-id="intro"]
{ … }' resolves at match time to '<parent> .title' via the implicit
'&' prefix.

'scopeCssToComposition' walks every rule via 'root.walkRules' and re-
scopes selectors, but it did so for nested rules too — producing
'[…scope…] .title' inside '[…scope…] { … }', which nesting then
prepends AGAIN to '[…scope…] […scope…] .title'. Since the composition
root only appears once in the DOM, the doubly-scoped selector never
matches — the nested rule appears 'just ignored' as the reporter
described (#2721).

Reproduced on 0.7.66 with the reporter's exact composition. Fix: add
'isNestedInsideAnotherRule' predicate — mirrors the existing
'isInsideGlobalAtRule' — and skip nested rules in the walkRules
callback. Top-level rules still get scoped; their nested descendants
inherit scope naturally via CSS Nesting at match time.

Added two focused tests:
- 'preserves nested-rule selectors so CSS Nesting inheritance works
  (#2721)' — asserts nested '.title' and 'h2' selectors stay verbatim
  while top-level rules keep scoping.
- 'preserves deeply-nested CSS Nesting rules (#2721)' — same rule at
  depth 3.

All 37 existing scopeCssToComposition tests still pass.

Fixes #2721.

Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
2026-07-22 00:24:59 -04:00
James RussoandClaude Opus 4.7 a637f394ee fix(producer): credit looping short videos in coverage gate (#2665) (#2732)
#2606 taught the video-coverage gate that a non-looping short video holds
its final decoded frame across the tail, so the delivered source frames
are enough to cover the authored slot. But that fix gated the credit on
'!video.loop' — a looping short video was still measured as
unique-source-frames / slot-frames and aborted at ratio << threshold.

Reproduced on 0.7.64 with the reporter's exact composition (3s clip in a
10s slot, loop attribute): render aborts with 'captured 90 of expected
300 frames (coverage 30.0%)'. Same source without loop renders clean via
#2606's freeze credit. This is the mainline 'loop a short clip to fill a
longer scene' case, the reason loop exists.

Fix: extend #2606's source-credit to loops symmetrically — the delivered
set (all N source frames) covers every repeat within the slot, so
expectedFrames = min(slotFrames, sourceFrames) for both hold and loop.
Fail-loud preserved for a genuinely-broken loop (extractor truncated
below its own source): a 60/90 delivery still aborts at 66.7% < 95%
because the delivered set no longer covers the full source period the
loop reuses. Missing extractions still require the full slot.

Test updates:
- 'still requires the full authored slot for looping clips' locked in
  the buggy behavior; replaced with 'credits a looping short clip
  against the source portion' which asserts the correct 90/90/1.0.
- Added 'still fails when a looping clip's source extraction is
  truncated' as the new fail-loud floor.

Fixes #2665. Regression window: 0.7.60 (#2606's original ship)
through 0.7.67 (current).

Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
2026-07-22 00:19:51 -04:00
James RussoandClaude Opus 4.7 807078c7cd docs(skills): make captions non-optional in changelog-video (#2729)
* docs(skills): make captions non-optional in changelog-video

The Jul 13-20 build shipped without captions because the pipeline had two soft
failure modes:

- Empty vo-words.json from the TTS provider was silently accepted, so
  align-captions.mjs had nothing to align. captions.json was never produced.
- Step 5 tolerated the master-skeleton's LINES array staying empty. The build
  lint-checked and validated clean, but the caption rail rendered no text.

This adds three hard gates on top of the existing scaffold:

- Step 4 adds a whisper forced-alignment fallback so a missing TTS timestamp
  payload no longer breaks the caption pipeline. Whisper only supplies timings;
  captions still use the DISPLAY layer from script-tokens.json.
- Step 5 flags an empty LINES array as a shipped bug and shows the exact
  IIFE-input shape it expects.
- Step 6 adds gate 5: sample 3-4 frames across the VO window and confirm visible
  caption text on each. If any spoken window renders no caption, the build is
  red.

Anti-patterns table gets two rows covering the empty-LINES and
missing-word-timings failure modes. .claude and .agents mirrors stay
byte-identical.

Follow-up to #2669 (pre-build gate); paired with the v5 rebuild that
retrofitted captions onto the shipped Jul 13-20 video.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* docs(skills): bump changelog caption size to 32px for phone-screen legibility

25px reads too small at 1080² when the video is viewed on a phone without
zoom. Bumped to 32px (font-size 25→32, top 1002→990, height 40→52, alpha
.92→.94) so captions carry across small-screen playback. Change is CSS-only
on the master-skeleton; existing per-scene chrome and layouts are untouched.

Retrofitted the Jul 13-20 v6 build with the same values (identical CSS
block) so the shipped video and the future default match. .claude and
.agents mirrors stay byte-identical.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* docs(skills): sync caption position refs to top: 990 across SKILL.md + build-spec

Miga caught: the master-skeleton bump to top: 990 / 32px / height: 52 was
not reflected in the SKILL.md prose or build-spec.md. All three files now
name the same values so the doc, gate, and code stay consistent. Also
clarifies build-spec.md's caption-rail line to point at SKILL.md step 5 as
the source of the LINES-populated requirement.

.claude and .agents mirrors byte-identical.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* docs(skills): sync script-voice.md caption rail to top: 990 / 32px

Third and final stale reference to top: 1002 / 25px — script-voice.md was
still stating the pre-bump values. Now matches master-skeleton.html,
build-spec.md, and SKILL.md. Also bumps the 'keep critical small text out'
guidance from ~80px to ~100px to reflect the slightly taller caption rail.

Full-directory sweep confirms zero remaining occurrences of 1002 or 25px
across .claude/ and .agents/ skill mirrors.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
2026-07-21 20:38:46 -04:00
James Russo 2e97e5b1ef docs(changelog): weekly digest 2026-07-13–2026-07-20 (#2664)
* docs(changelog): weekly digest 2026-07-13–2026-07-20

* docs(changelog): embed the weekly video in the Jul 13-20 digest

Adds the Jul 13-20 changelog video (produced via the changelog-video
skill, hosted at static.heygen.ai) at the top of the Update block using
Mintlify's <Frame> component with a native <video controls>.

Video URL: https://static.heygen.ai/hyperframes/changelog-videos/weekly-changelog-jul13-20.mp4
Slack thread: C0ACCNHLG3U · 1784565857.520599
2026-07-21 20:36:27 -04:00
James 4b6bb8ffa9 chore: release v0.7.67 2026-07-21 23:51:05 +00:00
James Russo 465c9e7641 fix(producer): preserve runtime audio variables in distributed plans (#2725)
* fix(producer): preserve runtime audio variables in distributed plans

* fix(producer): prefer runtime duration for volume sampling
2026-07-21 19:49:39 -04:00
James RussoandMiao Yang 696cbdbbd0 chore(skills): package Codex plugin upload (#2668)
* chore(skills): package Codex plugin upload

* chore(skills): harden Codex plugin content

* fix(skills): satisfy plugin quality gates

* fix(skills): address plugin packaging review

* fix(plugin): simplify asset validation

* fix(skills): correct embedded-captions catalog count to 35 after nightcity removal

The nightcity theme removal left SKILL.md claiming 36 identities in
four places, including the frontmatter description the router reads.
The catalog now has 35 entries (10 classic + 25 themed).

---------

Co-authored-by: Miao Yang <miao.yang@heygen.com>
2026-07-22 00:41:40 +08:00
James 835fa899c7 chore: release v0.7.65 2026-07-21 04:45:59 +00:00
James Russo efab7a1b32 Merge pull request #2671 from heygen-com/fix/bound-static-dedup-cardinality
fix: bound invalid render durations
2026-07-21 00:37:12 -04:00
James 52da8d3cdb test: align distributed duration assertion 2026-07-21 03:51:33 +00:00
James 344d9c0a87 fix: bound invalid render durations 2026-07-21 03:05:53 +00:00
James Russo e4a30f627f Merge pull request #2669 from heygen-com/jerrai/changelog-video-skill-pre-build-gate
docs(skills): add pre-build gate to changelog-video SKILL.md
2026-07-20 21:13:59 -04:00
jrusso1020 7d312bd170 docs(skills): add pre-build gate to changelog-video SKILL.md
Adds an explicit Step 0 above the pipeline that spells out the concrete file
copies (fonts, bgm, ffmpeg-encoded bg-pattern, master-skeleton.html) before
any composition HTML is written. Extends the anti-patterns table with the
three failure modes James caught on the Jul 13-20 weekly run: starting from
a prior video's index.html, hand-crafting @font-face / WebGL shader / custom
BGM, and shipping without a CloudFront invalidation after the S3 replace.

Why: the previous SKILL.md said "follow references/build-spec.md exactly" in
step 5, but that lets an agent read the build-spec after already writing
composition HTML on the wrong scaffold. Ships of the Jul 13-20 video went
through three off-brand iterations before I finally started from
master-skeleton.html (Jake called v3 "trash" — the skill's assets, fonts,
and scaffold ARE the brand, not the SKILL.md prompt on its own).

The three added anti-patterns are the concrete traps: agents will keep
starting from prior-project templates unless the skill explicitly bans it.

Mirrors to .agents/skills/ (Codex CLI) and .claude/skills/ (Claude Code)
byte-identical, per the skill-mirror gate.
2026-07-21 01:05:53 +00:00
James ab8b50afd7 refactor(repo): resolve changed-code audit 2026-07-20 11:59:57 -07:00
James a03d40ef4c test(engine): isolate peer abort regression 2026-07-20 11:02:05 -07:00
James 3222f1f31d refactor(cli): decompose render phases 2026-07-20 10:34:06 -07:00
James a9338a4e0f fix(cli): await error telemetry before finalization 2026-07-20 09:45:54 -07:00
James 73d3b4e1f4 fix(cli): report command failures once 2026-07-20 09:04:03 -07:00
James 619406a23b fix(cli): complete process lifecycle migration 2026-07-20 09:04:03 -07:00
James e0bda7a171 fix(cli): keep post-render exit reset root-owned 2026-07-20 09:04:03 -07:00
James 00b88abeb7 test(cli): align timeout failure with result contract 2026-07-20 09:04:03 -07:00
James 3aa2404747 refactor(cli): centralize process lifecycle 2026-07-20 09:04:03 -07:00
James 942db16fcd fix(cloudrun): publish adapter contract 2026-07-18 20:17:01 -04:00
James 634cd719a2 fix(parsers): mark node-only subpaths 2026-07-18 18:50:26 -04:00
James 3454a80eb2 test(repo): execute packed subpaths 2026-07-18 18:27:44 -04:00
James 8d9d9c016e refactor(repo): centralize package subpaths 2026-07-18 15:58:23 -04:00
James 562544f68d refactor(core): own edit protocol contract 2026-07-18 13:24:57 -04:00
James f0956e5944 test(compiler): enforce preview render parity 2026-07-18 12:26:52 -04:00
James 38c2d06933 refactor(studio): gate SDK operation families 2026-07-18 11:34:22 -04:00
James 8dd7e3dfc5 fix(studio): keep atomic Acorn splits Recast-free 2026-07-18 09:36:00 -04:00
James 022e260ac3 fix(studio): read writer environment explicitly 2026-07-18 06:41:26 -04:00
James 710a8f1db2 fix(studio): select writer for atomic cuts 2026-07-18 06:41:26 -04:00
James 43788c6dda refactor(studio): gate Acorn writer migration 2026-07-18 06:41:26 -04:00
James a7d6f7f7dc fix(producer): retain streaming retry after OOM 2026-07-17 19:14:04 -04:00
James e9604270b2 test(producer): preserve parallel plan watchdog coverage 2026-07-17 19:14:04 -04:00
James 6a84e95c68 refactor(producer): make capture plans immutable 2026-07-17 19:14:04 -04:00
James e73304fb0e feat(cli): make cloud archives size-aware 2026-07-17 18:44:58 -04:00
James 1a66c881b8 fix(producer): preserve render request config contracts 2026-07-17 17:22:34 -04:00