# Director Notes Playbook — verbal feedback → pipeline fix

> **What this is:** the procedure for turning JT's verbal/visual feedback on an output
> ("this doesn't make physical sense", "the pod should be on a platform", "panel 3 to 4
> doesn't connect") into the RIGHT pipeline change at the RIGHT layer. Every chain below
> was executed and verified live on 2026-06-12 (the CONT_004 cryopod-platform session).
> SSOT rule: each kind of truth has exactly ONE home — patch the home, never the artifact.

## The layer map (who owns what truth)

| Truth | SSOT home | Never patch instead |
|---|---|---|
| What HAPPENS + why (events, causality, dialogue) | `scripting/episodes/ep_NNN.md` (locked script) | board prompts, sidecars, take prompts |
| WHERE things are (spatial anchors, set geography) | `_pipeline/state/visual/global_bible.json` → `locations.<id>.sublocations` (descriptions) + derived refs under `assets/loc/<id>/base/sublocations/` | location hero refs, board images |
| Per-shot STAGING (who faces what, gaze, stance) | persisted scene `beat_metadata.batch_shots[].raw.blocking_metadata` (`_pipeline/state/orchestration/scenes/ep_NNN_BATCH_NNN.json`) | the board PNG, the video prompt |
| Per-shot TEMPORAL ACTION (what moves during the shot) | `raw.prompt_data.prompt_skeleton.motion_line` (REC-139; authored at ingest for new plans, hand-patched for legacy) | action_line (frozen-frame language, stills only) |
| Shot LIST for a batch (beat insertion/removal) | persisted scene `beat_metadata.batch_shots[]` (mirror `EP001_SH12A` shape: `raw.source_text` + routing/prompt/blocking) | board panel count alone |
| Board look/judgment | regenerated FROM the above via `--storyboard`; judged by the story gate; approved/rejected at the CLI | hand-editing board prompts |

## Step 0 — classify the note (the gate usually already did)

If the output went through the story gate, read its verdict sidecar
(`prep/ep_NNN/storyboards/<board>.verdict.json`): `routing.class` names the owning layer —
`script_problem` → script; `board_problem` → staging/board; `prompt_problem` → prompt encode.
If JT's note disagrees with the gate (e.g. gate said gaze, JT says spatial), **JT's framing
wins** — record it via `--reject-board --reason "<JT's words>"` or `--approve-board --reason
"<adjudication>"` so the label flywheel learns the disagreement.

## Chains by note type (verified procedures)

### A. "X should be <somewhere else>" / set-geography canon change
(2026-06-12 example: "the cryopod must be on a platform in the center, never hanging")
1. **Backup + patch the script span** in `ep_NNN.md` (backup to `_history/script_edits/`).
   COHERENCE CHECK before saving: grep the episode for downstream references (the platform
   patch *fixed* a hole — "her feet leave the grating" had no grating established).
2. **Patch the bible sublocation description** (or add one) under
   `locations.<loc_id>.sublocations.<slug>` — encode the canon ("the pod sits ON the
   platform, never hanging in open air").
3. **Regenerate the sublocation ref**: `gen_sublocations.py --project P --location <loc_id>`.
   ⚠ Known bug: if the ref already exists, the tool RESTAMPS the old image's hash instead of
   regenerating — archive the old png+sidecar to `base/sublocations/_archive/` and drop its
   registry entry from `base/location.json` first, then rerun. Verify the new image by eye.
4. **Patch per-shot blocking** where the note implies staging: the persisted scene's
   `blocking_metadata.characters[].{gaze_target, head_facing, stance}` + a `staging_note`
   carrying JT's words verbatim. Backup the scene JSON first.
5. **Regenerate the board** (`--storyboard EP00N_CONT_NNN`, ~$0.41), read the gate verdict,
   eyeball it, send to JT, then `--approve-board --reason "<adjudication>"`.

### B. "There's no reason for him to do that" / causality-logic note
(The CONT_007 cable-catch class — script_problem route.)
1. Patch the script: articulate the CAUSE in story order (purpose + spatial reachability —
   "capability is not cause"). Same backup discipline.
2. The pre-gen text gate re-judges at next board build; the fix is verified when
   `causal_setup_present` passes at the flagged beat.

### C. "Those two shots don't connect" / continuity jump
(The panel 3→4 class.)
1. Preferred: **insert an approach/bridge beat** — script paragraph (chain A step 1) + a new
   segment in `batch_shots` between the two shots (copy a neighbor's dict; set shot_id
   `EP00N_SHnnA`, `raw.source_text`, duration ~3s, `motion_line`, blocking). Boards take 5–6
   panels.
2. Too big for one beat → REC-137 f2v in-between at video time (not yet built).
3. Small gaps → the per-shot `transition` key (rendered "<Transition> to @ImageN" — value
   must read correctly before "to": "Whip pan", "Match cut").

### D. "It's not doing what the shot says" / under-animation, frozen poses
Motion authoring: check `prompt_skeleton.motion_line` per shot (REC-139). New ingests fail
loud without it; legacy plans need hand-patching (chain A step 4 pattern). Micro-action for
inserts: state + its evolution ("the crack line begins to enlarge with a splintering sound").

### E. Style/identity/technical ("wrong face", "too smooth", artifacts)
Existing machinery — identity refs/pools, cinema modes, reroll with strategy. Not this
playbook's scope; see PIPELINE_SSOT.

## After any fix
- Board staleness is now a true content fingerprint (raw segments, pre-derivation) — a
  segment change correctly invalidates proposed boards; regenerate, don't fight it.
- Record JT's verbal note VERBATIM somewhere durable in the same change: the approve/reject
  `--reason`, a `staging_note`, or the script itself. The flywheel and future sessions read
  these.
- Costs: board $0.41 · sublocation ref ~$0.10 · 15s r2v arm ~$4.55–5.50. Renders need JT's
  explicit spend approval, always.

## Known traps (all hit live)
- `gen_sublocations` restamp-instead-of-regenerate (chain A step 3).
- Editing persisted scene JSON: ALWAYS via `load_scene`/`save_scene` with a `.bak` copy; a
  fingerprint drift demotes succeeded takes to rebuild (expected, but know why).
- The board's SCENE CONTEXT comes LIVE from `ep_NNN.md` at build time — script patches reach
  boards automatically; segments (panels) come from the persisted scene and do NOT.
- Custom/ad-hoc shot_ids break grouping identity; pass `pass_counter`/`tag` on bare
  `execute_pass` calls.
- Flora 500/DNS poll blips can fail the local take while the run completes server-side —
  before re-paying, poll the run id from the log via the adapter and recover the output.
