# Visual Reliability Routing Map — design boundary spec

**Date**: 2026-05-14
**Status**: routing boundary spec (구현 spec 이 아님)
**Scope**: 9 visual reliability case 의 책임 경계 + cross-cutting principle + 4 future area boundary + 1 first implementation candidate

---

## 1. Purpose

본 문서는 **routing boundary spec** 이지 **구현 spec 이 아니다**.

목적:
1. 9 visual reliability case 의 현재 SOT / ref path / gap 매핑을 한 곳에 고정.
2. cross-cutting principle 3가지 (특히 cross-shot reference arbitration 부재) 의 정확한 표현 기록.
3. 절대 하지 말 것 5가지 명시 (구현 위험 패턴).
4. 4 future area 의 boundary 분리 + 구현 의존성.
5. 첫 구현 후보 1개만 추천 (구현 결정 X, 별도 spec/plan 으로 위임).
6. plausible / unverified 항목의 verification backlog 명시.

**다음 spec/plan/code 작성 시 본 문서를 기준선으로 사용한다.** plausible / unverified 등급은 다음 세션에서 확정 결함으로 취급 금지.

---

## 2. 9 case Routing Table

각 case 의 column:
- **current SOT** — producer schema field / consumer validator (file:line)
- **ref path** — image reference 또는 prompt-only
- **status** — closed / partial / open / closed (offline)
- **confirmed gap** — 코드/프롬프트 근거 확보된 결함
- **plausible gap** — 가설 (case review / census 필요)
- **unverified** — 별도 audit 또는 production 측정 필요

### Case 1: 캐릭터 자세 일관성

| | |
|---|---|
| current SOT | `shot_staging.character_angles[].body_pose` NL (2-5 words) + `gaze_target` NL with `{dead, unconscious, severely_injured}` 특수 keyword + `scene_consistency.fixed_elements[].element_type == "character_state"` enum + `applies_to_shots minItems: 2` |
| ref path | `character_state_variant` ref (`image_steps.py:635-700`, 3종만) + `composite:char:outlook` + character base ref + scene_consistency `character_state` element (text only, no image) |
| status | **partial** — lifeless 3-state lock 강함, active pose lock NL-only |
| confirmed gap | state-variant ref 의 scope = `IMMOBILIZED_GAZE = frozenset({"dead", "unconscious", "severely_injured"})` (`semantic_contract_router.py:22`) 만. body_pose 는 prompt-only NL, cross-shot enforcement schema field 부재. |
| plausible gap | "active 정지 자세" (sitting on chair, holding object) 의 cross-shot continuity 가 prompt-only on `scene_consistency.character_state` element_type. LLM emission accuracy 의존. asleep / cryosleep / fainted / restrained 등 living immobility state ([[session_20260511_patch_b_spec_plan]] §17 carry) cover 없음. |
| unverified | T2I prompt-following 결함 path (S11/14 1차 canary 의 "kneeling looking at blood pool" 살아있는 자세 PNG → sanitize 미발동 — defense scope 밖 결함이지만 case 1 영역에 영향). |
| defer area | `area-character-pose-state-reference` |

### Case 2: 탈것/큰 prop 일관성

| | |
|---|---|
| current SOT | `EntityCanon.metadata_json.visual_identity.reference_required: bool` (entity_extractor v2 LLM emit) + `render_contracts[]` (`render_prompt_card.py:1809-1894`, dimension=`visual_identity`, operation=`preserve`, strength=`required`) + `required_refs (kind="prop")` derive (`render_prompt_card.py:2008-2077`) + `validate_visible_entities_contract` PRO-13 word-boundary check + `validate_attached_refs` Tier 3 |
| ref path | prop ref (visual_identity.reference_required=true 만, scope=`single_shot`) |
| status | **partial** — visual_identity dimension only, single_shot scope |
| confirmed gap | render_contracts 의 `scope.duration: "single_shot"`, `scope.shot_indices`: single int (`render_prompt_card.py:1881`). cross-shot vehicle 위치/상태/orientation continuity 부재. |
| plausible gap | prop identity ref 와 background-owned object 의 **역할 충돌 가능성**. namespace 는 다름 (`owned_objects` = common noun NL list / `required_refs` = entity ID). 그러나 같은 entity 가 두 channel 에 등록되는 case 있을 수 있음. `entity_canon × owned_objects × required_refs` 교차 census 필요. |
| unverified | Rule D (`scene_detail/23.../system.md:399-421`) 의 list 가 `vehicle / bicycle / motorcycle / boat / cart / wheelchair` 6 token. **동물 탈것 (말 / 낙타 / 코끼리)** 누락 가능성 — image-level validation coverage unknown / likely incomplete, audit 필요. Patch D S28/3 boat 결함 (entity 외관 부재) carry. |
| defer area | `area-large-prop-vehicle-identity` (Patch D S28/3 흡수) |

