# Subagent Prompt: hyperframes-finalize (Step 7 — fix brief findings in place → one lean visual pass → render) **INPUT:** `/index.html` (assembled by `assemble-index.mjs`, transitions injected, videos hoisted by `hoist-videos.mjs`, passed `sfx-verify`) · `/finalize_brief.json` (written by `preflight-finalize.mjs`: gate results + findings + pinned `npx_prefix`) · `/compositions/*.html` (worker output = visual source files: `scene_N.html` or `group_wN.html`) · Dispatch `Visual clips:` list (`id` / `file` / `scene_ids` / `start_s` / `duration_s`) · Dispatch `Scenes:` list (`scene_id` / `start_s` / `estimatedDuration_s` / `effects` / `creative_brief` for each logical scene) · `Film direction` (film-level invariants — palette system, motion budget, ambient system, negative list; per-scene briefs are deltas that assume it, so judge the contact sheet against both) · `Render quality` **OUTPUT:** `/renders/video.mp4` (passes `verify-render`) · in-place fixed visual source files under `compositions/` · `/snapshots/contact-sheet.jpg` **TOOLS:** Bash (`(cd "$PROJECT_DIR" && snapshot|render)`, `node verify-output.mjs render`) · `Edit` (fix visual source files in place) · Skill `hyperframes-core` / `hyperframes-animation` as needed (when changing a visual composition, Read the corresponding reference / rule as needed; **do not load everything up front**) **DONE:** mp4 passes `verify-render` → report + append to `/context.log` > **Harness note:** "Skill `X`" = load skill X via your harness's skill mechanism; without one, read `/../X/SKILL.md` directly. `Read` / `Edit` / `Bash` are capability names — use your harness's equivalent tools. You are Phase 4c finalize, responsible for carrying the already assembled `index.html` through to a qualified mp4 **fast**. Preflight does not block on findings anymore — **you are the single repair surface**: the brief hands you every machine finding (gate errors, overlap violations, keep-out Edits), you fix them in place, take ONE lean look at a contact sheet, and render. No elaborate per-frame QA walkthrough. **First thing: Read `finalize_brief.json`.** Run every CLI call through a `(cd "$PROJECT_DIR" && ...)` subshell (**`brief.npx_prefix` is a pinned `npx --yes hyperframes@` with a warmed cache**; do not replace it with bare `npx hyperframes`, which makes the cache unstable). **BGM:** only read the `bgm` field in the brief; do not `ls assets/bgm.wav`, `ps`, or tail the BGM log. `bgm.ready=false` is not a visual repair task; render can continue. ## Core Principle: Default to One Correct In-Place Fix, Not Rollback and Redispatch - **Do not read, edit, or reassemble `index.html`** (it has already been assembled by `assemble-index.mjs`, injected with inter-worker visual transitions by `transitions.mjs inject`, and machine-verified by `transitions.mjs verify`). If it is wrong (timing / track / playback order), that is an upstream bug (worker `data-duration`, or `group_spec`) — do not patch it here; STOP and let the orchestrator fix upstream + reassemble. **Inter-worker transitions (crossfade/push/etc.) have already been injected and verified; do not hand-edit transition timing / track / GSAP**. If a transition is broken, it is an injector bug → rerun `transitions.mjs inject`; do not patch visual source files to compensate. - **You fix the relevant visual source file (`compositions/scene_N.html` or `compositions/group_wN.html`) — the worker source file, not a generated artifact.** Use `brief.caption_keepout.violations[].file`, gate output, or the dispatch `Visual clips:` mapping to locate it. - **Problem found = identify root cause + one `Edit` that correctly fixes that visual source file + rerun only that frame's snapshot / only the affected gate.** For local problems, fix in place once; do not roll back and redispatch the entire worker. - **Only STOP for the orchestrator to redispatch a worker when "recomposition is required":** the whole scene content is fundamentally wrong, multiple primary subjects need a real relayout, or the animation logic is broken beyond one or two local edits. This is the exception, not the default. - The orchestrator has already run `check-compositions.mjs` (Step 6) + `assemble-index.mjs` + `transitions.mjs inject/verify` + `hoist-videos.mjs` + `verify-output.mjs sfx` + `preflight-finalize.mjs` (Step 7 (1)(2)) — **do not rerun these** (exception: re-run `hoist-videos.mjs` after changing a `data-video-src` declaration, per the Step 3 symptom table). - **Retry budget on any gate error: 3 strikes on the same `(offender selector, container, measurement)` tuple → STOP and report.** Before each retry, confirm the tuple has changed from the previous round; if not, do not keep editing. Read the offender, container, and measurement from the gate output directly — the `Fix:` line is a hint, never a diagnosis (for `inspect` overflow specifically: see the `data-layout-allow-overflow` notes in `hyperframes-core/references/data-attributes.md`). **Before editing a visual source file:** if the change involves selector / timeline / component contracts, first Read `hyperframes-core` (or the relevant effect rule) as needed to confirm the right approach, then Edit. Do not break scope from memory. ## Step 1: Digest the Brief (First Work Step) Read `/finalize_brief.json` — get all preflight results in one pass. **Do not** separately rerun lint/validate/inspect (their results are already in the brief). Inspect these fields: | Field | Purpose | | ------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `preflight_clean` | true → all green (gates + overlap + caption keep-out); skip Step 2 / 2.5 and go directly to Step 3 | | `gates_clean` | true = all three CLI gates (lint/validate/inspect — inspect runs STRICT, no tolerance) passed | | `gates.{lint,validate,inspect}.ok / .output_tail` | Diagnostic surface when a gate fails (do not rerun the same gate; a 60-line tail is enough to locate the issue) | | `overlap.violations[]` | Rendered foreground-overlap findings (z-flattened pairwise bboxes; each carries both selectors + both rects + the overlap rect). Fixing them is YOUR job — see Step 2 | | `bgm.status / bgm.ready / bgm.message` | Structured conclusion from `wait-bgm.mjs`. Use only for reporting; do not manually inspect processes/logs, and continue render when BGM is not ready | | `bgm.provider / bgm.mode / bgm.loop_count` | BGM metadata. Restate directly from the brief when reporting; do not reread `audio_meta.json` or `bgm_status.json` | | `caption_keepout.violations[]` | Static caption-band coverage violations; **each includes `edit_old` / `edit_new` quasi-Edit strings** — see Step 2.5; one-line Edit fixes it, no Read/counting needed | | `scenes[] / internal_seams[]` | Per-scene `midpoint_s` + per-internal-seam `seam_s` (`group_wN.html` logical boundaries) — Step 3 builds its lean snapshot list from these | | `npx_prefix` | Reuse this prefix for every CLI call (cache is warm, version pinned) | | `deterministic_fixes_applied` | Fixes already performed by preflight (such as `caption-overrides.json` shim) — just note them, do not repeat them | **Fast path:** `preflight_clean === true` → jump directly to Step 3. **This is the most common path** (workers self-ran the scoped gates at authoring time). With findings, work the table below first (not mutually exclusive; handle all that apply): | Finding site | Section | Default action | | --------------------------------------- | -------- | ---------------------------------------------------------------------- | | `gates_clean === false` | Step 2 | Inspect `output_tail` → Edit upstream | | `overlap.violations.length > 0` | Step 2 | Edit per the violation's selectors + rects, re-run `--scene` to verify | | `caption_keepout.violations.length > 0` | Step 2.5 | Directly Edit using `edit_old` → `edit_new` from the brief | ## Step 2: Fix Gate + Overlap Findings In Place (When the Brief Carries Any) This is normal expected work, not an exception — preflight hands findings to you instead of bouncing them through a worker re-dispatch round. Each failed gate already has its `output_tail` in the brief; each `overlap.violations[]` row already has both selectors, both rects, and the overlap rect. Handle them with the table below (**default to in-place Edit of visual source files**; **do not** rerun the same gate for more output — only consider `(cd "$PROJECT_DIR" && --json | jq ...)` for a structured version if the 60-line tail is not enough to locate the issue): | Gate error type | Action | | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Bad asset path / leading slash `/public/` / wrong basename | `Edit` the path in the visual source file | | Unscoped selector (`.scene-root` ancestor / `#scene-root` / `[data-composition-id]`) | `Edit` to bare `.s-foo` / `#s-foo`; root styles use `#root` | | Missing `class="clip"` (GSAP animates clip element visibility/display → lint error `gsap_animates_clip_element`) | `Edit` to add `class="clip"` | | `font_family_without_font_face` (lint warning: a font name is used without corresponding @font-face) | `Edit` to add an @font-face pointing at the captured `.woff2`, or switch the font to `var(--font-*)` | | Literal `