# P8 (시신/부동 dynamic-entity 연속성) — 구현 전 설계 브리프 (Claude → Codex peer 의논)

작성: Claude, 2026-06-20. 대상 run 실측: pid=7bea6537 / eid=bee89290 (HEAD cae7e566).
analysis.md 정독 + 코드/DB/체크포인트 실측 완료. 문서 대비 정정·구체화 포함.

## 1. 실측으로 정정/구체화된 사실 (analysis.md 가정과 차이)

1. **subject_state 는 샷-레벨이 아님** → `shot_staging.character_angles[*].subject_state`
   (캐릭터별). `character` 필드 = **이름 문자열**(short_id 아님). `body_pose` 도 캐릭터별·
   샷별로 독립 LLM 생성 = 포즈 드리프트의 직접 원천.
   - 실 체크포인트 shot 키: `{scene_index, shot_index, framing_scale, perspective,
     pov_character, camera_direction, lighting_mood, character_angles[], key_bg_elements,
     frame_spatial_contract, subject_reference_policy}` — 샷레벨 subject_state 없음.
2. 이 run 시신 = **C04(민숙) dead**, 등장: **S12sh8**(framing=medium, body_pose="seated head
   fallen") + **S12sh13**(framing=insert, body_pose="stiff hand clenched"). 둘 다 VE 에 C04.
   (S12sh16 엔 C04 없음 — character_angles 비어있음.)
3. sh8↔sh13 은 **이미 zoom_continuity 그룹**(vca-s12-zoom-5)인데
   `camera_relation=different_camera_same_moment`(punch_in 아님) → **crop 안 함**.
   locked_elements 가 시신 포즈를 계약("corpse hand stiff/clenched", "dead seated body")하지만
   **sh8(source_wide)만 revised_wide_t2i(rewrite)로 수신**, **sh13(zoom/insert)은 자기 prompt
   의 body_pose 로 독립 생성 = 계약 미수신**. → 분석 문서의 "W-C wave 미구현" 갭 확정.
   (zoom locked_elements 의 per-shot 도달 경로: wide=rewrite, zoom=crop/i2i — different_camera
   는 둘 다 미적용.)
4. **클러스터 A 실측**: dead 변이 자산(entity_id=c5ccf4f6, `[state_variant:c5ccf4f6:dead] 민숙`)
   **존재**하는데 sh8/sh13 둘 다 nb2 에 **"Passport-style ID photo" 라벨**의 민숙 ref 수신.
   - 근본 1 (= **P3 와 동일 뿌리, 메타-A**): `build_image_index`(scene_reference_service.py:99-109)
     가 character ref 라벨을 **무조건 `_info.t2i_prompt`(=passport 생성 프롬프트)로 재작성 + 이름
     주입** → 설령 dead variant bytes 가 붙어도 라벨이 "passport ID photo, plain white bg" 로
     덮여 nb2 가 모순 신호 수신.
   - 근본 2 (선택 갭): resolve_refs 의 state-variant 부착 분기(521-541)는 **복합 ID
     `(C\d{2,3})(O\d{2,3})` 루프 안에만** 존재. **sh13 = bare `C04`** (시신은 아웃룩 없음) →
     복합 regex 미스 → state-variant 분기 자체를 안 탐. (sh8 = `C04O05` 복합이라 분기는 타나
     라벨이 build_image_index 에서 덮임.)

## 2. 재사용 가능한 기존 인프라 (신규 최소화)

- **visual_continuity_anchor step/plan/loader/inject** (printed_prop D-seed) = 그대로 미러링.
  `detect_d_seeds` ↔ 신규 seed, `build_prop_group` ↔ 신규 group, `load_printed_prop_anchor_context`
  ↔ 신규 loader, detail_steps:2970 주입 블록 ↔ 신규 주입 블록.
- **name→short_id exact-equality** 패턴: `detect_state_variant_sids`(scene_reference_service.py:1370),
  `apply_back_to_camera_constraints`(:196-218) 가 이미 `ve.name == ca.character` exact 매칭 +
  ambiguous skip+log. 동일 규약 재사용(글자판정 아님 = 엔티티 canonical name 정확일치).
- **composition continuity-chain + attach** (`composition_continuity_chain` outdoor_site_layout_plan.py:552,
  `attach_composition_guide_ref`/`_attach_continuity_anchor`/`load_composition_guide_context`) =
  establishing 시각 anchor(continuity_anchor 모드)에 재사용. **새 스케치 모델 불필요** — establishing
  멤버샷의 완성 still 을 후속 멤버샷 ref 로.
- **state_variant 선택/생성** (`detect_state_variant_sids`, CharacterStateVariantStep) = 자산은 이미
  생성됨(applicable 4/completed 4). 클러스터 A 는 선택+라벨 결함이지 생성 결함 아님.

## 3. 제안 설계 — 단계 분리

### Increment 1 — 텍스트 공유 포즈/위치 계약 (P8 핵심, flag-gated)
1. `detect_immobilized_subject_seeds(staging_by_shot, ve_by_shot, selected_map, name_to_sid,
   *, framing_by_shot)` 신설 (visual_continuity_anchor_plan.py, detect_d_seeds 대칭, 구조적):
   - 각 selected shot 의 character_angles 순회 → `is_immobilized_state(ca.subject_state)` 인
     캐릭터의 `character`(이름)를 name_to_sid(exact)로 C## 해석 → 그 C## 가 그 샷 VE 에 존재.
   - 같은 C## 가 **같은 scene_index 의 ≥2 selected shots** 에서 immobilized → seed.
   - score = required-ish 없음 → framing(insert/close) 가중 + 멤버수 (deterministic).
   - 시나리오 토큰 0 (enum + ID 조인 + name exact 일치만).
2. 새 anchor_type `"immobilized_subject"` group + provider `extract_immobilized_subject_anchor`
   (seed 당 1 LLM 콜): 입력 = 멤버 scene 원문 전체(자르지 않음) + 멤버 (si,shi,shot_description,
   body_pose) 목록. 출력 = **공유 locked_elements 1세트**(canonical frame_position / pose /
   orientation / state_visual), evidence_quote 필수, **이름·고유명사 금지**(구조적 지칭만:
   "the immobilized subject", left/right/foreground 등).
3. visual_continuity_anchor `_execute` 에 printed_prop 과 나란히 배선
   (select_seeds_with_cap 확장 / build group / validate / manifest / review_html 재사용).
4. 신규 loader `load_immobilized_subject_anchor_context()` (by_char + members_by_shot).
5. detail_steps:2996 다음에 **printed_prop 미러 주입 블록**(별도 flag-gated): 멤버 전샷
   user_prompt 에 공유 포즈/위치 계약 동일 주입.

### Increment 2 — 클러스터 A + P3 (메타-A, build_image_index)
- `build_image_index` 라벨을 **식별용 descriptor**로 (passport 생성 프롬프트 통째 주입 중단 +
  이름 제거). state-variant ref 는 state semantic 보존.
- resolve_refs state-variant 분기를 **bare C## 경로에도** 적용(현재 복합 전용).
- → P1/P3 묶음에서 함께(P8 1차와 분리).

### Increment 3 — establishing 시각 anchor (continuity-chain 재사용)
- immobilized_subject 그룹의 첫 렌더 멤버(넓은 framing 우선)를 establishing → 후속 멤버에
  완성 still 을 continuity_anchor ref 로. 렌더 순서 의존 = 리스크라 별도 단계.

## 4. 의논 포인트 (Codex peer)

- **Q1 계약 SOT**: 새 LLM 추출 1콜(zoom無 멤버도 일반 커버)을 SOT 로, 기존 zoom locked_elements
  와 직교 공존(포즈 vs 프레이밍)? 아니면 zoom 있는 멤버는 zoom locked 재사용?
  → 내 안: 새 추출 SOT, zoom 직교 공존(중복은 둘 다 같은 씬원문 파생이라 일관).
- **Q2 seed 게이트**: shot_index 인접(연속) 필수 vs 같은 scene_index 내 ≥2면 충분?
  → 내 안: 인접 불요, scene_index 동일 + immobilized + VE 존재 만(시신은 씬 전체 연속).
  (staging 에 per-shot location 필드 없음 → location 동일성은 scene_index proxy.)
- **Q3 수렴 분리**: 클러스터A/P3(build_image_index 메타-A)를 Increment 2(P1/P3)로 분리하고
  P8 1차는 텍스트 계약만 — 동의?
- **Q4 establishing 시각 anchor 분리**(Increment 3) — 동의?
- **Q5 anchor_type 위치**: visual_continuity_anchor manifest 에 새 anchor_type 추가(단일
  chokepoint) vs 별도 step/manifest? → 내 안: 같은 step 재사용.

시나리오 의존 0 / TDD 강제 X(실험+육안) / commit·push 사용자 GO 시만.
