# Reference resolution — FULL map. Expands the ref_resolution seed (ref_system_split
# divergence stays in ref_resolution.topo.yaml; this file ADDS the per-kind routes +
# composite-sheet plumbing + the canonical/legacy resolver split).
#
# THE landscape (all grounded against this worktree's live source):
#   board surface  → board_builder._collect_board_refs → per-kind INDIVIDUAL refs:
#       char  : resolve_character_bundle (phase = wardrobe_phase_id) — turn-views
#       loc   : _append_sublocation_ref → composite SHEET (resolve_sheet_asset) when locked + use_composite_sheets on (C3), else sublocation_registry.sublocation_ref (plate)
#       prop  : _append_prop_refs → _prop_identity_ref (pool/identity/*.png)
#       wardrobe: NOT a resolver — a `phase` threaded into the char bundle
#   video surface  → dispatch_payload._collect_reference_images:
#       composite SHEET path (gated by use_composite_sheets) OR two-pass angle path
#
# LIVE-CODE SURPRISE: the manifest names resolve_reference_bundle as canonical_target
# and lists resolve_location_refs among deprecated_paths, but BOTH production surfaces
# call the deprecated/legacy resolvers. resolve_character_bundle wraps the canonical
# resolve_reference_bundle; resolve_location_refs is a thin back-compat wrapper over
# resolve_entity_refs → _resolve_legacy_flat_refs and is the LIVE video-location path.
# This is the ref_resolution capability state=transitioning made concrete.
subsystem: ref_resolution_full

# ref_resolution capability declared once in _capabilities.topo.yaml (FK seed);
# this file expands its routes/symbols/artifacts only.

entrypoints:
  - id: collect_board_refs
    file: recoil/pipeline/_lib/board_builder.py
    symbol: _collect_board_refs
    invoke: "from recoil.pipeline._lib.board_builder import _collect_board_refs"
    kind: module
    summary: "Board surface ref collector — char refs per-kind INDIVIDUAL (char bundle turn-views); prop refs individual prop-identity for NON-worn props (a WORN prop, bible attached_to a char in the shot, renders as PROSE on the carrier with NO standalone ref — REC-213 C4); the LOCATION ref is the composite SHEET (resolve_sheet_asset) when locked + use_composite_sheets on (REC-213 C3), else the sublocation plate."
    capabilities: [ref_resolution]
    produces: [board_ref_layout]
    reduced_tier: always
    risk_level: high

  - id: collect_reference_images_entry
    file: recoil/pipeline/_lib/dispatch_payload.py
    symbol: _collect_reference_images
    invoke: "from recoil.pipeline._lib.dispatch_payload import _collect_reference_images"
    kind: module
    summary: "Video/r2v surface ref collector. Tries composite sheets first (when enabled), else two-pass angle collection capped at 9 refs. Emits ref_manifest position map."
    capabilities: [ref_resolution]
    produces: [video_ref_manifest]
    reduced_tier: always
    risk_level: high

routes:
  # ── BOARD surface: four per-kind individual routes ───────────────
  - id: board_char_route
    capability: ref_resolution
    surface: board
    entry: recoil/pipeline/_lib/board_builder.py::_collect_board_refs
    resolves_via: recoil/core/ref_resolver.py::resolve_character_bundle
    ref_kind: turn_view           # hero + fullbody + up to 3 turn-views, capped at 6 assets
    gated_by: null
    fallback_route: null
    risk_level: high

  - id: board_wardrobe_route
    capability: ref_resolution
    surface: board
    entry: recoil/pipeline/_lib/board_builder.py::_phase_for_char
    resolves_via: recoil/core/ref_resolver.py::resolve_reference_bundle
    ref_kind: individual          # wardrobe = a phase (wardrobe_phase_id) threaded into the char bundle, NOT a separate resolver
    gated_by: null
    fallback_route: board_char_route   # no phase / phase miss → falls back to phase=None legacy refs inside resolve_reference_bundle
    risk_level: medium

  - id: board_location_sheet_route
    capability: ref_resolution
    surface: board
    entry: recoil/pipeline/_lib/board_builder.py::_append_sublocation_ref
    resolves_via: recoil/core/ref_resolver.py::resolve_sheet_asset
    ref_kind: composite_sheet     # locked board + flag on → the location composite SHEET (same route as video, REC-213 C3)
    gated_by: use_composite_sheets
    fallback_route: board_location_route   # not-locked / flag-off / no-sheet → individual sublocation plate
    risk_level: high

  - id: board_location_route
    capability: ref_resolution
    surface: board
    entry: recoil/pipeline/_lib/board_builder.py::_append_sublocation_ref
    resolves_via: recoil/pipeline/_lib/sublocation_registry.py::sublocation_ref
    ref_kind: plate               # named sublocation plate via location registry (the C3 fallback)
    gated_by: null
    fallback_route: null
    risk_level: high

  - id: board_prop_route
    capability: ref_resolution
    surface: board
    entry: recoil/pipeline/_lib/board_builder.py::_append_prop_refs
    resolves_via: recoil/pipeline/_lib/board_builder.py::_prop_identity_ref
    ref_kind: individual          # first pool/{prop}/identity/*.png — local glob, NOT the core resolver
    gated_by: null
    fallback_route: null
    risk_level: high

  # ── VIDEO surface: composite-sheet vs two-pass angle fork ────────
  - id: video_sheet_route
    capability: ref_resolution
    surface: video
    entry: recoil/pipeline/_lib/dispatch_payload.py::_collect_reference_images
    resolves_via: recoil/core/ref_resolver.py::resolve_sheet_asset
    ref_kind: composite_sheet     # one multi-angle sheet per char + one per location (Seedance/Kling lock)
    gated_by: use_composite_sheets
    fallback_route: video_twopass_route   # disabled OR any required sheet missing → angle path
    risk_level: critical

  - id: video_twopass_route
    capability: ref_resolution
    surface: video
    entry: recoil/pipeline/_lib/dispatch_payload.py::_collect_reference_images
    resolves_via: recoil/core/ref_resolver.py::resolve_character_bundle
    ref_kind: individual          # Pass1 heroes + location, Pass2 back-fills angles; 9-ref cap
    gated_by: null
    fallback_route: null
    risk_level: high

  - id: video_location_route
    capability: ref_resolution
    surface: video
    entry: recoil/pipeline/_lib/dispatch_payload.py::_collect_reference_images
    resolves_via: recoil/core/ref_resolver.py::resolve_location_refs
    ref_kind: individual          # LIVE video-location resolver — a manifest deprecated_path, still wired
    gated_by: null
    fallback_route: null
    risk_level: critical

