Skip to content

0024 — reel plan: VO-driven timing + pre-build sanity

Status: IMPLEMENTED Date: 2026-06-29 Source: REPORT-keryx-in-anger-afmpeg-reel.md (request G, pinch point #5). Related: 0023 (take workflow), the reelcmd.ReelTimingFromVO helper (keryx !76).

1. Goal

There is no way to see the VO-driven total or per-card timing before a build. The build log shows only an inaccurate fallback duration (the report saw 69s logged for a ~90s reel), so sizing the music bed meant summing ffprobe durations across vo/*.mp3 in python. Expose the real timing as a command.

2. What already exists

reelcmd.ReelTimingFromVO (extracted in keryx !76) computes per-card durations + the assembled reel.Timeline (Starts, VODelaysMS, XFadeOffsets, Total) by probing the promoted vo/NN.mp3 clips — the same maths reel build and music gen --takes use. This spec surfaces it; the computation already exists and is unit-tested.

3. Design

A read-only keryx reel plan --workspace <slug> command (no generation, no render):

  1. Resolves the render backend (for Probe) exactly as build does, probes the promoted VO, and runs ReelTimingFromVO.
  2. Reports, per card: index, on-screen dur, start, vo_delay, and the source of the duration (VO clip vs. storyboard dur fallback).
  3. Reports the VO-driven total and the implied music-bed length (what music gen --takes would request) so the bed can be sized confidently.
  4. Pre-build sanity (the bit that turns it from a duration printout into a pre-flight): flags lines with no promoted VO (→ silent fallback or "takes generated, none selected"), overlay cards missing media, a missing cover, and whether a music bed is present.
  5. Text (human table) + --output json (machine-readable for the studio / CI).

It degrades gracefully: with no VO promoted it reports the silent-render durations (from storyboard dur) and says so, rather than erroring.

3.5 The build log (verified 2026-07-02)

The root annoyance was reel build logging an inaccurate duration (69s for a ~90s reel). On investigation this is already fixed on current main: reel build logs Video.DurationSec, which the renderer sets to totalDuration(timeline) = sum(durs) − (n−1)·xfade, and the timeline's durs come from the shared ReelTimingFromVO when VO is promoted. So the logged number is the VO-driven total — the 69s was the stale installed binary (the same "stale binary" pattern as the rest of the field report), which logged a storyboard-dur fallback. The deliverable here is therefore a regression guard, not a code change: pin that build times the reel via the VO-driven computation (not the dur fallback), so the accurate log can't silently regress.

4. Requirements

  • R-GEN-40 (MUST) reel plan --workspace <slug> prints the VO-driven total and per-card timing (dur/start/vo_delay) without generating or rendering anything.
  • R-GEN-41 (MUST) The total matches what reel build would assemble (shared ReelTimingFromVO); the reported bed length matches what music gen --takes requests.
  • R-GEN-41b (MUST) reel build logs the accurate VO-driven total (via the shared ReelTimingFromVO), not the fallback duration. Already satisfied on current main (verified 2026-07-02); held by a regression guard that pins build's timing basis to the VO-driven durations rather than the storyboard dur.
  • R-GEN-42 (SHOULD) reel plan flags pre-build gaps: lines missing VO, unpromoted VO takes, overlay cards missing media, missing cover, absent music bed.
  • R-GEN-43 (SHOULD) --output json emits the timing + gaps for the studio/CI.

5. Testing (TDD)

  • Given promoted VO (fake renderer probe), reel plan reports the same total as ReelTimingFromVO / build; per-card start/vo_delay match reel.BuildTimeline.
  • No-VO workspace → silent-fallback durations reported + flagged (no error).
  • reel build's logged total equals ReelTimingFromVO (not the fallback) for a VO-promoted workspace (R-GEN-41b).
  • Gap flags: a missing-media overlay card and an unpromoted-takes line are surfaced.
  • JSON shape stable (golden).

6. Resolved decisions

Reviewed with Matt 2026-06-29:

  • D1 (was Q1) — name: reel plan (pre-flight framing, pairs with reel make).
  • D2 (was Q2) — breadth: timing + asset-gap flags (§3.4) — the gap pre-flight is what makes it worth running before build, and the data is already at hand (R-GEN-42).
  • D3 (was Q3) — probe backend: mirror buildplan resolves providers.render and probes through it (a default-ffmpeg setup needs the binary; an afmpeg setup probes in-memory, zero-config since !75). Documented, not configurable separately.