# Engine-side hierarchy enumeration — the correct long-term fix

Phase 3 of the Console v2 fix ships HIERARCHY SYNTHESIS as the minimal unblock: `Project.episodes` is populated per-request from `set(shot["episode_id"])`, one synthetic Scene is emitted per Episode (id `<episode_id>__synthetic_scene_1`), every synthesis fires a registered fallback (`episodes_synthesized_from_shot_index`, `scenes_synthesized_one_per_episode`), and every synthesized node carries `synthesized: true` so callers and reviewers can tell placeholder from first-class. The frontend HierarchyNavigator gets a real tree it can walk; PHASE_18_SMOKE Item 2 unblocks; Law 4 is honored because the silent recovery is named, registered, and visible in the events drawer.

This is the MINIMAL fix. The CORRECT long-term fix is engine-side enumeration: `scene_id` becomes a first-class field on shot JSON files, `Project.episodes` and `Episode.scenes` become first-class engine projections read from disk rather than synthesized at request time, and the synthesizing fallbacks retire. ADR-0011 is the supersede record for the rescope; THIS file is the deferral record for the long-term fix.

Three structural reasons the long-term fix is not part of this build:

1. **Requires an engine-side migration tool.** Existing shot JSON files across every project (tartarus, the-afterimage, leviathan, the-hike, olympus, singularity, plus the `_archive/` shows) need `scene_id` backfilled. The mapping is non-trivial: scene boundaries today are inferred from script structure (treatment.md scene headings) plus pipeline annotations (plan-pass output). The migration tool needs to read both, reconcile differences, and emit a per-project audit log of "here's what we believe the scene boundaries are; sign off before we backfill." That's a focused CP unto itself.

2. **Requires coordinating with the script-doctor / breakdown pipeline.** `scene_id` would become an authoring-time concept — when the breakdown pass produces shots, it would now stamp `scene_id` per shot. That changes the breakdown's contract with downstream stages. The script-doctor (which can renumber scenes during fixes) needs to learn how to emit `scene_id` migrations alongside its annotations. Both already-shipped substrates need amendments; both have their own validation gates.

3. **Blocks on a small spec for what scenes-as-first-class entities mean for the engine's authoring workflow.** Today JT thinks in beats and shots; scenes are an editorial layer surfaced for the console's hierarchy navigator. Promoting scenes to first-class engine entities raises questions the spec must answer: can a beat belong to multiple scenes? Does retiming a beat propagate to the scene's duration? Is scene one-to-one with a treatment.md heading or can it span? When a /script-doctor fix renumbers scenes mid-episode, what happens to all the in-flight workspace state that referenced old scene ids? These aren't engineering questions — they're product questions that need JT's input before a CP can land.

When the CP lands:

- The two synthesis fallbacks (`episodes_synthesized_from_shot_index`, `scenes_synthesized_one_per_episode`) are retired from the registry — they STOP firing because the underlying data is now first-class.
- `Episode.synthesized` and `Scene.synthesized` schema fields stay on the wire (codegen-propagated to TS), but `synthesized: true` becomes a never-seen value in production. The fields can deprecate in a future schema bump.
- The two routes added in P3 (`/api/projects/{pid}/episodes/...` and `/api/projects/{pid}/episodes/{eid}/scenes`) keep their shape; only the implementation changes from synthesis to disk-walk.
- The frontend HierarchyNavigator does not change at all. It already walks a real tree today; the tree just has different provenance.

Cited: console-v2-audit-2026-05-04 Cluster 1B. ADR-0011 (the supersede record for Phase 16's silent rescope). The minimal fix in P3 IS quality-neutral and law-compliant; this file is not a debt-ledger entry, it's a roadmap entry.