### Case 3: 가구/장치 일관성

| | |
|---|---|
| current SOT | `entity_canon.metadata_json.location.space_profile` (D6 SOT) + `bg_state_vocab.STATE_CLASS_ENUM` 11 + `bg_catalog.assign_bg_ids` semantic_key dedup + `background_prompt.objects_owned_by_background` NL list + `background_binding.{mode, bg_id, owned_objects, camera_reference}` 4-mode (`render_prompt_card.py:1331-1469`) + `scene_consistency.fixed_elements[].element_type == "persistent_prop"` + `keep_elements` (kind ∈ `{environment, static_prop}`, D-next-min closure) + `scene_detail_owned_judge` post-validation (`redraw_violation` vs `anchor_reference`) |
| ref path | chain_bg PNG (4-layer chain: floor_plan_render → background_render → scene_consistency) + prev_shot ref (`ref_usage=exact_background` + `keep_elements`) |
| status | **partial** — chain_bg PNG visual 일관 + owned NL list. screen 좌표 lock 부재 |
| confirmed gap | `owned_objects` 가 NL string list (`render_prompt_card.py:1437`). 가구의 screen 좌표 (어디 놓여있는지) hard structured field 없음 — chain_bg PNG painted layout 의 implicit 의존. |
| plausible gap | 가구 state 변화 (`busy / ransacked / blood_scene / clean_after` 같은 STATE_CLASS_ENUM 11 변종) 의 cross-shot enforcement 가 scene_consistency.persistent_prop LLM emission 의존. 같은 floor_plan 1개가 multiple state 의 background 를 cover. |
| unverified | 새로 추가된 가구의 처리 (prop entity 승격 vs background owned 결정 기준). 인물이 가구 일부 가리는 partial occlusion 처리 (prompt-side prose only). |
| defer area | cross-shot anchor placement (cross-cutting arbitration 의 subset, 별도 area 명명 없음) |

### Case 4: 문서/휴대폰/사진/액자/지도 앞뒤