# use_composite_sheets flag declared once in dispatch_payload.topo.yaml (canonical home);
# video_sheet_route below is gated_by it.

artifacts:
  - id: composite_sheet_v1
    path: "char=assets/char/<id>/base/sheets/sheet_v1.png | loc=assets/loc/<id>/sheets/sheet_v1.png | prop=assets/prop/<id>/sheet_v1.png"
    written_by: [generate_composite_sheet_cli]
    read_by: [video_sheet_route, board_location_sheet_route, render_board_finish]   # video (C1+C2) + locked board (C3) + the board's photoreal finish re-reading the sheet from the sidecar
    schema: "single multi-angle composite PNG per entity; ProjectPaths.sheet_path resolves the canonical location PER KIND (char has base/sheets/, loc has sheets/ (no base/), prop has sheet_v1.png at the subject root); resolve_sheet_asset loud-fails (SheetIntegrityError) on 1x1/truncated clobber"
    reduced_tier: always
    risk_level: high

  - id: board_ref_layout
    path: "in-memory ref_layout dict → board generation sidecar (sublocation_refs / sublocation_ref / prop entries)"
    written_by: [collect_board_refs]
    read_by: [collect_reference_images_entry]   # board_gated/board_ref_path bridge into video collection
    schema: "ordered refs[] + ref_layout index map; sidecar persists sublocation_refs + shared_ref for board→video reuse"
    reduced_tier: auto
    risk_level: medium

  - id: video_ref_manifest
    path: "in-memory {logical_key: 1-based ImageN index} returned to prompt builders"
    written_by: [collect_reference_images_entry]
    read_by: []   # consumed by prompt builders (out of subsystem) to resolve @Image{identity_N}
    schema: "{identity_N: pos, scene_1: pos}; sheet path mirrors angle path so @Image{identity_1} → @Image1 in both routes"
    reduced_tier: auto
    risk_level: high

symbols:
  - id: resolve_reference_bundle
    file: recoil/core/ref_resolver.py
    symbol: resolve_reference_bundle
    role: "THE canonical resolver (manifest canonical_target). Precedence shelf→pool→legacy-flat; returns a ReferenceBundle. Only reached on the char path (via resolve_character_bundle); video-location + board-prop + board-loc bypass it."
    reduced_tier: always
    risk_level: critical

  - id: resolve_character_bundle
    file: recoil/core/ref_resolver.py
    symbol: resolve_character_bundle
    role: "Char-only wrapper over the canonical resolver: hero + fullbody + ≤3 turn-views, capped at 6 assets. The ONE shared resolver across board AND video char routes (the convergence point REC-213=C would unify location/prop onto)."
    reduced_tier: always
    risk_level: high

  - id: resolve_entity_refs
    file: recoil/core/ref_resolver.py
    symbol: resolve_entity_refs
    role: "manifest `canonical` symbol — but it is just _resolve_legacy_flat_refs; resolve_character_refs / resolve_location_refs / resolve_prop_refs are thin wrappers over it. Three of four manifest deprecated_paths collapse to this one legacy function."
    reduced_tier: always
    risk_level: high

  - id: reference_bundle_type
    file: recoil/core/ref_types.py
    symbol: ReferenceBundle
    role: "The role-tagged ordered ref container (RefAsset: role/subject/kind/is_hero/view/source). by_role/hero_subjects/view_path projections. The target type any consolidation onto one resolver must emit for all kinds."
    reduced_tier: auto
    risk_level: medium

  - id: sheet_path
    file: recoil/core/paths.py
    symbol: sheet_path
    role: "The single per-kind composite-sheet LAYOUT home (char base/sheets/, loc sheets/, prop subject-root). Reader (ref_resolver.resolve_sheet_asset) and writer (generate_composite_sheet._sheet_dest) both call it, so they cannot drift (REC-213 C1+C2)."
    reduced_tier: auto
    risk_level: medium
