{
  "director_note_routes": [
    {
      "evidence": "DIRECTOR_NOTES_PLAYBOOK.md:31-47 chain A; :11-18",
      "note_type": "'X should be elsewhere' / set-geography canon (e.g. pod on a platform)",
      "routes_to": "bible_sublocation + script + blocking"
    },
    {
      "evidence": "PLAYBOOK:49-55 chain B",
      "note_type": "'no reason for him to do that' / causality",
      "routes_to": "script (ep_NNN.md — articulate the CAUSE)"
    },
    {
      "evidence": "PLAYBOOK:56-64 chain C",
      "note_type": "'those two shots don't connect' / continuity jump",
      "routes_to": "script (bridge beat) + batch_shots transition key"
    },
    {
      "evidence": "PLAYBOOK:66-69 chain D; :16",
      "note_type": "'not doing what the shot says' / under-animation",
      "routes_to": "motion_line (raw.prompt_data.prompt_skeleton.motion_line, REC-139)"
    },
    {
      "evidence": "PLAYBOOK:15; chain A step 4 :44-47",
      "note_type": "per-shot staging (gaze, stance, facing)",
      "routes_to": "blocking (scene beat_metadata.batch_shots[].raw.blocking_metadata)"
    },
    {
      "evidence": "PLAYBOOK:70-73 chain E",
      "note_type": "'wrong face'/'too smooth'/artifacts / identity-technical",
      "routes_to": "existing machinery (identity refs/pools, cinema modes, reroll-with-strategy) — NOT a script/bible/blocking patch"
    },
    {
      "evidence": "story_gate.py:34-40; PLAYBOOK:20-28",
      "note_type": "gate-classified board verdict (story_gate routing.class)",
      "routes_to": "script_problem->script | board_problem->blocking/board | prompt_problem->prompt encode"
    }
  ],
  "edges": [
    {
      "from": "batch_checkpoint_gate",
      "is_deprecated": false,
      "label": "batch 12 complete",
      "to": "finish"
    },
    {
      "from": "batch_checkpoint_gate",
      "is_deprecated": false,
      "label": "PASS unlock / FAIL regen",
      "to": "generate_script"
    },
    {
      "from": "blocking_pass",
      "is_deprecated": false,
      "label": "blocking_metadata (staging) -> board",
      "to": "keyframes"
    },
    {
      "from": "board_decision",
      "is_deprecated": false,
      "label": "reject / stale-sha -> regenerate",
      "to": "keyframes"
    },
    {
      "from": "board_decision",
      "is_deprecated": false,
      "label": "approved + fresh sha",
      "to": "photoreal_finish"
    },
    {
      "from": "board_story_gate",
      "is_deprecated": false,
      "label": "board/prompt_problem -> blocking/prompt layer",
      "to": "provenance_index"
    },
    {
      "from": "board_story_gate",
      "is_deprecated": false,
      "label": "script_problem route",
      "to": "script_lock"
    },
    {
      "from": "camera_test",
      "is_deprecated": false,
      "label": "all camera_tested/*.json (batch)",
      "to": "global_bible"
    },
    {
      "from": "camera_test",
      "is_deprecated": false,
      "label": "camera_tested/ep_NNN.json (1:1 shots)",
      "to": "plan_pass"
    },
    {
      "from": "casting",
      "is_deprecated": false,
      "label": "character hero (blueprint, 1-char scenes)",
      "to": "keyframes"
    },
    {
      "from": "cinema_mode",
      "is_deprecated": false,
      "label": "cinema tokens",
      "to": "keyframes"
    },
    {
      "from": "cinema_mode",
      "is_deprecated": true,
      "label": "style/camera tokens (at prompt build)",
      "to": "previz"
    },
    {
      "from": "cinema_mode",
      "is_deprecated": false,
      "label": "camera/style tokens",
      "to": "video_gen"
    },
    {
      "from": "dailies_review",
      "is_deprecated": false,
      "label": "approved",
      "to": "final_review_export"
    },
    {
      "from": "dailies_review",
      "is_deprecated": false,
      "label": "reject -> regenerate (new take)",
      "to": "video_gen"
    },
    {
      "from": "develop",
      "is_deprecated": false,
      "label": "5 dev docs + 34/34",
      "to": "validate"
    },
    {
      "from": "dispatch_audit",
      "is_deprecated": false,
      "label": "payload-shape guardrail (build-time)",
      "to": "video_gen"
    },
    {
      "from": "dispatch_chassis_orchestrator",
      "is_deprecated": false,
      "label": "status/budget/terminal_status",
      "to": "dispatch_status_ledger"
    },
    {
      "from": "dispatch_chassis_orchestrator",
      "is_deprecated": false,
      "label": "auto-PR carries handoff metadata",
      "to": "session_workspace"
    },
    {
      "from": "dispatch_entry_point",
      "is_deprecated": false,
      "label": "get_runner(modality)",
      "to": "modality_registry"
    },
    {
      "from": "dispatch_entry_point",
      "is_deprecated": false,
      "label": "receipt provenance/receipts.jsonl",
      "to": "provenance_index"
    },
    {
      "from": "enrichment",
      "is_deprecated": false,
      "label": "bible",
      "to": "blocking_pass"
    },
    {
      "from": "enrichment",
      "is_deprecated": false,
      "label": "enriched bible (episode summary)",
      "to": "plan_pass"
    },
    {
      "from": "episode_metrics_gate",
      "is_deprecated": false,
      "label": "5 eps valid -> checkpoint",
      "to": "batch_checkpoint_gate"
    },
    {
      "from": "episode_metrics_gate",
      "is_deprecated": false,
      "label": "is_valid:false -> fix (max 3)",
      "to": "generate_script"
    },
    {
      "from": "eval_panel",
      "is_deprecated": false,
      "label": "SUBSTRATE: score -> select_primary('score')",
      "to": "select_primary_decision"
    },
    {
      "from": "eval_panel",
      "is_deprecated": false,
      "label": "SUBSTRATE: ScoreCard -> from_score_card",
      "to": "strategy_score_bridge"
    },
    {
      "from": "final_review_export",
      "is_deprecated": false,
      "label": "final reject -> re-render pass",
      "to": "video_gen"
    },
    {
      "from": "finish",
      "is_deprecated": false,
      "label": "preflight OK",
      "to": "finish_script_doctor"
    },
    {
      "from": "finish_apply_revisions",
      "is_deprecated": false,
      "label": "modified episodes",
      "to": "finish_revalidate"
    },
    {
      "from": "finish_compile",
      "is_deprecated": false,
      "label": "Fountain locked -> visual pipeline (Camera Test)",
      "to": "script_lock"
    },
    {
      "from": "finish_extract_annotations",
      "is_deprecated": false,
      "label": "annotations.json",
      "to": "finish_apply_revisions"
    },
    {
      "from": "finish_revalidate",
      "is_deprecated": false,
      "label": "re-validated",
      "to": "finish_verify"
    },
    {
      "from": "finish_script_doctor",
      "is_deprecated": false,
      "label": "brief.json",
      "to": "finish_extract_annotations"
    },
    {
      "from": "finish_verify",
      "is_deprecated": false,
      "label": "issues remain -> re-revise (loop)",
      "to": "finish_apply_revisions"
    },
    {
      "from": "finish_verify",
      "is_deprecated": false,
      "label": "informational pass-through",
      "to": "finish_compile"
    },
    {
      "from": "generate_script",
      "is_deprecated": false,
      "label": "ep_XXX.md written",
      "to": "episode_metrics_gate"
    },
    {
      "from": "global_bible",
      "is_deprecated": false,
      "label": "visual_description + brief_visual/wardrobe + look_map",
      "to": "casting"
    },
    {
      "from": "global_bible",
      "is_deprecated": false,
      "label": "[OPUS_ENRICHMENT] placeholders",
      "to": "enrichment"
    },
    {
      "from": "global_bible",
      "is_deprecated": false,
      "label": "bible + sublocation refs",
      "to": "keyframes"
    },
    {
      "from": "global_bible",
      "is_deprecated": false,
      "label": "locations.<id>.description/atmosphere",
      "to": "location_refs"
    },
    {
      "from": "global_bible",
      "is_deprecated": false,
      "label": "phases + wardrobe_philosophy",
      "to": "wardrobe_intent_gate"
    },
    {
      "from": "keyframes",
      "is_deprecated": false,
      "label": "proposed board",
      "to": "board_decision"
    },
    {
      "from": "keyframes",
      "is_deprecated": false,
      "label": "auto-reroll (new board version)",
      "to": "keyframes"
    },
    {
      "from": "keyframes",
      "is_deprecated": false,
      "label": "board gen dispatches storyboard modality",
      "to": "modality_storyboard"
    },
    {
      "from": "location_refs",
      "is_deprecated": false,
      "label": "location hero / moodboard",
      "to": "keyframes"
    },
    {
      "from": "modality_registry",
      "is_deprecated": false,
      "label": "audio_t2a",
      "to": "modality_audio_t2a"
    },
    {
      "from": "modality_registry",
      "is_deprecated": false,
      "label": "image_t2i",
      "to": "modality_image_t2i"
    },
    {
      "from": "modality_registry",
      "is_deprecated": false,
      "label": "lipsync_post",
      "to": "modality_lipsync_post"
    },
    {
      "from": "modality_registry",
      "is_deprecated": false,
      "label": "r2v_multi",
      "to": "modality_r2v_multi"
    },
    {
      "from": "modality_registry",
      "is_deprecated": false,
      "label": "storyboard",
      "to": "modality_storyboard"
    },
    {
      "from": "modality_registry",
      "is_deprecated": false,
      "label": "video_i2v",
      "to": "modality_video_i2v"
    },
    {
      "from": "modality_storyboard",
      "is_deprecated": false,
      "label": "board -> story gate verdict",
      "to": "board_story_gate"
    },
    {
      "from": "photoreal_finish",
      "is_deprecated": false,
      "label": "approved board ref",
      "to": "video_gen"
    },
    {
      "from": "plan_pass",
      "is_deprecated": false,
      "label": "ep_NNN_plan.json (required)",
      "to": "blocking_pass"
    },
    {
      "from": "plan_pass",
      "is_deprecated": false,
      "label": "shot skeleton -> board gen (live; previz bypassed)",
      "to": "keyframes"
    },
    {
      "from": "plan_pass",
      "is_deprecated": true,
      "label": "shot plan + spatial/axis plan",
      "to": "previz"
    },
    {
      "from": "plan_pass",
      "is_deprecated": false,
      "label": "EpisodePlan structural_sha fingerprint",
      "to": "provenance_index"
    },
    {
      "from": "pre_treatment_gate",
      "is_deprecated": false,
      "label": "fail -> promote first",
      "to": "promote"
    },
    {
      "from": "pre_treatment_gate",
      "is_deprecated": false,
      "label": "exit 0",
      "to": "treatment"
    },
    {
      "from": "previz",
      "is_deprecated": true,
      "label": "previz assets",
      "to": "previz_review"
    },
    {
      "from": "previz_review",
      "is_deprecated": true,
      "label": "previs_rejected -> reroll",
      "to": "previz"
    },
    {
      "from": "promote",
      "is_deprecated": false,
      "label": "bible/ + state created",
      "to": "pre_treatment_gate"
    },
    {
      "from": "provenance_index",
      "is_deprecated": false,
      "label": "structural re-derive invalidates locked downstream",
      "to": "take_store"
    },
    {
      "from": "script_lock",
      "is_deprecated": false,
      "label": "scene source text",
      "to": "blocking_pass"
    },
    {
      "from": "script_lock",
      "is_deprecated": false,
      "label": "locked ep_NNN.md -> shot boundaries",
      "to": "camera_test"
    },
    {
      "from": "script_lock",
      "is_deprecated": false,
      "label": "characters.md DNA",
      "to": "global_bible"
    },
    {
      "from": "script_lock",
      "is_deprecated": false,
      "label": "treatment.md + series_bible.md",
      "to": "wardrobe_intent_gate"
    },
    {
      "from": "session_workspace",
      "is_deprecated": false,
      "label": "claim ledger + lease -> reaper reconcile",
      "to": "dispatch_reaper"
    },
    {
      "from": "strategy_engine_live",
      "is_deprecated": false,
      "label": "LIVE: StrategyDiff overlay -> next Take",
      "to": "take_store"
    },
    {
      "from": "take_store",
      "is_deprecated": false,
      "label": "Take.execute -> Workflow.run -> dispatch() per step",
      "to": "dispatch_entry_point"
    },
    {
      "from": "take_store",
      "is_deprecated": false,
      "label": "Beat.select_primary over takes",
      "to": "select_primary_decision"
    },
    {
      "from": "take_store",
      "is_deprecated": false,
      "label": "reroll = Beat.new_take (append-only)",
      "to": "take_store"
    },
    {
      "from": "treatment",
      "is_deprecated": false,
      "label": "treatment.md MASTER",
      "to": "generate_script"
    },
    {
      "from": "validate",
      "is_deprecated": false,
      "label": "NOT READY -> fill gaps",
      "to": "develop"
    },
    {
      "from": "validate",
      "is_deprecated": false,
      "label": "READY (hard gates + score>=3.5)",
      "to": "promote"
    },
    {
      "from": "video_gen",
      "is_deprecated": false,
      "label": "rendered takes",
      "to": "dailies_review"
    },
    {
      "from": "video_gen",
      "is_deprecated": false,
      "label": "each step -> dispatch()",
      "to": "dispatch_entry_point"
    },
    {
      "from": "video_gen",
      "is_deprecated": false,
      "label": "realized via Take/Beat (reroll = new take)",
      "to": "take_store"
    },
    {
      "from": "video_gen",
      "is_deprecated": false,
      "label": "reroll = NEW take / strategy retry",
      "to": "video_gen"
    },
    {
      "from": "wardrobe_intent_gate",
      "is_deprecated": false,
      "label": "approved wardrobe phase descriptions (-> Screen Test)",
      "to": "casting"
    },
    {
      "from": "workflow_step",
      "is_deprecated": false,
      "label": "WorkflowStep.modality -> dispatch()",
      "to": "dispatch_entry_point"
    }
  ],
  "meta": {
    "deprecated_nodes": [
      "previz",
      "previz_review"
    ],
    "edge_count": 82,
    "human_review_nodes": [
      "board_decision",
      "dailies_review",
      "develop",
      "final_review_export",
      "previz_review",
      "wardrobe_intent_gate"
    ],
    "node_count": 54,
    "substrate_only_nodes": [
      "eval_panel",
      "modality_eval",
      "strategy_score_bridge"
    ],
    "swimlanes": [
      "narrative",
      "prepro",
      "production",
      "review_export",
      "infra"
    ],
    "topology_loop_count": 17
  },
  "nodes": [
    {
      "gate": null,
      "id": "develop",
      "inputs": [
        {
          "artifact": "concept / logline",
          "from": "external"
        },
        {
          "artifact": "STATUS.md + existing dev docs",
          "from": "external"
        }
      ],
      "is_deprecated": false,
      "is_human_review": true,
      "is_substrate": false,
      "label": "Develop (34-point checklist)",
      "loops": [
        {
          "kind": "director_note_route",
          "note": "interactive, section-by-section; --audit reports gaps without advancing (develop/SKILL.md:78-87)",
          "to": "develop"
        }
      ],
      "node_type": "human_review",
      "produces": [
        "thematic_spine.md",
        "characters.md",
        "relationship_map.md",
        "structure_outline.md",
        "plant_payoff_plan.md",
        "STATUS.md (34 items)"
      ],
      "provenance": [
        {
          "field": "tool",
          "file": "recoil/.claude/skills/develop/SKILL.md",
          "line": 1,
          "ref": "recoil/.claude/skills/develop/SKILL.md:1",
          "resolved": true
        },
        {
          "field": "evidence",
          "file": "recoil/.claude/skills/develop/SKILL.md",
          "line": 36,
          "ref": "recoil/.claude/skills/develop/SKILL.md:36",
          "resolved": true
        }
      ],
      "shape": "diamond_person",
      "source_index": 0,
      "status": "live",
      "swimlane": "narrative"
    },
    {
      "gate": {
        "pass_condition": "Tier-1 HARD GATES all pass (34/34, 5 dev docs, Law-2 beats Ep15/30/45/60, Primary Ache+2 threats, >=8 relationship markers, >=3 plant/payoff, >=1 Object/Phrase/Image thread, >=1 echo, protagonist Lie/Truth+3 need layers, antagonist counter-thesis, theme question) AND Tier-2 avg >= 3.5; Tier-3 warnings block only --strict",
        "validator": "skill /validate (recoil/.claude/skills/validate/SKILL.md:37-95)"
      },
      "id": "validate",
      "inputs": [
        {
          "artifact": "5 dev docs + STATUS.md",
          "from": "develop"
        }
      ],
      "is_deprecated": false,
      "is_human_review": false,
      "is_substrate": false,
      "label": "Validate (pre-promotion gate)",
      "loops": [
        {
          "kind": "director_note_route",
          "note": "NOT READY -> back to /develop (validate/SKILL.md:88-102)",
          "to": "develop"
        }
      ],
      "node_type": "gate",
      "produces": [
        "validation report (READY / READY WITH WARNINGS / NOT READY)"
      ],
      "provenance": [
        {
          "field": "tool",
          "file": "recoil/.claude/skills/validate/SKILL.md",
          "line": 1,
          "ref": "recoil/.claude/skills/validate/SKILL.md:1",
          "resolved": true
        },
        {
          "field": "evidence",
          "file": "recoil/.claude/skills/validate/SKILL.md",
          "line": 37,
          "ref": "recoil/.claude/skills/validate/SKILL.md:37",
          "resolved": true
        }
      ],
      "shape": "diamond",
      "source_index": 1,
      "status": "live",
      "swimlane": "narrative"
    },
    {
      "gate": {
        "pass_condition": "34/34 STATUS, 5 dev docs, validate_behavioral_dna.py pass, validate_episode_arc.py pass, /validate pass. Blocked if project exists unless --force",
        "validator": "promote prerequisites (recoil/.claude/skills/promote/SKILL.md:73-85)"
      },
      "id": "promote",
      "inputs": [
        {
          "artifact": "5 dev docs",
          "from": "develop"
        },
        {
          "artifact": "validation PASS",
          "from": "validate"
        }
      ],
      "is_deprecated": false,
      "is_human_review": false,
      "is_substrate": false,
      "label": "Promote (create scripting folder + episode_arc)",
      "loops": [],
      "node_type": "generation",
      "produces": [
        "bible/series_bible.md",
        "bible/characters.md",
        "bible/episode_arc.md (60 eps)",
        "state/current_state.json",
        "ORCHESTRATION.md"
      ],
      "provenance": [
        {
          "field": "tool",
          "file": "recoil/.claude/skills/promote/SKILL.md",
          "line": 1,
          "ref": "recoil/.claude/skills/promote/SKILL.md:1",
          "resolved": true
        },
        {
          "field": "evidence",
          "file": "recoil/.claude/skills/promote/SKILL.md",
          "line": 36,
          "ref": "recoil/.claude/skills/promote/SKILL.md:36",
          "resolved": true
        }
      ],
      "shape": "rect",
      "source_index": 2,
      "status": "live",
      "swimlane": "narrative"
    },
    {
      "gate": {
        "pass_condition": "episode_arc.md has eps 1..60, characters.md passes behavioral DNA, series_bible.md non-empty (exit 0)",
        "validator": "validate_pre_treatment.py (recoil/.claude/hooks/validate_pre_treatment.py:35-60)"
      },
      "id": "pre_treatment_gate",
      "inputs": [
        {
          "artifact": "bible/* + state/current_state.json",
          "from": "promote"
        }
      ],
      "is_deprecated": false,
      "is_human_review": false,
      "is_substrate": false,
      "label": "Pre-treatment hard gate",
      "loops": [
        {
          "kind": "director_note_route",
          "note": "fail -> run /promote (validate_pre_treatment.py:39-44)",
          "to": "promote"
        }
      ],
      "node_type": "gate",
      "produces": [
        "exit 0 proceed / 1 missing prereq / 2 path error"
      ],
      "provenance": [
        {
          "field": "tool",
          "file": "recoil/.claude/hooks/validate_pre_treatment.py",
          "line": 1,
          "ref": "recoil/.claude/hooks/validate_pre_treatment.py:1",
          "resolved": true
        },
        {
          "field": "evidence",
          "file": "recoil/.claude/hooks/validate_pre_treatment.py",
          "line": 9,
          "ref": "recoil/.claude/hooks/validate_pre_treatment.py:9",
          "resolved": true
        },
        {
          "field": "evidence",
          "file": "treatment/SKILL.md",
          "line": 16,
          "ref": "treatment/SKILL.md:16",
          "resolved": false
        }
      ],
      "shape": "diamond",
      "source_index": 3,
      "status": "live",
      "swimlane": "narrative"
    },
    {
      "gate": {
        "pass_condition": "passes validate_treatment.py; hook ratio 70-85% SILENT, cliffhanger 70-85% MID-ACTION (CONSTANTS.md:70-71)",
        "validator": "validate_treatment.py (recoil/tools/validate_treatment.py)"
      },
      "id": "treatment",
      "inputs": [
        {
          "artifact": "bible/episode_arc.md",
          "from": "promote"
        },
        {
          "artifact": "bible/characters.md",
          "from": "promote"
        },
        {
          "artifact": "bible/series_bible.md",
          "from": "promote"
        },
        {
          "artifact": "pre-treatment gate PASS",
          "from": "pre_treatment_gate"
        }
      ],
      "is_deprecated": false,
      "is_human_review": false,
      "is_substrate": false,
      "label": "Treatment (episode_arc -> treatment.md MASTER)",
      "loops": [
        {
          "kind": "director_note_route",
          "note": "--close-read/--plus/--flag-weak iterate (treatment/SKILL.md:42-49)",
          "to": "treatment"
        }
      ],
      "node_type": "generation",
      "produces": [
        "treatment.md (MASTER: prose/ep, THE MOMENT, cliffhanger image, THREAD INDEX)"
      ],
      "provenance": [
        {
          "field": "tool",
          "file": "recoil/.claude/skills/treatment/SKILL.md",
          "line": 1,
          "ref": "recoil/.claude/skills/treatment/SKILL.md:1",
          "resolved": true
        },
        {
          "field": "evidence",
          "file": "recoil/.claude/skills/treatment/SKILL.md",
          "line": 12,
          "ref": "recoil/.claude/skills/treatment/SKILL.md:12",
          "resolved": true
        }
      ],
      "shape": "rect",
      "source_index": 4,
      "status": "live",
      "swimlane": "narrative"
    },
    {
      "gate": null,
      "id": "generate_script",
      "inputs": [
        {
          "artifact": "treatment.md section (prose, THE MOMENT, cliffhanger)",
          "from": "treatment"
        },
        {
          "artifact": "bible/characters.md (voice/stage)",
          "from": "promote"
        },
        {
          "artifact": "format_v12 + CONSTANTS (constraints)",
          "from": "external"
        },
        {
          "artifact": "last 2 episodes (continuity)",
          "from": "episode_metrics_gate"
        },
        {
          "artifact": "current_state.json (next_batch)",
          "from": "promote"
        }
      ],
      "is_deprecated": false,
      "is_human_review": false,
      "is_substrate": false,
      "label": "Generate Script (per-batch episode generation)",
      "loops": [
        {
          "kind": "reroll",
          "note": "is_valid:false -> --prompt fix, max 3 (generate-script/SKILL.md:131-187)",
          "to": "generate_script"
        },
        {
          "kind": "director_note_route",
          "note": "cinematization + subtext (~70%) passes after word-count validates",
          "to": "generate_script"
        }
      ],
      "node_type": "generation",
      "produces": [
        "scripting/episodes/ep_XXX.md (Kill Box; 450-500 words; <=40% dialogue; <=8 exchanges)",
        "state/batch_N_summary.json (orchestrated)"
      ],
      "provenance": [
        {
          "field": "evidence",
          "file": "generate-script/SKILL.md",
          "line": 91,
          "ref": "generate-script/SKILL.md:91",
          "resolved": false
        },
        {
          "field": "evidence",
          "file": "generate-script-orchestrated/SKILL.md",
          "line": 151,
          "ref": "generate-script-orchestrated/SKILL.md:151",
          "resolved": false
        },
        {
          "field": "evidence",
          "file": "recoil/CLAUDE.md",
          "line": 49,
          "ref": "recoil/CLAUDE.md:49",
          "resolved": true
        }
      ],
      "shape": "rect",
      "source_index": 5,
      "status": "live",
      "swimlane": "narrative"
    },
    {
      "gate": {
        "pass_condition": "word_count 450-500 AND exchanges <=8 AND dialogue <=40% AND kill_box_status==OK (5 sections present, ordered HOOK->SETUP->ESCALATION->TURN->CLIFFHANGER, non-empty)",
        "validator": "episode_metrics.py is_valid (recoil/tools/episode_metrics.py:119-123,356-399)"
      },
      "id": "episode_metrics_gate",
      "inputs": [
        {
          "artifact": "ep_XXX.md (just written)",
          "from": "generate_script"
        }
      ],
      "is_deprecated": false,
      "is_human_review": false,
      "is_substrate": false,
      "label": "Episode Metrics (per-episode validator)",
      "loops": [
        {
          "kind": "reroll",
          "note": "is_valid:false -> --prompt fix loop max 3 (recoil/CLAUDE.md:77-89)",
          "to": "generate_script"
        }
      ],
      "node_type": "gate",
      "produces": [
        "JSON metrics + is_valid; exit 0/1/2; --prompt fix instructions"
      ],
      "provenance": [
        {
          "field": "tool",
          "file": "recoil/tools/episode_metrics.py",
          "line": 617,
          "ref": "recoil/tools/episode_metrics.py:617",
          "resolved": true
        },
        {
          "field": "evidence",
          "file": "recoil/tools/episode_metrics.py",
          "line": 99,
          "ref": "recoil/tools/episode_metrics.py:99",
          "resolved": true
        },
        {
          "field": "evidence",
          "file": "CONSTANTS.md",
          "line": 13,
          "ref": "CONSTANTS.md:13",
          "resolved": false
        },
        {
          "field": "evidence",
          "file": "recoil/CLAUDE.md",
          "line": 77,
          "ref": "recoil/CLAUDE.md:77",
          "resolved": true
        }
      ],
      "shape": "diamond",
      "source_index": 6,
      "status": "live",
      "swimlane": "narrative"
    },
    {
      "gate": {
        "pass_condition": "HARD: validate_batch.py exit0 (word/dialogue/exchanges/pattern) AND quality_gate.py exit0 (variety/beats/continuity); @batch12 ALSO transition_gate.py != hard-fail (59 transitions). SOFT warn-only: dramatic_qc_gate.py, baseline_comparison.py @batches 3/6/9/12",
        "validator": "save_checkpoint.py -> validate_batch.py + quality_gate.py (HARD); dramatic_qc_gate.py + baseline_comparison.py (SOFT); transition_gate.py @batch12 (HARD)"
      },
      "id": "batch_checkpoint_gate",
      "inputs": [
        {
          "artifact": "5 episodes of batch N",
          "from": "generate_script"
        },
        {
          "artifact": "per-episode metrics PASS",
          "from": "episode_metrics_gate"
        }
      ],
      "is_deprecated": false,
      "is_human_review": false,
      "is_substrate": false,
      "label": "Batch Checkpoint Gate (unlock next batch)",
      "loops": [
        {
          "kind": "reroll",
          "note": "fail -> checkpoint NOT saved, next batch BLOCKED, regen (save_checkpoint.py:368-383)",
          "to": "generate_script"
        },
        {
          "kind": "director_note_route",
          "note": "soft QC/voice flags recommend /rewrite, don't block",
          "to": "generate_script"
        }
      ],
      "node_type": "gate",
      "produces": [
        "state/checkpoints/batch_NN_checkpoint.json + next_batch unlocked"
      ],
      "provenance": [
        {
          "field": "tool",
          "file": "recoil/.claude/hooks/save_checkpoint.py",
          "line": 333,
          "ref": "recoil/.claude/hooks/save_checkpoint.py:333",
          "resolved": true
        },
        {
          "field": "evidence",
          "file": "recoil/.claude/hooks/save_checkpoint.py",
          "line": 1,
          "ref": "recoil/.claude/hooks/save_checkpoint.py:1",
          "resolved": true
        },
        {
          "field": "evidence",
          "file": "CONSTANTS.md",
          "line": 24,
          "ref": "CONSTANTS.md:24",
          "resolved": false
        }
      ],
      "shape": "diamond",
      "source_index": 7,
      "status": "live",
      "swimlane": "narrative"
    },
    {
      "gate": {
        "pass_condition": "episodes + treatment.md + characters.md exist, GEMINI_API_KEY set",
        "validator": "Step 1 Preflight (finish/SKILL.md:44-62)"
      },
      "id": "finish",
      "inputs": [
        {
          "artifact": "60 episodes ep_*.md",
          "from": "generate_script"
        },
        {
          "artifact": "treatment.md, characters.md, GEMINI_API_KEY",
          "from": "external"
        }
      ],
      "is_deprecated": false,
      "is_human_review": false,
      "is_substrate": false,
      "label": "Finish (post-gen pipeline orchestrator)",
      "loops": [],
      "node_type": "decision",
      "produces": [
        "orchestrated doctor->annotations->revise->validate->verify->compile"
      ],
      "provenance": [
        {
          "field": "tool",
          "file": "recoil/.claude/skills/finish/SKILL.md",
          "line": 1,
          "ref": "recoil/.claude/skills/finish/SKILL.md:1",
          "resolved": true
        },
        {
          "field": "evidence",
          "file": "recoil/.claude/skills/finish/SKILL.md",
          "line": 40,
          "ref": "recoil/.claude/skills/finish/SKILL.md:40",
          "resolved": true
        }
      ],
      "shape": "hex",
      "source_index": 8,
      "status": "live",
      "swimlane": "narrative"
    },
    {
      "gate": null,
      "id": "finish_script_doctor",
      "inputs": [
        {
          "artifact": "full corpus + characters.md + treatment.md",
          "from": "generate_script"
        }
      ],
      "is_deprecated": false,
      "is_human_review": false,
      "is_substrate": false,
      "label": "Script Doctor (Gemini multi-pass diagnostic)",
      "loops": [],
      "node_type": "generation",
      "produces": [
        "_pipeline/state/script_doctor_brief.json (structural T/I, close-read C, series F; P1/P2/P3)"
      ],
      "provenance": [
        {
          "field": "evidence",
          "file": "finish/SKILL.md",
          "line": 64,
          "ref": "finish/SKILL.md:64",
          "resolved": false
        },
        {
          "field": "evidence",
          "file": "script-doctor/SKILL.md",
          "line": 66,
          "ref": "script-doctor/SKILL.md:66",
          "resolved": false
        }
      ],
      "shape": "rect",
      "source_index": 9,
      "status": "live",
      "swimlane": "narrative"
    },
    {
      "gate": null,
      "id": "finish_extract_annotations",
      "inputs": [
        {
          "artifact": "script_doctor_brief.json",
          "from": "finish_script_doctor"
        }
      ],
      "is_deprecated": false,
      "is_human_review": false,
      "is_substrate": false,
      "label": "Extract Annotations",
      "loops": [],
      "node_type": "generation",
      "produces": [
        "_pipeline/state/script_doctor_annotations.json (REWRITE/DELETE/FLAG)"
      ],
      "provenance": [
        {
          "field": "tool",
          "file": "finish/SKILL.md",
          "line": 84,
          "ref": "finish/SKILL.md:84",
          "resolved": false
        },
        {
          "field": "evidence",
          "file": "finish/SKILL.md",
          "line": 84,
          "ref": "finish/SKILL.md:84",
          "resolved": false
        },
        {
          "field": "evidence",
          "file": "script-doctor/SKILL.md",
          "line": 189,
          "ref": "script-doctor/SKILL.md:189",
          "resolved": false
        }
      ],
      "shape": "rect",
      "source_index": 10,
      "status": "live",
      "swimlane": "narrative"
    },
    {
      "gate": null,
      "id": "finish_apply_revisions",
      "inputs": [
        {
          "artifact": "script_doctor_annotations.json",
          "from": "finish_extract_annotations"
        },
        {
          "artifact": "ep_XXX.md",
          "from": "generate_script"
        }
      ],
      "is_deprecated": false,
      "is_human_review": false,
      "is_substrate": false,
      "label": "Apply Revisions",
      "loops": [
        {
          "kind": "director_note_route",
          "note": "FLAG NOT auto-applied -> /rewrite or --deep-fix (finish/SKILL.md:96-108)",
          "to": "finish_apply_revisions"
        }
      ],
      "node_type": "generation",
      "produces": [
        "modified ep_XXX.md (REWRITE+DELETE auto; FLAG logged for manual)"
      ],
      "provenance": [
        {
          "field": "tool",
          "file": "finish/SKILL.md",
          "line": 94,
          "ref": "finish/SKILL.md:94",
          "resolved": false
        },
        {
          "field": "evidence",
          "file": "finish/SKILL.md",
          "line": 94,
          "ref": "finish/SKILL.md:94",
          "resolved": false
        }
      ],
      "shape": "rect",
      "source_index": 11,
      "status": "live",
      "swimlane": "narrative"
    },
    {
      "gate": {
        "pass_condition": "is_valid:true per modified ep; OVER->trim, UNDER->add detail, max 3 attempts then manual",
        "validator": "episode_metrics.py (recoil/tools/episode_metrics.py:119-123)"
      },
      "id": "finish_revalidate",
      "inputs": [
        {
          "artifact": "episodes modified by revisions",
          "from": "finish_apply_revisions"
        }
      ],
      "is_deprecated": false,
      "is_human_review": false,
      "is_substrate": false,
      "label": "Re-validate Modified Episodes",
      "loops": [
        {
          "kind": "reroll",
          "note": "out of range -> 3 attempts (finish/SKILL.md:118-128)",
          "to": "finish_revalidate"
        }
      ],
      "node_type": "gate",
      "produces": [
        "per-episode is_valid; word-count auto-adjust"
      ],
      "provenance": [
        {
          "field": "tool",
          "file": "finish/SKILL.md",
          "line": 110,
          "ref": "finish/SKILL.md:110",
          "resolved": false
        },
        {
          "field": "evidence",
          "file": "finish/SKILL.md",
          "line": 110,
          "ref": "finish/SKILL.md:110",
          "resolved": false
        }
      ],
      "shape": "diamond",
      "source_index": 12,
      "status": "live",
      "swimlane": "narrative"
    },
    {
      "gate": {
        "pass_condition": "INFORMATIONAL ONLY — does NOT block compile (finish/SKILL.md:137)",
        "validator": "script_doctor.py --verify (finish/SKILL.md:130-138)"
      },
      "id": "finish_verify",
      "inputs": [
        {
          "artifact": "revised + re-validated episodes",
          "from": "finish_revalidate"
        }
      ],
      "is_deprecated": false,
      "is_human_review": false,
      "is_substrate": false,
      "label": "Verify (post-revision, informational)",
      "loops": [
        {
          "kind": "director_note_route",
          "note": "issues remain -> re-extract -> /revise -> verify (script-doctor/SKILL.md:202-207)",
          "to": "finish_apply_revisions"
        }
      ],
      "node_type": "gate",
      "produces": [
        "verification result + remaining issues count"
      ],
      "provenance": [
        {
          "field": "tool",
          "file": "finish/SKILL.md",
          "line": 130,
          "ref": "finish/SKILL.md:130",
          "resolved": false
        },
        {
          "field": "evidence",
          "file": "finish/SKILL.md",
          "line": 130,
          "ref": "finish/SKILL.md:130",
          "resolved": false
        },
        {
          "field": "evidence",
          "file": "script-doctor/SKILL.md",
          "line": 202,
          "ref": "script-doctor/SKILL.md:202",
          "resolved": false
        }
      ],
      "shape": "diamond",
      "source_index": 13,
      "status": "live",
      "swimlane": "narrative"
    },
    {
      "gate": null,
      "id": "finish_compile",
      "inputs": [
        {
          "artifact": "final ep_XXX.md corpus",
          "from": "finish_verify"
        }
      ],
      "is_deprecated": false,
      "is_human_review": false,
      "is_substrate": false,
      "label": "Compile (episodes -> Fountain)",
      "loops": [],
      "node_type": "generation",
      "produces": [
        "[TITLE]_COMPLETE.fountain",
        "[TITLE]_WITH_METADATA.fountain"
      ],
      "provenance": [
        {
          "field": "evidence",
          "file": "finish/SKILL.md",
          "line": 140,
          "ref": "finish/SKILL.md:140",
          "resolved": false
        },
        {
          "field": "evidence",
          "file": "compile/SKILL.md",
          "line": 60,
          "ref": "compile/SKILL.md:60",
          "resolved": false
        }
      ],
      "shape": "rect",
      "source_index": 14,
      "status": "live",
      "swimlane": "narrative"
    },
    {
      "gate": {
        "pass_condition": "is_valid:true per episode (V12) before promotion to visual",
        "validator": "tools/episode_metrics.py (recoil/CLAUDE.md EPISODE WRITING RULE)"
      },
      "id": "script_lock",
      "inputs": [
        {
          "artifact": "validated episode scripts (episode_metrics passed)",
          "from": "finish_compile"
        }
      ],
      "is_deprecated": false,
      "is_human_review": false,
      "is_substrate": false,
      "label": "Script Lock",
      "loops": [
        {
          "kind": "director_note_route",
          "note": "chains A/B/C causality/set-geography/continuity patch locked script (PLAYBOOK:13-64); note_id-gated (REC-176)",
          "to": "scripting/episodes/ep_NNN.md"
        }
      ],
      "node_type": "store",
      "produces": [
        "scripting/episodes/ep_NNN.md (locked screenplay SSOT)"
      ],
      "provenance": [
        {
          "field": "evidence",
          "file": "pipeline/CLAUDE.md",
          "line": 90,
          "ref": "pipeline/CLAUDE.md:90",
          "resolved": false
        },
        {
          "field": "evidence",
          "file": "DIRECTOR_NOTES_PLAYBOOK.md",
          "line": 13,
          "ref": "DIRECTOR_NOTES_PLAYBOOK.md:13",
          "resolved": false
        }
      ],
      "shape": "cylinder",
      "source_index": 15,
      "status": "live",
      "swimlane": "prepro"
    },
    {
      "gate": {
        "pass_condition": "Pydantic-valid AND min<=total_shots<=max (default 28-41); MAX_RETRIES=2 then save-with-warning or review_queue",
        "validator": "validate_camera_test_budget + Pydantic CameraTestedEpisode (ingest_pipeline.py:718,728)"
      },
      "id": "camera_test",
      "inputs": [
        {
          "artifact": "locked episode script text (_load_episode_script)",
          "from": "script_lock"
        }
      ],
      "is_deprecated": false,
      "is_human_review": false,
      "is_substrate": false,
      "label": "Camera Test Pass (Stage 0)",
      "loops": [
        {
          "kind": "reroll",
          "note": "retry w/ error-feedback up to 2 (ingest_pipeline.py:698-735); hard parse-fail -> review_queue",
          "to": "camera_test"
        }
      ],
      "node_type": "generation",
      "produces": [
        "_pipeline/state/visual/camera_tested/ep_NNN.json (shot-boundary blocks)",
        "derivation manifest stamp (script_sha source)"
      ],
      "provenance": [
        {
          "field": "tool",
          "file": "ingest_pipeline.py",
          "line": 633,
          "ref": "ingest_pipeline.py:633",
          "resolved": false
        },
        {
          "field": "evidence",
          "file": "ingest_pipeline.py",
          "line": 633,
          "ref": "ingest_pipeline.py:633",
          "resolved": false
        },
        {
          "field": "evidence",
          "file": "ingest_pipeline.py",
          "line": 97,
          "ref": "ingest_pipeline.py:97",
          "resolved": false
        }
      ],
      "shape": "rect",
      "source_index": 16,
      "status": "live",
      "swimlane": "prepro"
    },
    {
      "gate": {
        "pass_condition": "all CT-shot chars in bible; every char >=1 wardrobe phase; non-overlapping phase ranges; uppercase snake_case ids; 2 retries then review_queue",
        "validator": "Pydantic GlobalBible + bible validation (global-bible/SKILL.md:110)"
      },
      "id": "global_bible",
      "inputs": [
        {
          "artifact": "all camera_tested/ep_NNN.json in batch",
          "from": "camera_test"
        },
        {
          "artifact": "character bible scripting/bible/characters.md (DNA)",
          "from": "script_lock"
        },
        {
          "artifact": "project_config + existing global_bible.json (incremental merge)",
          "from": "external"
        }
      ],
      "is_deprecated": false,
      "is_human_review": false,
      "is_substrate": false,
      "label": "Global Bible (Stage 1 / Breakdown Pass)",
      "loops": [
        {
          "kind": "reroll",
          "note": "Pydantic error -> retry x2; merge preserves human edits",
          "to": "global_bible"
        },
        {
          "kind": "director_note_route",
          "note": "set-geography (chain A) patches sublocation desc; regen ref (PLAYBOOK:14,37-42)",
          "to": "global_bible.json locations.<id>.sublocations"
        }
      ],
      "node_type": "generation",
      "produces": [
        "_pipeline/state/visual/global_bible.json (chars+phases+looks, locations, props, lighting; [OPUS_ENRICHMENT] placeholders)",
        "episode_look_map.json (--detect-looks)",
        "brief_visual/brief_wardrobe -> casting_state.json"
      ],
      "provenance": [
        {
          "field": "tool",
          "file": "ingest_pipeline.py",
          "line": 772,
          "ref": "ingest_pipeline.py:772",
          "resolved": false
        },
        {
          "field": "evidence",
          "file": "ingest_pipeline.py",
          "line": 772,
          "ref": "ingest_pipeline.py:772",
          "resolved": false
        },
        {
          "field": "evidence",
          "file": "global-bible/SKILL.md",
          "line": 149,
          "ref": "global-bible/SKILL.md:149",
          "resolved": false
        }
      ],
      "shape": "rect",
      "source_index": 17,
      "status": "live",
      "swimlane": "prepro"
    },
    {
      "gate": {
        "pass_condition": "no remaining [OPUS_ENRICHMENT]; failures non-blocking",
        "validator": "_find_placeholders re-scan (ingest_pipeline.py:1069); downstream warn-only"
      },
      "id": "enrichment",
      "inputs": [
        {
          "artifact": "global_bible.json [OPUS_ENRICHMENT] placeholders",
          "from": "global_bible"
        },
        {
          "artifact": "scripting/bible/characters.md per-entity DNA",
          "from": "script_lock"
        }
      ],
      "is_deprecated": false,
      "is_human_review": false,
      "is_substrate": false,
      "label": "Opus Enrichment (Stage 1.5)",
      "loops": [
        {
          "kind": "reroll",
          "note": "per-entity; failure -> marker, not hard cap (ingest_pipeline.py:2172,2185)",
          "to": "enrichment"
        }
      ],
      "node_type": "generation",
      "produces": [
        "global_bible.json placeholders filled; failures stamped [OPUS_ENRICHMENT_FAILED]"
      ],
      "provenance": [
        {
          "field": "tool",
          "file": "ingest_pipeline.py",
          "line": 2027,
          "ref": "ingest_pipeline.py:2027",
          "resolved": false
        },
        {
          "field": "evidence",
          "file": "ingest_pipeline.py",
          "line": 2027,
          "ref": "ingest_pipeline.py:2027",
          "resolved": false
        }
      ],
      "shape": "rect",
      "source_index": 18,
      "status": "live",
      "swimlane": "prepro"
    },
    {
      "gate": {
        "pass_condition": "1:1 shot count vs CT; location_id/char_id exist in bible; phase_id matches; axis structurally valid else neutral-fallback; motion_line present; MAX_RETRIES=2",
        "validator": "Pydantic CreativeEpisodeOutput -> validate/sanitize_axis_plans (axis_validation.py:120,141) -> _validate_motion_lines -> validate_spatial_data (spatial_validation.py:35)"
      },
      "id": "plan_pass",
      "inputs": [
        {
          "artifact": "camera_tested/ep_NNN.json (1 episode)",
          "from": "camera_test"
        },
        {
          "artifact": "global_bible.json (enriched; episode summary)",
          "from": "enrichment"
        }
      ],
      "is_deprecated": false,
      "is_human_review": false,
      "is_substrate": false,
      "label": "Plan Pass (Stage 2 / Storyboard Pass)",
      "loops": [
        {
          "kind": "reroll",
          "note": "axis/motion/assembly errors -> retry x2; final-attempt DEGRADE: drop invalid axis_plans -> neutral-fallback not cap (ingest_pipeline.py:1148-1206)",
          "to": "plan_pass"
        },
        {
          "kind": "director_note_route",
          "note": "under-animation (chain D) patches motion_line (PLAYBOOK:16,66-69)",
          "to": "raw.prompt_data.prompt_skeleton.motion_line"
        }
      ],
      "node_type": "generation",
      "produces": [
        "_pipeline/state/visual/plans/ep_NNN_plan.json — the SHOT SKELETON (EpisodePlan: ShotRecord x5 consumer groups)",
        "scene-level axis_plans (SceneAxisPlan: 180-line + jumps/re-establish) LLM-authored",
        "per-shot spatial_data DERIVED (camera_side, screen_direction, axis_segment_id, cut_relation) via propagate_axis"
      ],
      "provenance": [
        {
          "field": "tool",
          "file": "ingest_pipeline.py",
          "line": 1054,
          "ref": "ingest_pipeline.py:1054",
          "resolved": false
        },
        {
          "field": "evidence",
          "file": "ingest_pipeline.py",
          "line": 1054,
          "ref": "ingest_pipeline.py:1054",
          "resolved": false
        },
        {
          "field": "evidence",
          "file": "axis_propagation.py",
          "line": 62,
          "ref": "axis_propagation.py:62",
          "resolved": false
        }
      ],
      "shape": "rect",
      "source_index": 19,
      "status": "live",
      "swimlane": "prepro"
    },
    {
      "gate": {
        "pass_condition": "valid SBD + per-shot blocking JSON per scene",
        "validator": "Pydantic SBD schema (Gemini Pro per scene); blocking_pass.py"
      },
      "id": "blocking_pass",
      "inputs": [
        {
          "artifact": "plans/ep_NNN_plan.json (REQUIRED, after storyboard pass)",
          "from": "plan_pass"
        },
        {
          "artifact": "scene source text (locked script)",
          "from": "script_lock"
        },
        {
          "artifact": "global_bible.json",
          "from": "enrichment"
        }
      ],
      "is_deprecated": false,
      "is_human_review": false,
      "is_substrate": false,
      "label": "Blocking Pass (Stage 2.5)",
      "loops": [
        {
          "kind": "director_note_route",
          "note": "per-shot staging (chain A step 4) patches persisted scene blocking (PLAYBOOK:15,44)",
          "to": "blocking_metadata.characters[].{gaze_target,head_facing,stance,staging_note}"
        }
      ],
      "node_type": "generation",
      "produces": [
        "blocking_metadata per shot (SBD + freeze-frame: gaze_target, head_facing, stance) + updated subject_lines; persisted scene JSON _pipeline/state/orchestration/scenes/"
      ],
      "provenance": [
        {
          "field": "tool",
          "file": "ingest_pipeline.py",
          "line": 1808,
          "ref": "ingest_pipeline.py:1808",
          "resolved": false
        },
        {
          "field": "evidence",
          "file": "ingest_pipeline.py",
          "line": 1808,
          "ref": "ingest_pipeline.py:1808",
          "resolved": false
        }
      ],
      "shape": "rect",
      "source_index": 20,
      "status": "live",
      "swimlane": "prepro"
    },
    {
      "gate": {
        "pass_condition": "hero_selected before turnaround (:921); Screen Test status empty->generating->generated->locked, verdict in {lock,hold,reject}; set-anchor requires locked (:2862)",
        "validator": "casting_state status-machine + Screen Test verdict (casting.py:921,3114) + bible-synced flag (:1260)"
      },
      "id": "casting",
      "inputs": [
        {
          "artifact": "global_bible.json characters.<id>.{visual_description,gender,phases,aesthetic_directives,props}",
          "from": "global_bible"
        },
        {
          "artifact": "brief_visual/brief_wardrobe (casting_state.json)",
          "from": "global_bible"
        },
        {
          "artifact": "episode_look_map.json",
          "from": "global_bible"
        }
      ],
      "is_deprecated": false,
      "is_human_review": false,
      "is_substrate": false,
      "label": "Casting (character refs)",
      "loops": [
        {
          "kind": "reroll",
          "note": "reroll-grid (:1880), reroll-phase (:1988), screen-test reroll (:2886); director_note enriched; _v{N}.png",
          "to": "casting"
        }
      ],
      "node_type": "generation",
      "produces": [
        "grid_images contact-sheet [generate-grid casting.py:727]",
        "assets/char/<slug>/hero.* [select-hero casting.py:820]",
        "assets/char/<slug>/{front,three_quarter,profile,back}.* [generate-turnaround casting.py:898]",
        "assets/expressions/*_active.png (27-ref matrix) [generate-expressions casting.py:1046]",
        "assets/char/<slug>/base/pool/{identity,turn,expr}/ (v3 canonical pool)"
      ],
      "provenance": [
        {
          "field": "evidence",
          "file": "pipeline/CLAUDE.md",
          "line": 78,
          "ref": "pipeline/CLAUDE.md:78",
          "resolved": false
        },
        {
          "field": "evidence",
          "file": "global-bible/SKILL.md",
          "line": 43,
          "ref": "global-bible/SKILL.md:43",
          "resolved": false
        }
      ],
      "shape": "rect",
      "source_index": 21,
      "status": "live",
      "swimlane": "prepro"
    },
    {
      "gate": {
        "pass_condition": "philosophy approved -> theses; thesis_approved before rewrite-phases (:2427); apply-rewrite gates writes to matching phase_ids",
        "validator": "approval flags (casting.py:2268 approve-philosophy, 2353 approve-thesis, 2475 apply-rewrite)"
      },
      "id": "wardrobe_intent_gate",
      "inputs": [
        {
          "artifact": "treatment.md + series_bible.md (philosophy)",
          "from": "script_lock"
        },
        {
          "artifact": "global_bible.json wardrobe fields + episode_arc.md",
          "from": "global_bible"
        }
      ],
      "is_deprecated": false,
      "is_human_review": true,
      "is_substrate": false,
      "label": "Wardrobe Intent Gate (sub-phase of Casting)",
      "loops": [
        {
          "kind": "director_note_route",
          "note": "propose->approve cycle; rewrites land in bible SSOT, feed Screen Test",
          "to": "global_bible.json wardrobe fields"
        }
      ],
      "node_type": "human_review",
      "produces": [
        "global_bible.json: wardrobe_philosophy(+approved), wardrobe_arc_thesis(+approved), phases.<id>.wardrobe_description/arc_delta/arc_carries"
      ],
      "provenance": [
        {
          "field": "evidence",
          "file": "casting.py",
          "line": 2176,
          "ref": "casting.py:2176",
          "resolved": false
        }
      ],
      "shape": "diamond_person",
      "source_index": 22,
      "status": "live",
      "swimlane": "prepro"
    },
    {
      "gate": {
        "pass_condition": "location hero requires ref_path on disk; generate-location async",
        "validator": "ref_path existence (casting.py:1162); moodboard_picks list type"
      },
      "id": "location_refs",
      "inputs": [
        {
          "artifact": "global_bible.json locations.<id>.{description,atmosphere}",
          "from": "global_bible"
        }
      ],
      "is_deprecated": false,
      "is_human_review": false,
      "is_substrate": false,
      "label": "Location Refs",
      "loops": [
        {
          "kind": "director_note_route",
          "note": "set-geography regen sublocation refs (chain A; gen_sublocations.py restamp trap)",
          "to": "global_bible.json locations.<id>.sublocations + assets/loc/<id>/base/sublocations/"
        }
      ],
      "node_type": "generation",
      "produces": [
        "assets/loc/<slug>/base/pool/loc/ moodboard set [generate-location]",
        "assets/loc/<slug>/hero.* [select-location-hero]",
        "casting_state.json locations.<id>.moodboard_picks [update-location-moodboard]"
      ],
      "provenance": [
        {
          "field": "evidence",
          "file": "casting.py",
          "line": 1112,
          "ref": "casting.py:1112",
          "resolved": false
        },
        {
          "field": "evidence",
          "file": "pipeline/CLAUDE.md",
          "line": 79,
          "ref": "pipeline/CLAUDE.md:79",
          "resolved": false
        }
      ],
      "shape": "rect",
      "source_index": 23,
      "status": "live",
      "swimlane": "prepro"
    },
    {
      "gate": null,
      "id": "previz",
      "inputs": [
        {
          "artifact": "shot skeleton / script beat (ep_NNN_plan.json shot record)",
          "from": "plan_pass"
        },
        {
          "artifact": "scoped Global Bible text",
          "from": "global_bible"
        },
        {
          "artifact": "3-shot continuity window (N-1,N,N+1)",
          "from": "plan_pass"
        },
        {
          "artifact": "location moodboards (2-3)",
          "from": "location_refs"
        },
        {
          "artifact": "prop ref (1)",
          "from": "location_refs"
        },
        {
          "artifact": "character hero + 1 turnaround per char",
          "from": "casting"
        },
        {
          "artifact": "expression ref (1, non-neutral)",
          "from": "casting"
        },
        {
          "artifact": "cinema-mode constraint/style tokens",
          "from": "cinema_mode"
        },
        {
          "artifact": "behavioral preamble + generative directive",
          "from": "external"
        }
      ],
      "is_deprecated": true,
      "is_human_review": false,
      "is_substrate": false,
      "label": "Previz Generation (gut-check boards)",
      "loops": [],
      "node_type": "generation",
      "produces": [
        "previz assets (prep/ep_NNN/)",
        "previz_inputs_snapshot"
      ],
      "provenance": [
        {
          "field": "tool",
          "file": "recoil/pipeline/_lib/previz_context.py",
          "line": 1706,
          "ref": "recoil/pipeline/_lib/previz_context.py:1706",
          "resolved": true
        },
        {
          "field": "tool",
          "file": "prompt_engine.py",
          "line": 6714,
          "ref": "prompt_engine.py:6714",
          "resolved": false
        },
        {
          "field": "evidence",
          "file": "previz_context.py",
          "line": 1706,
          "ref": "previz_context.py:1706",
          "resolved": false
        },
        {
          "field": "evidence",
          "file": "take_inputs.py",
          "line": 91,
          "ref": "take_inputs.py:91",
          "resolved": false
        },
        {
          "field": "evidence",
          "file": "pipeline/CLAUDE.md",
          "line": 97,
          "ref": "pipeline/CLAUDE.md:97",
          "resolved": false
        }
      ],
      "shape": "rect",
      "source_index": 24,
      "status": "deprecated",
      "swimlane": "production"
    },
    {
      "gate": {
        "pass_condition": "human approve; reject sets previs_rejected (server.py:2395-2396)",
        "validator": "Workspace promote_item / reject_shot (server.py:2293, :2369)"
      },
      "id": "previz_review",
      "inputs": [
        {
          "artifact": "previz assets + inputs snapshot",
          "from": "previz"
        }
      ],
      "is_deprecated": true,
      "is_human_review": true,
      "is_substrate": false,
      "label": "Previz Review (HUMAN)",
      "loops": [
        {
          "kind": "reroll",
          "note": "reject -> regenerate previz",
          "to": "previz"
        },
        {
          "kind": "director_note_route",
          "note": "physical/blocking/spatial notes -> script/bible/blocking (PLAYBOOK; PIPELINE_SSOT protocol 10)",
          "to": "ssot_layer"
        }
      ],
      "node_type": "human_review",
      "produces": [
        "status: previs_pending -> (approve|previs_rejected)"
      ],
      "provenance": [
        {
          "field": "evidence",
          "file": "server.py",
          "line": 2369,
          "ref": "server.py:2369",
          "resolved": false
        },
        {
          "field": "evidence",
          "file": "pipeline/CLAUDE.md",
          "line": 98,
          "ref": "pipeline/CLAUDE.md:98",
          "resolved": false
        }
      ],
      "shape": "diamond_person",
      "source_index": 25,
      "status": "deprecated",
      "swimlane": "production"
    },
    {
      "gate": {
        "pass_condition": "board emitted status=proposed when clean; else status=rejected with reroll lineage (board_builder.py:735-821)",
        "validator": "board_builder auto-reroll critic loop (board_builder.py:673 build_with_auto_reroll); plan_pass_critic prereq"
      },
      "id": "keyframes",
      "inputs": [
        {
          "artifact": "shot skeleton / shot plan record (5 consumer groups)",
          "from": "plan_pass"
        },
        {
          "artifact": "Global Bible (chars/locations/props/phases)",
          "from": "global_bible"
        },
        {
          "artifact": "character/location/prop refs",
          "from": "casting"
        },
        {
          "artifact": "location refs",
          "from": "location_refs"
        },
        {
          "artifact": "cinema-mode tokens",
          "from": "cinema_mode"
        }
      ],
      "is_deprecated": false,
      "is_human_review": false,
      "is_substrate": false,
      "label": "Keyframe / Board Generation (production frames)",
      "loops": [
        {
          "kind": "reroll",
          "note": "auto-reroll up to max_board_attempts (default 3); each = new board version (board_builder.py:61)",
          "to": "keyframes"
        }
      ],
      "node_type": "generation",
      "produces": [
        "proposed storyboard strip (prep/ep_NNN/storyboards/)",
        "board sidecar status=proposed",
        "structural_sha + source_sha256"
      ],
      "provenance": [
        {
          "field": "tool",
          "file": "board_builder.py",
          "line": 209,
          "ref": "board_builder.py:209",
          "resolved": false
        },
        {
          "field": "evidence",
          "file": "board_builder.py",
          "line": 209,
          "ref": "board_builder.py:209",
          "resolved": false
        },
        {
          "field": "evidence",
          "file": "pipeline/CLAUDE.md",
          "line": 99,
          "ref": "pipeline/CLAUDE.md:99",
          "resolved": false
        }
      ],
      "shape": "rect",
      "source_index": 26,
      "status": "live",
      "swimlane": "production"
    },
    {
      "gate": {
        "pass_condition": "source_sha256 == board.source_sha256 (not stale) AND artifact valid AND human approve (generate.py:949-986)",
        "validator": "_run_board_decision freshness + artifact checks (generate.py:879-1019)"
      },
      "id": "board_decision",
      "inputs": [
        {
          "artifact": "proposed board (status=proposed)",
          "from": "keyframes"
        }
      ],
      "is_deprecated": false,
      "is_human_review": true,
      "is_substrate": false,
      "label": "Board/Keyframe Approval Gate (HUMAN)",
      "loops": [
        {
          "kind": "reroll",
          "note": "reject -> reject_board; stale sha -> regenerate --storyboard (generate.py:951-953)",
          "to": "keyframes"
        }
      ],
      "node_type": "human_review",
      "produces": [
        "board status: approved|rejected",
        "scene locked",
        "board SSOT stamp in manifest.execution.boards"
      ],
      "provenance": [
        {
          "field": "tool",
          "file": "cli/generate.py",
          "line": 879,
          "ref": "cli/generate.py:879",
          "resolved": false
        },
        {
          "field": "tool",
          "file": "workspace/board.py",
          "line": 40,
          "ref": "workspace/board.py:40",
          "resolved": false
        },
        {
          "field": "evidence",
          "file": "generate.py",
          "line": 879,
          "ref": "generate.py:879",
          "resolved": false
        },
        {
          "field": "evidence",
          "file": "board.py",
          "line": 98,
          "ref": "board.py:98",
          "resolved": false
        },
        {
          "field": "evidence",
          "file": "pipeline/CLAUDE.md",
          "line": 99,
          "ref": "pipeline/CLAUDE.md:99",
          "resolved": false
        }
      ],
      "shape": "diamond_person",
      "source_index": 27,
      "status": "live",
      "swimlane": "production"
    },
    {
      "gate": {
        "pass_condition": "board approved AND sha not stale; raises BoardBuilderError if stale -> re-run --storyboard",
        "validator": "render_board_finish + resolve_board_for_spend (board_builder.py:508-560,:101)"
      },
      "id": "photoreal_finish",
      "inputs": [
        {
          "artifact": "approved board (fresh source_sha256)",
          "from": "board_decision"
        }
      ],
      "is_deprecated": false,
      "is_human_review": false,
      "is_substrate": false,
      "label": "Photoreal Board Finish (full-size keyframe)",
      "loops": [],
      "node_type": "generation",
      "produces": [
        "photoreal_artifact (validated on disk)"
      ],
      "provenance": [
        {
          "field": "tool",
          "file": "board_builder.py",
          "line": 508,
          "ref": "board_builder.py:508",
          "resolved": false
        },
        {
          "field": "evidence",
          "file": "board_builder.py",
          "line": 508,
          "ref": "board_builder.py:508",
          "resolved": false
        },
        {
          "field": "evidence",
          "file": "generate.py",
          "line": 1016,
          "ref": "generate.py:1016",
          "resolved": false
        }
      ],
      "shape": "rect",
      "source_index": 28,
      "status": "live",
      "swimlane": "production"
    },
    {
      "gate": {
        "pass_condition": "board gate: r2v_multi beats need approved+fresh board (:224-265); budget: est cost <= remaining; refs fingerprint matches (else demote+rebuild)",
        "validator": "pre-dispatch gates in _dispatch_one_beat: board gate (:224), budget (:1725 BudgetGuard), inputs_fingerprint drift (:1401-1420), phantom-success demotion (:460), stale-take recovery (:367)"
      },
      "id": "video_gen",
      "inputs": [
        {
          "artifact": "approved board ref (into reference_images)",
          "from": "photoreal_finish"
        },
        {
          "artifact": "canonical plan shots / coverage passes",
          "from": "plan_pass"
        },
        {
          "artifact": "character/location refs (resolved)",
          "from": "casting"
        },
        {
          "artifact": "cinema-mode camera/style tokens",
          "from": "cinema_mode"
        }
      ],
      "is_deprecated": false,
      "is_human_review": false,
      "is_substrate": false,
      "label": "Video Generation (coverage passes / takes)",
      "loops": [
        {
          "kind": "reroll",
          "note": "retry = NEW Take (beat.new_take), never mutate; --new-take/POST reroll preflighted (:736,:2110); StrategyEngine mutates next workflow (:2013)",
          "to": "video_gen"
        },
        {
          "kind": "director_note_route",
          "note": "approve board -> ref change -> fingerprint drift -> demote succeeded take -> re-render (:591-598 V-D trigger)",
          "to": "ssot_layer"
        }
      ],
      "node_type": "generation",
      "produces": [
        "renders/ep_NNN/*.mp4 (per take)",
        "boundary_frames/",
        "GenerationReceipt",
        "Scene/Beat/Take JSON"
      ],
      "provenance": [
        {
          "field": "tool",
          "file": "episode_runner.py",
          "line": 2197,
          "ref": "episode_runner.py:2197",
          "resolved": false
        },
        {
          "field": "evidence",
          "file": "episode_runner.py",
          "line": 2197,
          "ref": "episode_runner.py:2197",
          "resolved": false
        }
      ],
      "shape": "rect",
      "source_index": 29,
      "status": "live",
      "swimlane": "production"
    },
    {
      "gate": {
        "pass_condition": "exit 0 = every enumerated path passes all 16 assertions; 1=assert fail; 2=infra",
        "validator": "audit_assertions.run_all_assertions over build_dispatch_payload(dry_run=True)"
      },
      "id": "dispatch_audit",
      "inputs": [
        {
          "artifact": "synthetic fixture plan (audit_plan.json)",
          "from": "external"
        }
      ],
      "is_deprecated": false,
      "is_human_review": false,
      "is_substrate": false,
      "label": "Dispatch-Audit Gate (output-shape, build-time)",
      "loops": [],
      "node_type": "gate",
      "produces": [
        "PASS/FAIL per (modality x model x modifier) dispatch shape"
      ],
      "provenance": [
        {
          "field": "evidence",
          "file": "audit_dispatch.py",
          "line": 1,
          "ref": "audit_dispatch.py:1",
          "resolved": false
        }
      ],
      "shape": "diamond",
      "source_index": 30,
      "status": "live",
      "swimlane": "production"
    },
    {
      "gate": null,
      "id": "cinema_mode",
      "inputs": [
        {
          "artifact": "project_config.json::cinema_mode activation",
          "from": "external"
        }
      ],
      "is_deprecated": false,
      "is_human_review": false,
      "is_substrate": false,
      "label": "Cinema Mode preset layer (camera/lens/stock/grade)",
      "loops": [],
      "node_type": "input",
      "produces": [
        "camera-body/lens/stock/grade tokens emitted into prompts via prompt_engine"
      ],
      "provenance": [
        {
          "field": "evidence",
          "file": "pipeline/CLAUDE.md",
          "line": 163,
          "ref": "pipeline/CLAUDE.md:163",
          "resolved": false
        }
      ],
      "shape": "chip",
      "source_index": 31,
      "status": "live",
      "swimlane": "production"
    },
    {
      "gate": {
        "pass_condition": "human approve/promote; reject -> keyframe/video_rejected (:2397-2402); failure_mode logged to LearningEngine (:2436)",
        "validator": "reject_shot/reject_segment/regenerate_shot (server.py:2369,:3436,:3488)"
      },
      "id": "dailies_review",
      "inputs": [
        {
          "artifact": "rendered takes (renders/ep_NNN/*.mp4) + segments",
          "from": "video_gen"
        }
      ],
      "is_deprecated": false,
      "is_human_review": true,
      "is_substrate": false,
      "label": "Dailies Review (HUMAN)",
      "loops": [
        {
          "kind": "reroll",
          "note": "reject take/segment -> regenerate (new Take); regenerate_shot patches sidecar replaced_by (:3488-3602)",
          "to": "video_gen"
        },
        {
          "kind": "director_note_route",
          "note": "verbal notes -> owning SSOT layer (PLAYBOOK)",
          "to": "ssot_layer"
        }
      ],
      "node_type": "human_review",
      "produces": [
        "status: pending -> (promote|keyframe_rejected|video_rejected|rejected)"
      ],
      "provenance": [
        {
          "field": "evidence",
          "file": "server.py",
          "line": 2369,
          "ref": "server.py:2369",
          "resolved": false
        },
        {
          "field": "evidence",
          "file": "pipeline/CLAUDE.md",
          "line": 100,
          "ref": "pipeline/CLAUDE.md:100",
          "resolved": false
        }
      ],
      "shape": "diamond_person",
      "source_index": 32,
      "status": "live",
      "swimlane": "review_export"
    },
    {
      "gate": {
        "pass_condition": "human confirms cut timestamps; cut-detection alignment within tolerance (:3287-3407)",
        "validator": "confirm_timestamps / get_detected_cuts (server.py:3287,:3240)"
      },
      "id": "final_review_export",
      "inputs": [
        {
          "artifact": "approved takes + confirmed cut points",
          "from": "dailies_review"
        }
      ],
      "is_deprecated": false,
      "is_human_review": true,
      "is_substrate": false,
      "label": "Final Review + Export",
      "loops": [
        {
          "kind": "reroll",
          "note": "final reject -> re-render affected pass as new take",
          "to": "video_gen"
        }
      ],
      "node_type": "human_review",
      "produces": [
        "final episode cut / EDL-FCPXML handoff (Phase C)",
        "selected primary takes"
      ],
      "provenance": [
        {
          "field": "evidence",
          "file": "server.py",
          "line": 3240,
          "ref": "server.py:3240",
          "resolved": false
        },
        {
          "field": "evidence",
          "file": "pipeline/CLAUDE.md",
          "line": 101,
          "ref": "pipeline/CLAUDE.md:101",
          "resolved": false
        }
      ],
      "shape": "diamond_person",
      "source_index": 33,
      "status": "live",
      "swimlane": "review_export"
    },
    {
      "gate": {
        "pass_condition": "payload shape matches modality contract; model profile flags honored",
        "validator": "_validate_payload + _validate_model_constraints (dispatch.py:232,:200)"
      },
      "id": "dispatch_entry_point",
      "inputs": [
        {
          "artifact": "modality string + payload dict",
          "from": "workflow_step"
        },
        {
          "artifact": "DispatchContext (caller_id, step_runner, project, episode)",
          "from": "external"
        }
      ],
      "is_deprecated": false,
      "is_human_review": false,
      "is_substrate": false,
      "label": "dispatch() — single generation entry point",
      "loops": [],
      "node_type": "decision",
      "produces": [
        "GenerationReceipt",
        "_dispatch_logs/receipts.jsonl line"
      ],
      "provenance": [
        {
          "field": "tool",
          "file": "dispatch.py",
          "line": 294,
          "ref": "dispatch.py:294",
          "resolved": false
        },
        {
          "field": "evidence",
          "file": "dispatch.py",
          "line": 294,
          "ref": "dispatch.py:294",
          "resolved": false
        },
        {
          "field": "evidence",
          "file": "ssot_manifest.yaml",
          "line": 88,
          "ref": "ssot_manifest.yaml:88",
          "resolved": false
        }
      ],
      "shape": "hex",
      "source_index": 34,
      "status": "live",
      "swimlane": "infra"
    },
    {
      "gate": {
        "pass_condition": "modality string registered (instance or factory)",
        "validator": "RunnerRegistry.get (registry.py:216) — KeyError if unregistered"
      },
      "id": "modality_registry",
      "inputs": [
        {
          "artifact": "modality_id -> runner instance",
          "from": "dispatch_entry_point"
        }
      ],
      "is_deprecated": false,
      "is_human_review": false,
      "is_substrate": false,
      "label": "Modality registry — 'any model, one socket'",
      "loops": [],
      "node_type": "store",
      "produces": [
        "resolved ModalityRunner via get_runner(modality)"
      ],
      "provenance": [
        {
          "field": "tool",
          "file": "registry.py",
          "line": 138,
          "ref": "registry.py:138",
          "resolved": false
        },
        {
          "field": "tool",
          "file": "dispatch.py",
          "line": 140,
          "ref": "dispatch.py:140",
          "resolved": false
        },
        {
          "field": "evidence",
          "file": "registry.py",
          "line": 46,
          "ref": "registry.py:46",
          "resolved": false
        },
        {
          "field": "evidence",
          "file": "dispatch.py",
          "line": 166,
          "ref": "dispatch.py:166",
          "resolved": false
        },
        {
          "field": "evidence",
          "file": "ssot_manifest.yaml",
          "line": 151,
          "ref": "ssot_manifest.yaml:151",
          "resolved": false
        }
      ],
      "shape": "cylinder",
      "source_index": 35,
      "status": "live",
      "swimlane": "infra"
    },
    {
      "gate": {
        "pass_condition": "generation + attached gates pass",
        "validator": "runner-internal gate (gate_verdict in RunResult.metadata)"
      },
      "id": "modality_image_t2i",
      "inputs": [
        {
          "artifact": "keyframe payload",
          "from": "dispatch_entry_point"
        }
      ],
      "is_deprecated": false,
      "is_human_review": false,
      "is_substrate": false,
      "label": "image_t2i (keyframe/still) modality",
      "loops": [],
      "node_type": "generation",
      "produces": [
        "RunResult (output_path png)"
      ],
      "provenance": [
        {
          "field": "tool",
          "file": "registry.py",
          "line": 46,
          "ref": "registry.py:46",
          "resolved": false
        },
        {
          "field": "evidence",
          "file": "dispatch.py",
          "line": 167,
          "ref": "dispatch.py:167",
          "resolved": false
        },
        {
          "field": "evidence",
          "file": "registry.py",
          "line": 23,
          "ref": "registry.py:23",
          "resolved": false
        }
      ],
      "shape": "rect",
      "source_index": 36,
      "status": "live",
      "swimlane": "infra"
    },
    {
      "gate": {
        "pass_condition": "start_frame exists if set; legacy 'image' key rejected (Bug-C guard)",
        "validator": "_validate_payload video_i2v branch (dispatch.py:249)"
      },
      "id": "modality_video_i2v",
      "inputs": [
        {
          "artifact": "video payload (start_frame Path or t2v)",
          "from": "dispatch_entry_point"
        }
      ],
      "is_deprecated": false,
      "is_human_review": false,
      "is_substrate": false,
      "label": "video_i2v (i2v/t2v) modality",
      "loops": [],
      "node_type": "generation",
      "produces": [
        "RunResult (output_path mp4)"
      ],
      "provenance": [
        {
          "field": "evidence",
          "file": "dispatch.py",
          "line": 168,
          "ref": "dispatch.py:168",
          "resolved": false
        }
      ],
      "shape": "rect",
      "source_index": 37,
      "status": "live",
      "swimlane": "infra"
    },
    {
      "gate": {
        "pass_condition": "soft: zero reference_images logs warning (env-only allowed)",
        "validator": "_validate_payload r2v_multi branch (dispatch.py:268) — WARN only"
      },
      "id": "modality_r2v_multi",
      "inputs": [
        {
          "artifact": "reference_images + multi-shot payload",
          "from": "dispatch_entry_point"
        }
      ],
      "is_deprecated": false,
      "is_human_review": false,
      "is_substrate": false,
      "label": "r2v_multi (multi-shot scene batching) modality",
      "loops": [],
      "node_type": "generation",
      "produces": [
        "RunResult"
      ],
      "provenance": [
        {
          "field": "tool",
          "file": "registry.py",
          "line": 50,
          "ref": "registry.py:50",
          "resolved": false
        },
        {
          "field": "evidence",
          "file": "dispatch.py",
          "line": 170,
          "ref": "dispatch.py:170",
          "resolved": false
        }
      ],
      "shape": "rect",
      "source_index": 38,
      "status": "live",
      "swimlane": "infra"
    },
    {
      "gate": {
        "pass_condition": "all 6 required payload keys present",
        "validator": "_validate_payload storyboard branch (dispatch.py:277)"
      },
      "id": "modality_storyboard",
      "inputs": [
        {
          "artifact": "storyboard payload (shot_id, prompt, model, size_override, save_dir, filename_stem)",
          "from": "dispatch_entry_point"
        }
      ],
      "is_deprecated": false,
      "is_human_review": false,
      "is_substrate": false,
      "label": "storyboard (board panel) modality",
      "loops": [
        {
          "kind": "director_note_route",
          "note": "board judged by story gate; rejection routes to script/board/prompt layer",
          "to": "board_story_gate"
        }
      ],
      "node_type": "generation",
      "produces": [
        "board PNG RunResult"
      ],
      "provenance": [
        {
          "field": "tool",
          "file": "registry.py",
          "line": 51,
          "ref": "registry.py:51",
          "resolved": false
        },
        {
          "field": "evidence",
          "file": "dispatch.py",
          "line": 175,
          "ref": "dispatch.py:175",
          "resolved": false
        },
        {
          "field": "evidence",
          "file": "registry.py",
          "line": 59,
          "ref": "registry.py:59",
          "resolved": false
        }
      ],
      "shape": "rect",
      "source_index": 39,
      "status": "live",
      "swimlane": "infra"
    },
    {
      "gate": {
        "pass_condition": "synthesis succeeds; fail-fast 401/402/422/429",
        "validator": "provider adapter typed errors (AudioSynthesisError)"
      },
      "id": "modality_audio_t2a",
      "inputs": [
        {
          "artifact": "audio payload (text, voice_id, model)",
          "from": "dispatch_entry_point"
        }
      ],
      "is_deprecated": false,
      "is_human_review": false,
      "is_substrate": false,
      "label": "audio_t2a (TTS via ElevenLabs) modality",
      "loops": [],
      "node_type": "generation",
      "produces": [
        "RunResult (output_path mp3)"
      ],
      "provenance": [
        {
          "field": "evidence",
          "file": "dispatch.py",
          "line": 177,
          "ref": "dispatch.py:177",
          "resolved": false
        },
        {
          "field": "evidence",
          "file": "recoil/CLAUDE.md",
          "line": 368,
          "ref": "recoil/CLAUDE.md:368",
          "resolved": true
        },
        {
          "field": "evidence",
          "file": "registry.py",
          "line": 26,
          "ref": "registry.py:26",
          "resolved": false
        }
      ],
      "shape": "rect",
      "source_index": 40,
      "status": "live",
      "swimlane": "infra"
    },
    {
      "gate": {
        "pass_condition": "lipsync job succeeds",
        "validator": "provider adapter typed errors (LipSyncError)"
      },
      "id": "modality_lipsync_post",
      "inputs": [
        {
          "artifact": "lipsync payload (video_path, audio_path, model)",
          "from": "dispatch_entry_point"
        }
      ],
      "is_deprecated": false,
      "is_human_review": false,
      "is_substrate": false,
      "label": "lipsync_post (sync.so post-process) modality",
      "loops": [],
      "node_type": "generation",
      "produces": [
        "RunResult (lipsynced mp4)"
      ],
      "provenance": [
        {
          "field": "evidence",
          "file": "dispatch.py",
          "line": 179,
          "ref": "dispatch.py:179",
          "resolved": false
        },
        {
          "field": "evidence",
          "file": "recoil/CLAUDE.md",
          "line": 388,
          "ref": "recoil/CLAUDE.md:388",
          "resolved": true
        },
        {
          "field": "evidence",
          "file": "registry.py",
          "line": 27,
          "ref": "registry.py:27",
          "resolved": false
        }
      ],
      "shape": "rect",
      "source_index": 41,
      "status": "live",
      "swimlane": "infra"
    },
    {
      "gate": {
        "pass_condition": "key set + artifact scorable",
        "validator": "GEMINI_API_KEY presence at EvalNode layer"
      },
      "id": "modality_eval",
      "inputs": [
        {
          "artifact": "artifact path + rubric",
          "from": "eval_panel"
        }
      ],
      "is_deprecated": false,
      "is_human_review": false,
      "is_substrate": true,
      "label": "eval_image_v1 / eval_video_v1 / eval_audio_v1 modalities",
      "loops": [],
      "node_type": "gate",
      "produces": [
        "EvalResult / ScoreCard"
      ],
      "provenance": [
        {
          "field": "tool",
          "file": "dispatch.py",
          "line": 407,
          "ref": "dispatch.py:407",
          "resolved": false
        },
        {
          "field": "evidence",
          "file": "dispatch.py",
          "line": 407,
          "ref": "dispatch.py:407",
          "resolved": false
        },
        {
          "field": "evidence",
          "file": "ssot_manifest.yaml",
          "line": 169,
          "ref": "ssot_manifest.yaml:169",
          "resolved": false
        }
      ],
      "shape": "diamond",
      "source_index": 42,
      "status": "substrate_only",
      "swimlane": "infra"
    },
    {
      "gate": {
        "pass_condition": "a take.status==succeeded selectable as primary, or exhausted",
        "validator": "Beat.is_exhausted (take.py:215) — max_takes(3) + phantom_recovery slots"
      },
      "id": "take_store",
      "inputs": [
        {
          "artifact": "Workflow (one per Take)",
          "from": "workflow_step"
        },
        {
          "artifact": "GenerationReceipt per WorkflowStep",
          "from": "dispatch_entry_point"
        }
      ],
      "is_deprecated": false,
      "is_human_review": false,
      "is_substrate": false,
      "label": "Take/Beat/Scene editorial model — reroll = new Take",
      "loops": [
        {
          "kind": "reroll",
          "note": "re-attempt = Beat.new_take(workflow=fresh) appended, NOT mutation (take.py:430)",
          "to": "take_store"
        }
      ],
      "node_type": "store",
      "produces": [
        "Beat.takes[] (append-only)",
        "primary_take_id",
        "derived Beat/Scene status"
      ],
      "provenance": [
        {
          "field": "evidence",
          "file": "episode_runner.py",
          "line": 357,
          "ref": "episode_runner.py:357",
          "resolved": false
        }
      ],
      "shape": "cylinder",
      "source_index": 43,
      "status": "live",
      "swimlane": "infra"
    },
    {
      "gate": {
        "pass_condition": "first_success: first succeeded; score: highest aggregate; manual: caller-set",
        "validator": "strategy dispatch (take.py:709)"
      },
      "id": "select_primary_decision",
      "inputs": [
        {
          "artifact": "Beat.takes[] with statuses/aggregate_scores",
          "from": "take_store"
        }
      ],
      "is_deprecated": false,
      "is_human_review": false,
      "is_substrate": false,
      "label": "Beat.select_primary — primary take strategy",
      "loops": [],
      "node_type": "decision",
      "produces": [
        "Beat.primary_take_id"
      ],
      "provenance": [
        {
          "field": "tool",
          "file": "take.py",
          "line": 685,
          "ref": "take.py:685",
          "resolved": false
        }
      ],
      "shape": "hex",
      "source_index": 44,
      "status": "live",
      "swimlane": "infra"
    },
    {
      "gate": {
        "pass_condition": "panel_score computed; cost_cap aborts mid-panel",
        "validator": "PanelOfJudges aggregation (median default) + cost_cap_usd (eval.py:67-72)"
      },
      "id": "eval_panel",
      "inputs": [
        {
          "artifact": "GenerationReceipt artifact path + rubric",
          "from": "take_store"
        }
      ],
      "is_deprecated": false,
      "is_human_review": false,
      "is_substrate": true,
      "label": "PanelOfJudges — multi-judge score-based eval",
      "loops": [
        {
          "kind": "reroll",
          "note": "score feeds Beat.select_primary('score')",
          "to": "select_primary_decision"
        }
      ],
      "node_type": "gate",
      "produces": [
        "ScoreCard -> receipt.eval_scores[panel_id]",
        "receipt.provenance['eval_cost_usd']",
        "Take.aggregate_score"
      ],
      "provenance": [
        {
          "field": "tool",
          "file": "take.py",
          "line": 126,
          "ref": "take.py:126",
          "resolved": false
        },
        {
          "field": "evidence",
          "file": "take.py",
          "line": 126,
          "ref": "take.py:126",
          "resolved": false
        },
        {
          "field": "evidence",
          "file": "ssot_manifest.yaml",
          "line": 147,
          "ref": "ssot_manifest.yaml:147",
          "resolved": false
        }
      ],
      "shape": "diamond",
      "source_index": 45,
      "status": "substrate_only",
      "swimlane": "infra"
    },
    {
      "gate": {
        "pass_condition": "n/a",
        "validator": "mirrors detect_failure_mode return shape"
      },
      "id": "strategy_score_bridge",
      "inputs": [
        {
          "artifact": "PanelOfJudges ScoreCard",
          "from": "eval_panel"
        }
      ],
      "is_deprecated": false,
      "is_human_review": false,
      "is_substrate": true,
      "label": "from_score_card — score -> FailureMode retry bridge",
      "loops": [],
      "node_type": "decision",
      "produces": [
        "(FailureMode, float)"
      ],
      "provenance": [
        {
          "field": "evidence",
          "file": "strategy_registry.py",
          "line": 1540,
          "ref": "strategy_registry.py:1540",
          "resolved": false
        }
      ],
      "shape": "hex",
      "source_index": 46,
      "status": "substrate_only",
      "swimlane": "infra"
    },
    {
      "gate": {
        "pass_condition": "failure classified to a strategy",
        "validator": "detect_failure_mode (pipeline/core/failure_mode.py)"
      },
      "id": "strategy_engine_live",
      "inputs": [
        {
          "artifact": "failed Take classified by detect_failure_mode()",
          "from": "take_store"
        }
      ],
      "is_deprecated": false,
      "is_human_review": false,
      "is_substrate": false,
      "label": "StrategyEngine — LIVE retry overlay (production reroll brain)",
      "loops": [
        {
          "kind": "reroll",
          "note": "overlay seed/tier via provider_hints onto next take",
          "to": "take_store"
        }
      ],
      "node_type": "decision",
      "produces": [
        "StrategyDiff overlaid onto next Workflow before Take.execute()"
      ],
      "provenance": [
        {
          "field": "evidence",
          "file": "ssot_manifest.yaml",
          "line": 233,
          "ref": "ssot_manifest.yaml:233",
          "resolved": false
        }
      ],
      "shape": "hex",
      "source_index": 47,
      "status": "live",
      "swimlane": "infra"
    },
    {
      "gate": {
        "pass_condition": "structural_sha unchanged => locked downstream survive; content_sha change alone does NOT invalidate",
        "validator": "structural_sha equality (derivation_sha.py:57)"
      },
      "id": "provenance_index",
      "inputs": [
        {
          "artifact": "EpisodePlan / ShotRecord dicts",
          "from": "plan_pass"
        },
        {
          "artifact": "GenerationReceipt provenance",
          "from": "dispatch_entry_point"
        }
      ],
      "is_deprecated": false,
      "is_human_review": false,
      "is_substrate": false,
      "label": "Provenance / freshness — structural vs content fingerprint",
      "loops": [
        {
          "kind": "director_note_route",
          "note": "structural re-derive invalidates locked downstream; fingerprint drift demotes succeeded takes",
          "to": "take_store"
        }
      ],
      "node_type": "store",
      "produces": [
        "structural_sha (partition fields)",
        "content_sha (full bytes)",
        "freshness verdict"
      ],
      "provenance": [
        {
          "field": "evidence",
          "file": "derivation_sha.py",
          "line": 32,
          "ref": "derivation_sha.py:32",
          "resolved": false
        },
        {
          "field": "evidence",
          "file": "DIRECTOR_NOTES_PLAYBOOK.md",
          "line": 85,
          "ref": "DIRECTOR_NOTES_PLAYBOOK.md:85",
          "resolved": false
        }
      ],
      "shape": "cylinder",
      "source_index": 48,
      "status": "live",
      "swimlane": "infra"
    },
    {
      "gate": {
        "pass_condition": "class==ok; else board_problem|script_problem|prompt_problem|mixed|judge_unavailable",
        "validator": "story_gate panel/transition forced checks (story_gate.py:399)"
      },
      "id": "board_story_gate",
      "inputs": [
        {
          "artifact": "storyboard PNG + scene context",
          "from": "modality_storyboard"
        }
      ],
      "is_deprecated": false,
      "is_human_review": false,
      "is_substrate": false,
      "label": "Story gate — board verdict router (script/board/prompt)",
      "loops": [
        {
          "kind": "director_note_route",
          "note": "script_problem -> patch ep_NNN.md",
          "to": "script_lock"
        },
        {
          "kind": "director_note_route",
          "note": "board_problem -> blocking; prompt_problem -> prompt encode",
          "to": "provenance_index"
        }
      ],
      "node_type": "gate",
      "produces": [
        "verdict sidecar prep/ep_NNN/storyboards/<board>.verdict.json",
        "routing.class label"
      ],
      "provenance": [
        {
          "field": "tool",
          "file": "take.py",
          "line": 266,
          "ref": "take.py:266",
          "resolved": false
        },
        {
          "field": "evidence",
          "file": "story_gate.py",
          "line": 34,
          "ref": "story_gate.py:34",
          "resolved": false
        },
        {
          "field": "evidence",
          "file": "DIRECTOR_NOTES_PLAYBOOK.md",
          "line": 20,
          "ref": "DIRECTOR_NOTES_PLAYBOOK.md:20",
          "resolved": false
        },
        {
          "field": "evidence",
          "file": "take.py",
          "line": 288,
          "ref": "take.py:288",
          "resolved": false
        }
      ],
      "shape": "diamond",
      "source_index": 49,
      "status": "live",
      "swimlane": "infra"
    },
    {
      "gate": {
        "pass_condition": "fail-CLOSED: only explicit VERDICT: READY/CONVERGED + deterministic gate guards mark green",
        "validator": "codex spec-review gate (:719) + dispatch-audit gate (:682) + per-phase validation + end-of-build convergence (:1747)"
      },
      "id": "dispatch_chassis_orchestrator",
      "inputs": [
        {
          "artifact": "BUILD_SPEC.md (phases, validation gates)",
          "from": "external"
        }
      ],
      "is_deprecated": false,
      "is_human_review": false,
      "is_substrate": false,
      "label": "Self-healing overnight build chassis — harness_orchestrator.sh",
      "loops": [
        {
          "kind": "reroll",
          "note": "per-phase retry up to MAX_RETRIES=3, escalating codex->claude at attempt>=2; IN_PROGRESS phases re-validated/resumed on crash",
          "to": "dispatch_chassis_orchestrator"
        }
      ],
      "node_type": "decision",
      "produces": [
        "per-phase commits",
        "build-log-*.md",
        "pushed branch + auto-PR + optional auto-merge"
      ],
      "provenance": [
        {
          "field": "evidence",
          "file": "harness_orchestrator.sh",
          "line": 1,
          "ref": "harness_orchestrator.sh:1",
          "resolved": false
        }
      ],
      "shape": "hex",
      "source_index": 50,
      "status": "live",
      "swimlane": "infra"
    },
    {
      "gate": {
        "pass_condition": "codex_rounds_used < max(18); wall_clock < 21600s; concurrent_runs < 4",
        "validator": "budget-check (dispatch_status.py; harness :1026)"
      },
      "id": "dispatch_status_ledger",
      "inputs": [
        {
          "artifact": "run_dir, attempt, phase, budget rounds",
          "from": "dispatch_chassis_orchestrator"
        }
      ],
      "is_deprecated": false,
      "is_human_review": false,
      "is_substrate": false,
      "label": "status.json SSOT + round/budget ledger",
      "loops": [],
      "node_type": "store",
      "produces": [
        "status.json (locked atomic)",
        "terminal_status.json per attempt",
        "heartbeat.json",
        "failure_signature"
      ],
      "provenance": [
        {
          "field": "evidence",
          "file": "dispatch_status.py",
          "line": 1,
          "ref": "dispatch_status.py:1",
          "resolved": false
        }
      ],
      "shape": "cylinder",
      "source_index": 51,
      "status": "live",
      "swimlane": "infra"
    },
    {
      "gate": {
        "pass_condition": "PID dead OR lease expired beyond TTL",
        "validator": "_pid_is_dead + lease TTL check (reaper.py)"
      },
      "id": "dispatch_reaper",
      "inputs": [
        {
          "artifact": "claim_ledger + lease state + worktree TTL",
          "from": "session_workspace"
        }
      ],
      "is_deprecated": false,
      "is_human_review": false,
      "is_substrate": false,
      "label": "Reaper — reclaim stranded claims + stale worktrees",
      "loops": [],
      "node_type": "decision",
      "produces": [
        "reclaimed claims (reaper:stranded)",
        "removed stale worktrees"
      ],
      "provenance": [
        {
          "field": "evidence",
          "file": "reaper.py",
          "line": 1,
          "ref": "reaper.py:1",
          "resolved": false
        }
      ],
      "shape": "hex",
      "source_index": 52,
      "status": "live",
      "swimlane": "infra"
    },
    {
      "gate": {
        "pass_condition": "branch push to origin succeeds (atomic cross-host claim); origin-unreachable fails CLOSED",
        "validator": "assert_owned (paths under SESSIONS_ROOT) + origin-reachable lease push"
      },
      "id": "session_workspace",
      "inputs": [
        {
          "artifact": "actor + issue REC-NN + slug",
          "from": "external"
        }
      ],
      "is_deprecated": false,
      "is_human_review": false,
      "is_substrate": false,
      "label": "session_workspace.sh — per-session worktree + lease (push-to-claim)",
      "loops": [],
      "node_type": "store",
      "produces": [
        "external worktree (~/Code/recoil-sessions)",
        "branch-on-origin lease (CAS claim)",
        "PR handoff metadata"
      ],
      "provenance": [
        {
          "field": "evidence",
          "file": "session_workspace.sh",
          "line": 1,
          "ref": "session_workspace.sh:1",
          "resolved": false
        }
      ],
      "shape": "cylinder",
      "source_index": 53,
      "status": "live",
      "swimlane": "infra"
    }
  ],
  "version": 1
}
