# Schedule against the recording

`src/recording-timing.ts` turns the separate-video timing contract into a checked
frame schedule. It does not infer a transcript, manufacture a pause, approve a
storyboard, or play the talking head. Its inputs must come from the actual
recording and a rehearsal of the intended playback setup.

## Gather evidence first

1. Preserve the supplied recording. Derive a timed transcript from its audio,
   including pauses. Watch it to mark the genuine ending wave/pause onset.
2. For each spoken beat, identify the exact recording time when its completed
   visual proof should be available. Record that as `recordingProofSeconds`.
3. Pick a recipe whose source-backed mechanic fits that beat. Specify the local
   output frame where its proof is complete, total duration, and a protected
   reading hold. Do not assume `settle` always means completed text: in
   `TitleCut`, for example, `change` completes the title and `settle` cuts away.
4. Place the recognizable content transition that cues the OBS scene switch.
   Measure reaction/startup delay in rehearsal; do not assume it is zero.
5. Choose the presentation end inside the actual talking-head tail, leaving
   enough real footage for the presenter to mute and stop video manually.

## Use the checked schedule

Import `alignToRecording` and the `RecordingClock` / `RecordingBeat` types from
`./recording-timing`. Supply a clock with these fields:

| Field | Evidence / units |
| --- | --- |
| `fps` | Chosen output frames per second, established at storyboard review |
| `cueSeconds` | Visible presentation cue time |
| `measuredReactionSeconds` | Rehearsed manual reaction plus OBS startup delay |
| `recordingDurationSeconds` | Actual supplied recording duration |
| `actualTailStartSeconds` | Watched onset of the genuine ending wave/pause |
| `lastRequiredSpeechSeconds` | End of the last required spoken word, from the actual timed transcript |
| `requiredRemainingTailSeconds` | Positive remaining buffer chosen against footage and rehearsal |
| `presentationEndFrame` | Exclusive end of the presentation file, not its last frame index |

Each beat supplies `id`, `recordingProofSeconds`, `proofLocalFrame`,
`durationInFrames`, and `minimumReadingFrames`. All frame fields are integers.
Use the returned `from` and `durationInFrames` on a Remotion `Sequence`; its
child's `useCurrentFrame()` then reads the recipe's local time. Keep existing
recipe phase durations. The scheduler works backward from proof, not forward
from a guessed speech rate.

The function checks both sides of the final interval, not just the files'
durations. With `S = cueSeconds + measuredReactionSeconds`, recording time `h`
maps to presentation time `S + h`. The permitted end window is
`S + actualTailStartSeconds <= presentation end <= S + recordingDurationSeconds - requiredRemainingTailSeconds`.
End boundaries round inward to whole output frames. Proof anchors round to
the nearest frame (at most half an output frame of quantization).

The earliest end also cannot precede `S + lastRequiredSpeechSeconds`. If the
presenter starts waving while still speaking, the wave does not authorize
ending the presentation before the required words finish.

Overlapping shots, missing reading time, a beat that cannot fit after the cue,
or an inadequate ending pause are errors. Shorten surplus holds, simplify the
visual, choose a direct crop instead of travel, or raise a recording conflict
in storyboard review. Do not automatically accelerate the whole edit.
Unfilled gaps need an explicit context/proof hold or chapter card; a schedule
with gaps is not itself a finished composition. A successful numerical check
does not prove that the chosen phrase matches the visible content.

Run the executable synthetic example and rejection checks:

```bash
node scripts/test-recording-timing.mjs
```

The numbers in that test are deliberately invented test fixtures, not timings
of any supplied footage. The test shows how the input contract works without
publishing a private recording or suggesting that its synchronization is done.

## Approval and paired playback

Consolidate the transcript-derived beat map, selected source examples, demo
list and current product verification, capture prerequisites, cue, measured
offset, ending buffer, and delivery settings into the single storyboard
review. Get approval before rendering the final presentation. Material
departures require review; routine approved scenes do not need new approvals.

Keep two assets: supplied talking head in OBS and the separate presentation in
Google Slides. Do not composite them, synthesize a voice, duplicate narration,
or add music. Verify the exported pair in the real setup. A stable Remotion
render cannot establish the real OBS startup delay or Slides playback behavior.