| | |
|---|---|
| current SOT | `shot_staging.key_bg_elements[].directionality_class` 5-enum (`content_surface, reflective_surface, transparent_surface, directional_3d, non_directional`, schema strict) + `orientation` NL field (content_surface / reflective_surface 의 경우 빈 값 금지) + `ORIENTATION_REQUIRED_CLASSES` validator + retry max_attempts=3 + `reproduction_surface_rule.applies: bool` derive (`render_prompt_card.py:1170-1190`) + `_forward_enforcement_exempt` (`visible_entities_validator.py:232-279`) + `_MISSING` sentinel 4-branch |
| ref path | prop ref (P## 보존 — Patch A NOTE clause `render_prompt_card.py:1246-1255`) + chain_bg PNG (표면이 painted 인 경우) |
| status | **partial** — binary (applies bool), front/back 자체 hard contract 부재 |
| confirmed gap | `orientation` NL string (shot_staging schema.json:38). front/back 의 enum 강제 없음. `directionality_class` 가 surface 종류만 결정, surface_facing (어느 면 보이는지) 의 별도 enum 부재. |
| plausible gap | 양면 의미 prop (지도 / 종이 펴서 양면 보임) 의 cover. 한 prop 의 display surface (화면) 와 case (뒷면) 가 같은 shot 에서 동시 보일 때 처리 부재. |
| unverified | 표면 안 face ≠ entity face (작품 외부 인물 사진) 의 image-level catch rate — `id_policy.constraints[1]` prose only. |
| defer area | `area-information-surface` |

### Case 5: 공간/문/이동 방향

| | |
|---|---|
| current SOT | `shot_staging.frame_spatial_contract` (opt-in, oneOf null/object): `reason` enum 6 (`movement_direction / points_to_anchor / looks_to_anchor / shared_space_relation / required_background_position / primary_subject_isolation`) + `constraints[]` (maxItems: 3) — `target_kind` (character/prop/background) + `target_id` + `label` + `screen_zone` 9-grid + `depth_plane` 3-zone + `gesture_action` 5-enum + `gesture_target_label` NL. code-assigned `constraint_id: "fsc_NNN"` (deterministic 7-tuple sort). echo MUST in `scene_detail.t2i_variations[].applied_frame_spatial_constraint_ids` (schema required). 1 retry + `_NON_RETRYABLE_CODES` outer retry filter. `scene_camera_flow.flow_stages[]` (scene-wide camera path NL). `shot_staging.camera_direction` NL. `detect_offscreen_drift` (regex preflight). |
| ref path | prompt-only (frame_spatial_contract 는 constraint metadata, no ref attach) |
| status | **producer/consumer contract closed (offline), image-level validation open** |
| confirmed gap | image-level validation 부재 — 생성된 이미지가 실제로 화면 좌표를 지켰는지 LVM 검증 안 됨. production canary visual 검증 미실행 (closure 직후 push). |
| plausible gap | scene 간 spatial continuity carry — `scene_camera_flow` 는 single-scene only. 같은 location 의 multiple scene 사이 camera angle / movement direction 의 cross-scene SOT 부재. 1 reason per shot 한계 (`reason` 은 single str, multi-aspect compromise). |
| unverified | image-level validation coverage. `t2i_review` / `shot_validator` 의 spatial constraint 시각 검증 강도 — likely incomplete, audit 필요. |
| defer area | image-level validation (cross-cutting arbitration 의 subset, 별도 area 명명 없음) |

### Case 6: 얼굴/표면 displacement

| | |
|---|---|
| current SOT | `id_policy.body_part_focus_rule.trigger_phrases` + `_FACE_CLOSE_UP_PATTERNS` regex (`visible_entities_validator.py:139-145`) + `reproduction_surface_rule.applies` bool + `id_policy.constraints[1]` (surface 안 face common noun) + `shot_staging.perception_mode` (string, no enum) + `prompt_sanitizer` 2-layer SEMANTIC OVERRIDE + `semantic_contract_router` (`pose_locked / immobilized` mode) + `t2i_review` post-validation (일부) |
| ref path | composite ref (face+outlook 정합) + character base ref |
| status | **partial** — prompt-side defense 강함, post-image validation 약함 |
| confirmed gap | `shot_staging.perception_mode` schema 가 `{"type": "string"}` only (shot_staging schema.json:13). enum 강제 없음. `shot_staging system.md:34-41` 의 7 token (`direct / hallucination / dream / memory / reflection / through_device / projection`) vs `scene_detail/23.../system.md:61` 의 4 token (`mirror / reflection / through_device / projection`) **불일치** — `shot_staging` 에 `hallucination/dream/memory` 추가, `scene_detail` 에 `mirror` 추가 (shot_staging 은 `reflection` 만). |
| plausible gap | 그림자 안 다른 인물 displacement (sub-case). 거울 안 다른 인물 reflection (perception_mode=`reflection` 이 해당 shot 의 전체 reflection 만 cover). 표면 안 multiple 인물 또는 표면 일부만 보일 때 처리. |
| unverified | post-image LVM coverage / `t2i_review` 의 face displacement specific catch rate — likely incomplete, audit 필요. |
| defer area | `area-id-policy-framing-extension` (Case 7과 공유) |

### Case 7: close-up 인물 추가 (close-up subject isolation)

| | |
|---|---|
| current SOT | `shot_director._resolve_scene_llm` frame-visible SOT (`shot_director.py:55-201`, 2026-05-13 unification, missing-shot fail-fast `AppError("shot_director.llm_missed_shots")`) + `detect_gaze_pattern_exclusions` deterministic exclusion (`shot_visibility.py:236-302`, Korean gaze-verb patterns) + `frame_spatial_contract.reason="primary_subject_isolation"` (opt-in) + `primary_framing_rule.close_framing_rules` (prose: `primary_subject_only_fully_visible`, `same_character_full_and_close_forbidden`, `two_characters_sharp_faces_forbidden`) + `body_part_focus_rule` close-up triggers (close-up C##O## 금지) |
| ref path | prev_shot ref (`ref_usage` 별 — zoom_in_detail / exact_background / atmosphere_reference / fallback) |
| status | **partial** — opt-in 종속 + close × ref_usage 매트릭스 routing 부재 |
| confirmed gap | close framing 시 chain_bg 는 skip 되지만 `prev_shot_ref` 는 `ref_usage` 무관 attach 유지 (`scene_generation_coordinator.py:346, 379`). `ref_usage=zoom_in_detail` 은 정의상 close-up 정상 케이스 (`shot_dependency_t2i/7.../system.md:24-26`, 같은 시공간 카메라 확대만). 나머지 ref_usage 는 close-up 시 다른 인물 침입 위험. **close × ref_usage 4-way 매트릭스 결정 부재 = 본 spec 의 First Implementation Candidate**. |
| plausible gap | `primary_framing_rule` prose only, enum gate 없음. "close framing 시 visible_entities count ≤ 1" 자동 검증 부재. `partial_focus` mode escape hatch (`visible_entities_validator.py:200-204`) 의 부적절한 사용 catch 없음. |
| unverified | `shot_director` LLM frame-visible emit 의 production 정확도 (PID 02829fe8 ep1 28/28 PASS 외 다른 PID 측정 미진행). |
| defer area | `area-id-policy-framing-extension` (Case 6과 공유) |

### Case 8: 몸 형태/앉음/잘림

| | |
|---|---|
| current SOT | `shot_staging.character_angles[].body_pose` NL (2-5 words, "standing alone 금지") + `angle` enum 8 (`facing_camera, back_to_camera, profile_left, profile_right, three_quarter_left, three_quarter_right, over_shoulder, looking_away`) + `_derive_framing_scale` 코드 derivation (close/medium/insert) + `camera_frame_rule.core_principles` 4 sub-rule (geometric) + `primary_framing_rule.wide_medium_rules.body_part_close_up_forbidden` + `scene_consistency._detect_framing_conflicts` (cross-shot, same scene) + Rule B (조명·색조 신체 변형 금지) + silhouette policy (평면 cutout 금지) + 옷 묘사 MUST + `t2i_review` physical_inconsistency post-validation |
| ref path | composite ref (전신, framing 무관 — model 이 framing 으로 crop) + character base ref |
| status | **open** — body_pose hard contract 부재, NL only |
| confirmed gap | `body_pose` schema description "2-5 words" 제한, 정확한 자세 enum 부재 (shot_staging schema.json:24). cross-shot body_pose continuity 부재 (single-shot only). |
| plausible gap | 앉음 자세 sub-case (의자에 앉은 인물의 정확한 다리/허리 위치). camera_frame_rule.core_principles 4 sub-rule 이 typical case 만 cover. 비대칭 / 옆에서 본 / 사선 카메라 케이스 부족. |
| unverified | `t2i_review` physical_inconsistency 의 실제 catch rate. |
| defer area | (명시적 area 카탈로그 외 — case 1 의 pose 영역과 일부 overlap 가능) |

### Case 9: 배경 가구-인물 mismatch (fg/bg shared anchor)

| | |
|---|---|
| current SOT | `frame_spatial_contract.reason="shared_space_relation"` (opt-in) + `fg_bg_shared_anchor_rule` (`render_prompt_card.py:689-729`, 6 keys, prose only — applies_when / shared_anchor_required / forbidden_phrasings / recommended_keywords / self_check_steps / rationale_summary) + `background_binding.camera_reference: {camera_position, camera_height, lens_hint, framing_notes}` + `primary_framing_rule.wide_medium_rules` (fg/bg 분리 시 fg_bg_shared_anchor_rule 동시 적용) + `t2i_review` `unshared_fg_bg_actors` post-validation (`t2i_review/3.../scene_system.md:65-78`) |
| ref path | chain_bg PNG (anchor 가구 painted) + prev_shot ref (`ref_usage=exact_background` + anchor in `keep_elements`) |
| status | **partial** — opt-in 종속, anchor 키워드 5 token list 한정 |
| confirmed gap | `fg_bg_shared_anchor_rule` 가 enum gate 없는 prose only. `recommended_keywords` 5 token (`shared bench`, `the same X they both occupy`, `across the X from each other`, `<prop> crosses the air between them`, `single line of sight`) 한정. emit 안 한 medium/wide shot 에서 enforce 약함. |
| plausible gap | 가구 자체의 screen 좌표 lock 부재. `frame_spatial_contract.target_kind=background` (`target_id=""` 만) cover, specific 가구 ID 결합 X. `gesture_target_label` NL 이라 P##/L## ID 와 결합 안 됨. cross-shot 같은 angle 의 `camera_reference` 일관성 부재 (각 shot 의 background_binding 독립). |
| unverified | `t2i_review` `unshared_fg_bg_actors` 의 실제 catch rate. 인물-prop 의 shared anchor 누락 검출 (현재 두 인물 분리만 검출). |
| defer area | (cross-cutting arbitration 일부 cover, 명시적 area 없음) |

---

## 3. Cross-Cutting Findings

세 가지 cross-cutting principle. 본 spec 의 의미를 결정하는 정확한 표현으로 기록한다.

### 3.1 cross-shot reference routing / object-anchor placement arbitration gap

**정확한 표현 (확정)**:

> "cross-shot SOT 부재" 가 아니라, **cross-shot reference routing / object-anchor placement arbitration 부재**.

존재하는 building block:
- `ref_usage` 3 enum (`zoom_in_detail / exact_background / atmosphere_reference`) — `shot_dependency_t2i/7.../system.md:24`
- `keep_elements` (`kind ∈ {environment, static_prop}`) — D-next-min closure
- `forward_zoom_targets` — `detail_steps.py:30-95`, reverse-lookup from `dependencies[*].location_refs[0].ref_usage='zoom_in_detail'`
- `background_binding.{mode, bg_id, owned_objects, camera_reference}` 4-mode — `render_prompt_card.py:1331-1469`
- `continuity_elements_used.fixed_elements[]` — scene_consistency carry
- `character_state_variant` ref (`image_steps.py:635-700`, 3종)
- `frame_spatial_contract` (opt-in spatial contract)
- `chain_bg_owned_by_shot` + `chain_bg_camera_meta_by_shot` (per-shot chain bg lineage)

부재한 것 = **"이 shot 에서 어떤 ref path 를 어떤 우선순위로 쓸 것인가" 의 상위 routing 표**:
- 같은 방을 유지해야 한다는 원칙은 building block 으로 있음.
- 이 shot 에서 previous-shot image 를 붙일지, chain_bg 를 쓸지, prompt-only 로 갈지, state-variant ref 도 쓸지의 **결정표 (arbitration)** 가 약함.
- Case 1, 2, 3, 4, 7, 9 의 공통 근본 원인.

### 3.2 frame_spatial_contract is opt-in screen-space contract, not universal router

**정확한 표현 (확정)**:

> `frame_spatial_contract` 는 Case 5 의 직접 cover 도구이지, **전체 visual reliability router 가 아니다**.

특성:
- opt-in (`oneOf [null, object]`, shot_staging schema.json:50-94)
- 1 `reason` per shot (single str enum, not array)
- `constraints[]` maxItems: 3
- `target_kind ∈ {character, prop, background}` + `target_id` (C##/P##/"")
- 9 zone × 3 depth × 5 gesture

한계:
- Case 5 (movement_direction / required_background_position) 직접 cover.
- Case 7 (`primary_subject_isolation`) 부분 cover (1 reason 만 emit, opt-in).
- Case 9 (`shared_space_relation`) 부분 cover (anchor name = `gesture_target_label` NL, P##/L## ID 결합 X).
- 동일 shot 의 multi-aspect (close-up + bg-character anchor + movement) 동시 cover 불가.

**금지**: frame_spatial_contract 를 만능 router 로 확장 (reason 추가 / constraint 늘림 / scope 확장 등) 으로 6 case 를 동시 해결하려는 시도 금지.

### 3.3 previous-shot ref policy needs close × ref_usage matrix

**정확한 표현 (확정)**:

> close framing 시 `chain_bg` 만 skip 되고 `prev_shot_ref` 는 attach 유지 (`scene_generation_coordinator.py:346, 379`). `ref_usage` 분류 별 routing 부재 = Case 7 의 직접 gap.

4-way 분류 (구현 spec 으로 위임):
- **close + zoom_in_detail** = preserve / allowed (정의상 동일 시공간 카메라 확대만, `shot_dependency_t2i/7.../system.md:24-26`)
- **close + exact_background** = risky, policy needed (다른 시점 같은 방 — 다른 인물 인식 위험)
- **close + atmosphere_reference** = likely image attach ban (스타일/조명만 의미, 이미지 첨부 무의미)
- **close + ref_usage 없음 fallback** = risky, likely ban ("ignore people, keep motionless figures" label 만, base 로 위험)

**금지**: previous-shot ref 를 close framing 에서 무조건 차단하는 단순 fix. zoom_in_detail 은 보존 의무.

---

## 4. Do Not Implement Here

본 spec 자체는 구현하지 않는다. 그리고 향후 구현 시 다음 5 패턴 금지:

1. **9 case 동시 구현 금지** — 책임 경계가 흐려진다. 한 area 씩 incremental.
2. **4 future area spec/plan 동시 작성 금지** — scope 폭발. 한 area 의 spec/plan/closure 후 다음.
3. **`frame_spatial_contract` 만능 확장 금지** — opt-in screen-space contract 의 본분 유지. 6 reason / 9 zone / 3 depth / 5 gesture 확장 시 의미 깨짐.
4. **`keep_elements` 에 character 재도입 금지** — D-next-min closure 결정 ([[session_20260515_area_d_next_min_clean_rebuild]]). `kind ∈ {environment, static_prop}` 만. character pose/state 는 scene_consistency / character_state_variant / semantic_contract_router 책임.
5. **previous-shot ref 무조건 금지 금지** — `ref_usage=zoom_in_detail` 은 close-up 의 정상 케이스. 차단 시 cross-shot continuity 깨짐. 4-way 분류 의무.

---

## 5. Future Area Boundaries

각 area 의 책임 범위 + 본 spec 의 confirmed/plausible gap 매핑.

### 5.1 area-character-pose-state-reference

**책임 범위**: Case 1 (캐릭터 자세 일관성).

**다룸**:
- state-variant ref scope 확장 — lifeless 3-state (dead/severely_injured/unconscious) 외 active immobility state (asleep / cryosleep / fainted / restrained 등) 검토 ([[session_20260511_patch_b_spec_plan]] §17 carry).
- `scene_consistency.character_state` element 의 active 정지 자세 (sitting on chair, holding object 등) cover 명시화 (현재 prose 가 "정지 상태" 강조).
- `body_pose` NL 의 cross-shot continuity 보강 결정 (hard enum 도입 vs scene_consistency 의존 강화).

**다루지 않음**:
- close × ref_usage 매트릭스 (별도 first implementation candidate).
- `directionality_class` / `reproduction_surface_rule` (Case 4, 6 영역).

### 5.2 area-large-prop-vehicle-identity

**책임 범위**: Case 2 (탈것/큰 prop 일관성).

**다룸**:
- `visual_identity` dimension 외 추가 dimension 검토 (예: cross-shot vehicle state / orientation).
- Patch D S28/3 boat 결함 흡수 — entity 외관 부재 + L17 SOT contradiction 처리.
- 동물 탈것 (말 / 낙타 / 코끼리) audit — Rule D list 확장 또는 별도 enum 도입.
- `entity_canon × owned_objects × required_refs` 교차 census (cross-cutting verification backlog 의 일부).
- prop ⊥ background-owned routing 결정 (LLM 두 단계 독립 판단 → 결정 메커니즘 명시화).

**다루지 않음**:
- 화면 좌표 lock (Case 3, 9 일부).

### 5.3 area-information-surface

**책임 범위**: Case 4 (문서/휴대폰/사진/액자/지도 앞뒤).

**다룸**:
- `orientation` NL → `surface_facing` enum (front / back / side / edge) 도입 검토.
- `directionality_class` 5-enum 의 surface facing sub-field 또는 `screen_anchors.surface_facing` 신규 field.
- 양면 의미 prop (지도 / 종이 펴서 양면) cover.
- 한 prop 의 display surface + case 동시 보이는 경우 처리.

**다루지 않음**:
- 표면 안 face displacement (Case 6 영역).

### 5.4 area-id-policy-framing-extension

**책임 범위**: Case 6 + Case 7 (face/body in wrong surface + close-up subject isolation).

**다룸**:
- `body_part_focus_rule` hard enum 도입 검토 (현재 trigger_phrases prose).
- `primary_framing_rule.close_framing_rules` enum gate ("close framing → visible_entities count ≤ 1" 자동 검증).
- `shot_staging.perception_mode` schema enum 강제 (7 token vs 4 token 불일치 해소).
- `partial_focus` mode escape hatch 의 적절성 검사.
- 그림자/거울 안 다른 인물 displacement sub-case (verification backlog 와 연계).

**다루지 않음**:
- close × ref_usage 매트릭스 (별도 first implementation candidate, 본 area 의 dependency).

### 5.5 Area 간 의존성

- **First Implementation Candidate (close × ref_usage)** 가 Case 7 의 일부를 해결 — `area-id-policy-framing-extension` 의 prerequisite.
- `area-large-prop-vehicle-identity` ⊥ 다른 3 area (Case 2 만).
- `area-character-pose-state-reference` ⊥ 다른 3 area (Case 1 만).
- `area-information-surface` 는 Case 4 만 — `area-id-policy-framing-extension` 의 `reproduction_surface_rule` 와 일부 SOT 공유 (`directionality_class`). 순서: information-surface 먼저 → id-policy-framing-extension 두 번째 권장.

---

## 6. First Implementation Candidate

**close framing × ref_usage attach policy**.

본 spec 에서 구현 결정 X. Routing Map 승인 후 별도 spec/plan 으로 진입.

**Prerequisite 충족 (2026-05-15)**: framing_scale enum SOT v1 area closure 로 본 §6 area unblocked. shot_staging v11 prompt + schema 의 framing_scale required enum (close/medium/wide/insert) emit + `backend/app/core/framing_scale.py` helper module (`get_framing_scale_or_raise` fail-fast) + 4 consumer (render_prompt_card / scene_generation_coordinator / detail_steps / scene_reference_service) helper read 전환. `scene_reference_service.build_prev_shot_background_ref` 의 ref_usage read 직후 close × ref_usage matrix 도 v1 으로 운영 (`close + ref_usage != "zoom_in_detail"` → RefContractError detail prefix `close_ref_usage_violation:`). spec: `docs/superpowers/specs/2026-05-15-framing-scale-enum-sot-v1-design.md`. plan: `docs/superpowers/plans/2026-05-15-framing-scale-enum-sot-v1-plan.md`. closure: see `session_20260515_framing_scale_enum_sot_v1_closure` memory. 따라서 본 §6 의 4-way 분류 표 (§6.1) 의 `close + zoom_in_detail = preserve / allowed`, 그 외 `close + non-zoom_in_detail = ban via matrix` 가 production 운영. §6.2 의 추가 결정 사항 (validate_attached_refs cascade enforcement / canary case S11/14, S12/4 검증 / bytes source verification — declared ref_usage vs dependent scene 실제 bytes / location-history fallback bytes 구분) 은 본 area scope 외 — 이후 hardening 후보.

### 6.1 4-way 분류

| close × ref_usage | 정책 (초안, 별도 spec 에서 확정) | 근거 |
|---|---|---|
| close + zoom_in_detail | **preserve / allowed** | shot_dependency_t2i/7.../system.md:24-26 — "동일 시공간 · 동일 피사체 · 카메라 확대/이동만". 정의상 close-up 정상. |
| close + exact_background | **risky, policy needed** | "다른 순간 같은 방" — close-up 안 다른 인물 / 다른 자세 침입 가능. attach 차단 또는 strong condition. |
| close + atmosphere_reference | **likely image attach ban** | "스타일/조명/atmosphere only, layout 복제 금지" — image 첨부 의미 약함. label 만 prompt-side carry. |
| close + ref_usage 없음 fallback | **risky, likely ban** | fallback label = "ignore people, keep motionless figures (lifeless)" only. base 로 활용 위험. |

### 6.2 별도 spec 에서 결정할 사항 (본 spec 에서 결정 X)

- 정확한 close framing detection 기준 (현재 `_CLOSE_FRAMING_RE` regex on `camera_direction` NL — 강화 또는 fail-fast 검토).
- `ref_usage` 별 attach 결정 위치 (`scene_generation_coordinator.build_scene_attached_refs` 의 5a/5b/5c/5d 분기 확장).
- 차단 시 attach_meta 의 silent skip vs typed error.
- `validate_attached_refs` 의 close × ref_usage 매트릭스 enforcement 추가.
- canary case (S11/14, S12/4 등) 으로 검증.

### 6.3 본 후보의 본 spec 위치

본 first implementation candidate 는 Case 7 (close-up isolation) 의 confirmed gap 직접 해결 + Case 3/9 (가구 / bg-character anchor) 의 ref routing 약점 일부 완화. 그러나:
- `area-id-policy-framing-extension` 의 일부.
- 단독 spec/plan 로 분리해서 incremental 진입 가능.
- 4 future area 중 어느 것보다도 즉각 효과 큰 single fix.

---

## 7. Verification Backlog

본 spec 의 plausible / unverified 항목에 대한 audit 의무. 별도 short audit session 으로 진행. 본 spec 의 결함 등급을 confirmed 로 승급 또는 plausible 로 demote.

### 7.1 post-image LVM / t2i_review / shot_validator coverage audit

**대상**: Case 5 image-level validation closure 확인 + Case 6 face displacement detect 강도 + Case 9 unshared_fg_bg_actors catch rate.

**작업**:
- `t2i_review/3.../scene_system.md` 의 모든 detection rule 추출 + 각 rule 이 cover 하는 case 매핑.
- `shot_validator` (있다면) 의 detection logic 추출.
- production canary (PID 02829fe8 ep1 또는 fresh) 의 t2i_review fail rate / catch case 추적.
- image-level validation 의 cross-shot coverage 측정.

### 7.2 entity_canon × owned_objects × required_refs cross-census

**대상**: Case 2 plausible gap — prop identity ref 와 background-owned object 의 역할 충돌 가능성.

**작업**:
- 모든 EntityCanon prop entity 에 대해 `metadata_json.visual_identity.reference_required: true` set 추출.
- 모든 `background_prompt.objects_owned_by_background` NL list 의 canonical noun set 추출.
- 두 set 의 entity 매핑 (canonical name 기반) — overlap entity 추출.
- overlap case 의 실제 image generation 결과 검증 (prop ref + chain_bg painted 같은 entity 가 어떻게 rendering 되는지).
- 확정 결함 (mutual exclusion 필요) vs 의도된 layered defense 판정.

### 7.3 state_variant × prev_shot fallback overlap case review

**대상**: Case 1 plausible gap — `state_variant` ref + `prev_shot_ref` fallback label "ignore people, keep motionless figures" 의 책임 overlap.

**작업**:
- `scene_reference_service.py:766` (state_variant 인물 remove_hints exclude) 와 `:847` (fallback label motionless keep) 의 실제 동작 case 추출.
- lifeless 3-state 인물이 동시에 prev_shot 에 있는 case 검색.
- 양쪽 layer 가 같은 결과 (보존) 인지 / 충돌하는 결과 (다른 처리) 인지 판정.
- 확정 overlap (redundant defense 정리 필요) vs 의도된 layered defense 판정.

---

## 8. References

### 8.1 Memory

- [[session_20260514_area_frame_spatial_contract_closure]] — Area Frame Spatial Contract closure (Case 5 직접 cover, 본 spec 의 분석 base).
- [[session_20260515_area_d_next_min_clean_rebuild]] — Area D-next-min closure (10-row Visual Routing Matrix + 4-layer architecture, keep_elements environment/static_prop 결정).
- [[session_20260514_area_d_min_required_refs_sot]] — Area D-min closure (render_contracts → required_refs SOT unification, Case 2 visual_identity dim).
- [[session_20260513_shot_director_frame_visible_sot]] — shot_director frame-visible SOT unification (Case 7 frame-visible producer).
- [[session_20260512_area_c_closure]] — Area C closure (reproduction_surface_rule.applies bool, Case 4).
- [[session_20260512_area_a_impl_and_audit_r1]] — Area A directionality_class 5-enum (Case 4).
- [[session_20260513_area_b_render_contracts]] — Area B-min render_contracts top-level field (Case 2 visual_identity).
- [[session_20260512_patch_b_implementation]] — Patch B-min semantic_contract_router + sanitizer (Case 1 lifeless 3-state).
- [[session_20260511_patch_a_implementation]] — Patch A 3-tier defense (Case 2 prop attach).
- [[session_20260510_d6_fp_bg_prompt_complete]] — D6 background SOT chain (Case 3).
- [[feedback_llm_based_judgment]] — 4 gate (open-world LLM-produced SOT 의무).
- [[feedback_subagent_model_opus]] — subagent model=opus 강제.

### 8.2 Code

- `backend/app/core/frame_spatial_contract.py` — Case 5 producer / consumer.
- `backend/app/modules/pipeline/shot_staging.py` — Case 1, 4, 5 producer.
- `backend/app/modules/pipeline/shot_director.py` — Case 7 frame-visible producer.
- `backend/app/modules/pipeline/shot_visibility.py` — Case 7 detect_offscreen_drift.
- `backend/app/modules/semantic_contract_router.py` — Case 1 lifeless 3-state aggregator.
- `backend/app/modules/prompt_sanitizer.py` — Case 1 2-layer SEMANTIC OVERRIDE.
- `backend/app/core/steps/render_prompt_card.py` — central SOT producer (6 builders).
- `backend/app/core/steps/scene_consistency_step.py` — Case 1, 3, 8 (cross-shot).
- `backend/app/core/steps/scene_camera_flow_step.py` — Case 5 scene-wide path.
- `backend/app/core/steps/shot_dependency_t2i_step.py` — ref_usage producer.
- `backend/app/core/steps/image_steps.py` — Case 1 CharacterStateVariantStep.
- `backend/app/core/steps/detail_steps.py` — Case 1, 5, 8 consumer (echo + retry).
- `backend/app/core/visible_entities_validator.py` — Case 2, 6 validator.
- `backend/app/core/scene_reference_service.py` (= `backend/app/services/scene_reference_service.py`) — ref resolver, Case 1/2/3/7 attach.
- `backend/app/services/scene_generation_coordinator.py` — build_scene_attached_refs, Case 7 close × ref_usage 분기.
- `backend/app/core/ref_contract_validator.py` — validate_attached_refs.
- `backend/app/core/entity_metadata.py` — Case 2 visual_identity.reference_required SOT.

### 8.3 Prompts

- `prompts/_base/shot_staging/10.202605141617/` — Case 1 (body_pose), 4 (directionality_class), 5 (frame_spatial_contract), 6 (perception_mode), 7 (frame_spatial_contract.primary_subject_isolation).
- `prompts/_base/scene_detail/23.202605141758/` — Case 4 (reproduction_surface_rule), 5 (echo MUST), 6 (silhouette + Rule B + perception_mode), 7 (close_framing_rules), 8 (camera_frame_rule), 9 (fg_bg_shared_anchor_rule).
- `prompts/_base/scene_consistency/6.202605031033/` — Case 1, 3, 8 cross-shot fixed_elements.
- `prompts/_base/shot_director/5.202605131800/` — Case 7 frame-visible.
- `prompts/_base/shot_dependency_t2i/7.202605151200/` — ref_usage enum.
- `prompts/_base/character_state_variant/1.202604101200/` — Case 1 state-variant ref.
- `prompts/_base/scene_detail_owned_judge/3.202605051746/` — Case 3 redraw post-validation.
- `prompts/_base/t2i_review/3.202605121200/` — Case 5/6/9 post-validation.
- `prompts/_base/scene_camera_flow/1.202604151200/` — Case 5 scene-wide.
- `prompts/_base/background_prompt/6.202605091200/` — Case 3 owned_objects.
- `prompts/_base/visual_world_rules/6.202605021400/` — Case 6 director_notes.

---

## 9. Notes

본 spec 의 결함 등급 의무:
- **confirmed** = 코드/프롬프트 직접 grep + file:line ref. 다음 spec 에서 그대로 인용 가능.
- **plausible** = 가설 (case review / census 필요). verification backlog 항목 수행 후 confirmed 또는 demoted.
- **unverified** = production 측정 또는 별도 audit 필요. 본 spec 의 base 정보로 활용하지 말 것.

본 spec 은 "큰 숲" 의 routing boundary 만 고정. 각 future area 의 detail 은 별도 spec/plan 에서 결정.

본 spec 의 First Implementation Candidate (close × ref_usage) 는 별도 spec/plan 으로 진입하되, 본 spec 의 정책 분류 (preserve / risky / ban) 를 기준선으로 사용한다.
