LFC Ledger Freeze Cascade (v2.0)
The freeze that turns a script into a contract
- script_text
- script_json
- news_used
- estimated_minutes
- freeze_verdict
- episode_seed
- v2_ledger_json
In OldTimeRadio the whole episode is a JSON "ledger" that flows node to node, and at one point it stops being a draft and becomes a contract. OTR_LedgerFreezeCascade is that point. It finalizes the writer's accepted script - no more quality-driven reauthoring - and stamps the version every downstream consumer will read. Think of it as the moment a screenplay gets locked before production: the cast, voices, and shots all get scheduled against this exact document, and rerunning from it is deterministic.
The node reads the production ledger directly (via peek_ledger()); the script_text socket is the wire that keeps the graph visually in line. It then re-serializes script_json from the post-freeze ledger so everyone downstream sees the final state.
The phases that do the actual work
Two phases are on by default, and they're the ones you'll care about:
- Phase 7 - audio readiness (
enable_phase_7_audio_readiness, default ON). Expands things TTS would stumble over:Dr.→Doctor,&→and,42→forty-two. Deterministic and cheap, and it's why the voices don't read "St. Louis" as "st dot louis". This is one of those hidden quality wins you only notice when it's off. - Phase 8 - video readiness (
enable_phase_8_video_readiness, default ON). An audit that checks cast portraits and voiced-line visual coverage. It mutates nothing - it stampsmeta.video_readinessso the video stage knows whether every speaking role has a picture. On, and the video branch can trust the ledger.
The technical_model input is validated via require_model - an unwired socket raises a loud MissingModelInputError rather than silently running with a guess.
There's a small legacy trap in the schema: render_selection, render_max_n, protagonist_only, and manual_line_ids are all marked deprecated compatibility inputs, ignored. They're kept so old saved workflows don't break, but setting them does nothing. Don't go hunting for a way to render "dramatic peaks only" - it's gone.
Outputs
Seven outputs: script_text, script_json (the frozen, re-serialized ledger - feed this to CastLock), news_used, estimated_minutes, freeze_verdict, episode_seed (INT), and v2_ledger_json. It's marked as an output node, so a stripped story-only workflow (validator → writer → freeze) can terminate here with the frozen ledger on disk and no media stage at all.
Install and gotchas
Pack-level install (ComfyUI Manager → ComfyUI-OldTimeRadio, restart; v2.0-alpha). No models - pure ledger logic. The main thing to remember is the freeze is a one-way door: downstream, the ledger is canonical, and changes belong upstream in the writer, not here. If you're hacking on the ledger JSON by hand, you're fighting the pipeline's determinism guarantees - the pack would rather you change the writer's inputs and re-run.
Inputs (7)
| Name | Type | Default | Description |
|---|---|---|---|
| script_text | STRING | Passthrough from OTR_LedgerScriptWriter. The cascade reads the production ledger directly via peek_ledger(); this socket exists so the graph wires the writer and cascade in line. | |
| script_jsonopt | STRING | Forwarded from the writer's script_json slot. The cascade re-serializes this from the post-freeze ledger so downstream consumers see the final state. | |
| news_usedopt | STRING | Passthrough of the writer's news_used slot. Not touched by the cascade. | |
| estimated_minutesopt | INT | Passthrough of the writer's estimated_minutes INT slot. Not touched by the cascade. | |
| technical_modelopt | STRING | Technical model ID from the writer. Required for compatibility on a normal current-ledger run; freeze does not acquire or generate with this model. Validated via _otr_model_inputs.require_model -- an unwired or blank socket raises MissingModelInputError loud. | |
| enable_phase_7_audio_readinessopt | BOOLEAN | true | LFC Phase 7 -- audio readiness. Expands abbreviations (Dr. -> Doctor), symbols (& -> and), and numbers (42 -> forty-two) so TTS produces pronounceable output. Default ON (deterministic + cheap). |
| enable_phase_8_video_readinessopt | BOOLEAN | true | LFC Phase 8 -- video readiness audit. Checks cast portraits + voiced-line visual coverage. Mutates nothing; stamps meta.video_readiness. Default ON. |
Outputs (7)
| Name | Type | Description |
|---|---|---|
| script_text | STRING | — |
| script_json | STRING | — |
| news_used | STRING | — |
| estimated_minutes | INT | — |
| freeze_verdict | STRING | — |
| episode_seed | INT | — |
| v2_ledger_json | STRING | — |