Shot Lock (video plan authority)
The shot list gets frozen before a single frame renders
- patched_ledger_json
- video_revision
- shot_report
- done
- episode_id
On the video side, OTR_CastLock's job is done by OTR_ShotLock: it's the single ledger['video'] authority - the node that stamps the shot plan into the frozen ledger and declares it final. Every beat gets its engine, its prompt, its clip budget, and that plan is what OTRVideoRenderBatch executes. Like its audio cousins, it exists to make the render deterministic: one decision point, locked before the expensive work starts.
The clever part is what it's locked against. Two of the three required inputs are gates that force the video plan to respect the audio timeline:
script_json- the frozen ledger (fromOTR_LedgerFreezeCascade's script_json output).audio_done- the gate fromOTR_EpisodeAssembler's out3. Wiring it orders ShotLock after audio timing freezes, so the per-beat clip budget is bound against the real timeline, not a guess. This is the "audio is king" discipline made structural: the shot list can't be planned before the episode's actual duration exists.video_policy_json- the per-role engine selection fromOTR_VideoDirector.
There's an image_done input declared to mirror audio_done (the image-before-video contract), but it's non-blocking in v1 - the local image engine runs in-process and nothing emits it yet. So don't sit waiting for it; the image branch's image_done from OTR_ImageGenDispatcher is what you'd wire if you want the ordering, but v1 won't enforce it. consistency_gate_warn_only is a compatibility-only widget - authored non-empty M4 prompts are always preserved, empty replies use the deterministic template.
Outputs
patched_ledger_json (ledger with the video section stamped), video_revision (INT - bumps when the shot plan changes), shot_report, done, and - worth knowing - episode_id, which ShotLock holds as the in-graph authority because it owns the audio-overlaid ledger. Everything that needs to write files per-episode (the stills dispatcher, the composite) can key off it.
Install and gotchas
Pack-level install (ComfyUI Manager → ComfyUI-OldTimeRadio, restart; v2.0-alpha). No models - plan logic. The gotcha is wiring discipline: leave audio_done unwired and you lose the timeline-bound guarantee, which is how you end up with beats that don't fit their clips. Wire it, and the clip budget is honest. And remember this node only plans - if the rendered clips look wrong, the fix is upstream in the engine selection (VideoDirector) or the prompts, not here; ShotLock is the authority, not the author.
Inputs (4)
| Name | Type | Default | Description |
|---|---|---|---|
| script_json | STRING | {} | Frozen ledger JSON (OTR_LedgerFreezeCascade out1 script_json). ShotLock stamps a video section into it. |
| audio_done | STRING | Audio-done gate (OTR_EpisodeAssembler out3). Wiring it orders ShotLock AFTER audio timing freezes so the clip budget is bound against the real timeline. Opaque STRING. | |
| video_policy_json | STRING | {} | Per-role selection policy from OTR_VideoDirector. |
| gate_inopt | STRING | Optional ordering signal (opaque STRING). |
Outputs (5)
| Name | Type | Description |
|---|---|---|
| patched_ledger_json | STRING | — |
| video_revision | INT | — |
| shot_report | STRING | — |
| done | STRING | — |
| episode_id | STRING | — |