Skip to content

0025 — Locked/reviewed assets: approved, reproducible reels

Status: DRAFT Date: 2026-06-29 Source: REPORT-keryx-in-anger-afmpeg-reel.md (request J). Related: 0022 (voice configurability), 0023 (take workflow).

1. Goal

The durable fix for pronunciation on multilingual_v2 turned out to be human-reviewed, committed vo/NN.mp3 clips rather than any runtime cleverness — take variance can re-mangle a respelling on any regeneration. keryx should make "this line's audio is approved — never re-roll it" an explicit, recorded state, so a build is reproducible from the committed clips.

2. What already exists (this is thinner than it looks)

Verified 2026-06-29:

  • reel make's buildPlan (plan.go) already skips lines that have a selection (takes.HasVOSelected) — so a promoted vo/NN.mp3 is not re-rolled on a re-run; reel make is resume-idempotent.
  • reel prune clears only takes/ + .cache/, never the selected vo/NN.mp3.

So a selected clip is already fairly safe. What's missing is an explicit "approved" state distinct from "a selection happens to exist", plus guards on the paths that do overwrite a selection (voice pick, a future voice gen --best/--force), and a reproducibility signal the human can trust.

3. Design

3.1 An explicit approved state

A selected asset can be locked (= reviewed/approved/frozen), recorded so tooling treats it as immutable. Locking applies uniformly across asset kinds — a VO line, a card image, the music bed, the cover (resolved §6 D2) — keyed by kind + index.

Storage (resolved §6 D1): a structured block in workspace.yaml, e.g.

locked:
  vo:    [1, 3, 5]   # storyboard line indices
  cards: [2]         # card indices
  music: true        # the single bed
  cover: true

Central, auditable, survives prune, and keeps review-state out of the creative storyboard.json. The workspace.Meta gains a Locked field.

3.2 Commands + guards

  • keryx reel lock <kind> <index> / keryx reel unlock <kind> <index> toggles the state (kindvo|card|music|cover; index omitted for the singleton music/cover). A voice pick --lock / --lock on the pick paths is a convenience that picks-then-locks.
  • A locked asset refuses destructive ops without --force: voice pick / cards pick / re-roll / a future --best warn + skip (so a bulk re-roll can't silently clobber an approved asset). reel make continues to skip selected items (it already does) and never offers to regenerate a locked one.
  • reel prune already spares selections; locking additionally records the provenance/ intent durably.

3.3 Reproducibility signal

  • reel plan (0024) and reel build report how many selected assets are locked vs merely selected — a reel whose every asset is locked is "reproducible from committed inputs". Surfaced in --output json for CI.

3.4 Scope

Locking applies to all selected asset kinds (VO, cards, music, cover) under one uniform model (resolved §6 D2) — VO is the highest-variance and the report's concern, but the same approve-and-freeze intent applies to a hand-picked card or bed.

4. Requirements

  • R-GEN-44 (MUST) A selected asset (VO line, card, music, cover) can be locked (approved) and unlocked, recorded durably in workspace.yaml (Meta.Locked).
  • R-GEN-45 (MUST) A locked asset is not overwritten by voice pick / cards pick / take re-roll / any regenerate-the-selection path without an explicit --force; reel make continues to skip it.
  • R-GEN-46 (SHOULD) reel plan/reel build report locked-vs-selected counts so a fully-locked reel is known reproducible from committed inputs.
  • R-GEN-47 (SHOULD) reel prune never disturbs a locked selection or its recorded state (it already spares selections).

5. Testing (TDD)

  • voice lock/unlock persists + round-trips the state (MemMapFs).
  • A locked line: voice pick / re-roll refuses without --force, succeeds with it; an unlocked line is unaffected.
  • reel make skips a locked line (and still skips a merely-selected one).
  • reel plan JSON reports the locked count.

6. Resolved decisions

Reviewed with Matt 2026-06-29:

  • D1 (was Q1) — storage: a locked block in workspace.yaml (Meta.Locked) — central, auditable, survives prune, decoupled from the creative storyboard.
  • D2 (was Q2) — scope: all selected asset kinds (VO, cards, music, cover) under one uniform lock model, not VO-only.
  • D3 (was Q3) — explicit lock is the point: "a selection exists" (already resume-skipped by reel make) does not capture "a human approved this"; the explicit, auditable approved state is the feature.

7. Open question (minor)

  • Q4 — granularity. Per-asset lock only, or also a whole-reel reel lock --all "freeze" that locks every current selection at once? Recommendation: per-asset is the primitive; add --all as sugar if wanted.