# 사용자 육안 6결함 진단 (2026-07-02, E2E b0ad5c18/ep 0d30302a)

DB SOT(llm_call_log user_prompt + image_asset lineage) + 이미지 육안 + manifest 게이팅 전수 확인 완료.

## ① S1sh1↔sh3 의상 불일치 (티셔츠→재킷)
- 저장 t2i 둘 다 같은 토큰 `C07O09`(일상캐주얼1 = 무채색 티셔츠+청바지+슬립온).
- shot_detail LLM이 토큰 옆에 임의 의상 수식: sh1 "in casual wear" / sh3 "**in a casual jacket**"(O09 정의에 없는 환각).
- composite ref(bb62b056)는 티셔츠 차림으로 정상인데 **텍스트가 ref를 이겨** 재킷 출력.
- sh1엔 composite 대신 state_variant(c1ea0a86, 중상 티셔츠)만 붙음(1차 wave ref-contract composite→state 대체) — sh1은 우연히 티셔츠로 일치.
- 수정방향: (a) t2i 작성 계약 "의상 표현은 토큰이 유일 SOT, 자연어 의상 수식 금지" (b) 생성 지시 "clothing must match the reference image exactly" 1줄.

## ② S10sh6 창문 안/밖 마네킹 (최심각)
- blocking(a55091c4) 탑다운은 **정확**: 카메라 밖 → 시선콘이 창문(③) 통과 → 방(②) 안 A/B.
- `compute_camera_brief`(outdoor_site_layout_plan.py:787~885)는 depth band/좌우/상대스케일/이동만 전달 — **위상관계(인물이 opening 너머 enclosure 내부) 미전달** → 스케치(998eeb09)가 마네킹을 밖 개방지면에 그림.
- t2i는 "window reflection 속 실루엣" 요구 = blocking/스케치/프롬프트 3자 충돌 → 최종(3c3dc2d7) 유리패널 콜라주.
- blocking_stage=used(structure_signal)였음 — 게이팅 문제 아님, brief 표현력 문제.
- 수정방향: (a) camera_brief에 좌표산술 through-opening 관계 서술(카메라→figure 선분이 edge/opening 교차 판정) (b) 사용자 정책: 반사/투과 특수광학 구도는 마네킹 생성/사용 게이트 제외.

## ③ S12sh15 거대 공중 손
- P03 "붉은 원형 표식" description 자체가 다형: "**벽이나 손목에** 나타나는" → 치환 스플라이스로 "appearing on a wall or wrist" 프롬프트 노출.
- shot_detail은 "벽 상단 중앙"으로 위치를 확정했는데 수식이 손목 선택지를 남김 → 모델이 손목 선택 + chain_bg(L04B06 옥탑방 내부 wide plate) 스케일 충돌 → 방 안 거대 손.
- 수정방향: 요소상세 계약 "소품 description=단일 시각 형태"(다형 발현은 variant 분리, EntityCanon variant 구조 활용) + shot_detail 확정 발현만 t2i 기술.

## ④ S26sh1 야외 스케치 이상 구조물(풀장)
- `blocking_stage=skipped_simple`(step:1064-1072 게이팅) → aerial(7a2b8632, 방파제 내항 수역)에서 sketch(1dd2eced) 직행.
- 스케일/카메라 앵커 없이 내항을 **수영장 풀**로 축소 오해 → t2i는 깨끗("빈 항구 부두")했으나 "match composition to image 2" 계약이 풀장을 최종(8391a07e)에 이식.
- 수정방향(사용자 명시): **3-stage 필수화** aerial→blocking(엔티티+카메라 주입)→sketch. skipped_simple 레인 제거. skipped_no_figures도 카메라 마커만으로 blocking 수행 검토.

## ⑤ S11sh4 문앞 벽 발명
- L10 is_indoor=False 정상, osl-l10 layout 존재. 그러나 seed member=[[11,3]]만(**sh4 미포함**), 11:3 guide도 최종 미생성.
- chain_bg L10B02 plate는 공간논리 완벽(계단→랜딩→문). scene_detail이 공간구조 모른 채 "문 정면 eye-level + 하단 parapet" 지정 = plate 기하상 계단통 공중 카메라(불가능) → 모델이 문앞 V자 벽 발명.
- 수정방향: 3-stage 필수화+seed 커버리지 확대(동일 outdoor loc 전 샷). 장기 = aerial 기반 bg 생성(P4 후속 연결).

## ⑥ S30sh3 배 방향 모순
- t2i 기하 모순: "strict side profile" + "moves toward middle-right background" + 선수가 우측 안개 속 → 선수/선미 혼동 하이브리드 배. 첨부 0(순수 T2I).
- 수정방향(경미): t2i 계약 "이동체 facing/heading 단일 화면 방향 명확 서술" 1줄 후보.

## 우선순위안
④+②+⑤ outdoor 3-stage 필수화 패키지(공통 기반) → ① → ③ → ⑥. 전부 시나리오 토큰 0 generic.

## 관련 코드 좌표
- blocking 게이팅: `backend/app/core/steps/outdoor_site_layout_step.py:1064-1072` (use_blocking 3분기)
- camera brief: `backend/app/modules/pipeline/outdoor_site_layout_plan.py:787-885` (compute_camera_brief)
- 치환/entity_text_map: `backend/app/services/scene_reference_service.py:1002~` (build_entity_text_map, C1 description-first)
- t2i 수식: shot_detail 프롬프트 팩(prompts/) — 신규 버전 디렉토리로 계약 추가 필요

## (별건) 후속과제 진단 완료분
- (a) DB 동시성 레이스: `resolve_chain_bg_asset_id`(scene_reference_service.py:339-372)가 워커 스레드(coordinator:1596)에서 공유 sync Session 쿼리 — 배치 시작 직후 15워커 동시 첫 resolve 충돌(IllegalStateChangeError). 수정 = 메인 스레드 pre-warm(배치 전 background_chain_bg_map 전 bg_id resolve, 캐시 채움). 워커 체인 다른 DB 접점 없음 전수 확인(로더=파일, llm_logger=자체 SessionLocal, crop=db None).
- (b) render_prompt_card drift 26건: detail_steps.py verify_completion — FINDING 8 dual-source fallback으로 20건 흡수, 26건은 fallback recompute도 불일치 → invariant_drift ERROR → run-all resume 차단. 다음 = 샘플(s5_sh3) stored vs recomputed 카드 필드 대조로 변화 입력 특정.

---
## 구현 진행 (2026-07-02 저녁, Codex 의견 수신·사용자 "니가 주도, Codex는 가벼운 리뷰만")

### Wave A — outdoor 3-stage 패키지 (코드 완료, canary 진행중)
- `outdoor_site_layout_step.py`: ①use_blocking 3분기 제거→`mandatory_3stage` 상시(skipped_simple/skipped_no_figures 폐지) ②optical_risk_shot_keys 게이트(judge per-shot 판정→sketch/anchor 엔트리 미생성, diag `optical_risk_excluded`+skip reason `optical_composition_risk`) ③figure 0 샷 pose fail-closed 바이패스(g_has_figures — featureless 스케치 경로) ④pose_brief_present=bool(pose_text) ⑤shot_blocking_recommended import 제거(함수는 plan에 보존)
- `outdoor_site_layout_plan.py`: ①detect_site_seeds broad lane figure 0 seed 포함(why_candidate=`single_shot_outdoor_no_figure`) ②single_shot_complexity_candidates broad figure 0 후보 ③`_point_in_polygon`+`_enclosure_relation_phrase`(순수 폴리곤 산술) ④compute_camera_brief figure 라인에 enclosure 관계(INSIDE/OUTSIDE through boundary) ⑤스케치 SYSTEM 2종에 enclosure 준수 지침
- `outdoor_site_layout_provider.py`: judge 스키마 `optical_risk_shot_keys`(required)+SYSTEM(no-figure 라우팅 안내+optical 판정 지침), SHARED_MODEL_GUIDE_VERSION=v3.202607021900
- 테스트: test_outdoor_site_layout_plan.py 50 passed(신규 4: enclosure/no_figure seed·candidates/optical step) + outdoor 스위트 73 passed

### Wave B — 의상 (완료)
- prompt_service.py ref_instructions에 clothing=ref image SOT 1줄(스냅샷 테스트 갱신)
- scene_detail 프롬프트 **v36.202607021930**(35 복사+수정: 의류 명사는 아웃룩 정의 텍스트의 의류 종류만+같은 씬 같은 C##O## 동일 표현) ★주의: scene_detail 팩 정렬 함정 — ls 문자열 정렬로 9가 최신처럼 보였으나 실제 35가 최신이었음(잘못 만든 10.x 삭제함)

### Wave C — 소품 단일형태 (완료)
- entity_extract_v4 **v10.202607021935**(9 복사+수정: description 단일 시각 형태 원칙, 다형("A이거나 B") 금지, 합치기 규칙 보완)

### Wave D — 이동체 방향 (완료, v36에 포함)
- scene_detail v36에 "이동체 방향 일관성 — 단일 화면 방향" 섹션

### 4-point sync 정렬 (기존실패 부채 5건 해소)
- detail_steps.py SCENE_DETAIL_PROMPT_VERSION="36.202607021930"(cp config_hash invalidation)
- version_registry.py scene_detail_composer 1.36.0 + prompt_dependency scene_detail/v36
- 테스트 리터럴 34→36: test_prompt_versions/id_policy/spatial/continuity_alignment/area_7b
- 결과: prompt 스위트 152 passed 1 failed(entity_extractor_v2-12. = 스코프 밖 기존 부채)

### (a) 동시성 레이스 fix (완료)
- scene_image_service.py 배치 준비부(메인 스레드)에서 background_chain_bg_map 전 bg_id를 resolve_chain_bg_asset_id로 pre-warm → 워커는 캐시 히트만. 서비스 테스트 125 passed.

### 환경/진행
- uvicorn PID 83022 :8000(Wave A 코드, 로그 scratchpad/uvicorn_wavea.log) — ★pre-warm/Wave B는 재기동 필요(canary 완료 후)
- canary: outdoor_site_layout force 재실행 진행중(E2E b0ad5c18, 폴링 bdsjg8y3y) — 완료 후 확인: S26sh1 parent_stage=shot_blocking / S10sh6 optical 제외 여부 / S11sh4 guide 유무 → 씬 재생성(S1sh3/S10sh6/S11sh4/S12sh15/S26sh1/S30sh3) → 육안
- 남은: (b) render_prompt_card drift 정책(후순위), Codex 가벼운 코드리뷰, 커밋(scope 분리)

### Codex 리뷰 + 2차 canary 결과 반영 (2026-07-02 저녁 2)
- Codex 리뷰: 방향/pre-warm/optical(continuity까지 차단)/mandatory/figure0 전부 승인, NARROW 1건=optical per-shot continue가 chain 모순(anchor_source가 skip 샷) → **eligible_members 재계산 구현**(체인 전 필터, 전멸시 attached=false/all_members_optical_risk) + 테스트 2건(first-optical anchor 승격/all-optical 콜0) + enclosure 문구 완화("mapped area ... if boundary or opening is visible"). Codex 확인 완료.
- 2차 canary(force) 실측: ①L03 그룹 생성 성공(S4sh1/S10sh5/S10sh6/S11sh4/S17sh1) ②★S10sh6 optical 게이트 실동작(judge admit 후 optical_risk_shot_keys 지목→sketch 미생성, candidate_skipped=optical_composition_risk) ③blocking 5/5 mandatory_3stage ④★신규버그 발견: figure0 바이패스 기준을 layout entity_count로 썼는데 **layout LLM이 staging에 없는 figure를 발명**(S4sh1/S11sh4/S17sh1 staging 0 → layout 1) → pose 추출 강제 → 텍스트 근거 없어 전부 pose_brief_unusable_fail_closed. **fix=기준을 staging character_angles(텍스트 SOT, seed와 동일)로 변경** + 테스트(staging0→pose 미호출+featureless sketch+pose_brief_present False). 53 passed.
- 3차 canary(force, uvicorn PID 7127 최신 코드=staging 바이패스+eligible_members+pre-warm) 진행중 — 완료 후 L03 4샷 guide 생성 확인 → 스케치 육안 → 6샷 재생성.

---
## 3차 육안 리뷰 진단 (2026-07-03, 사용자 3건+구조제안+마네킹 전면 재리뷰 지시)

### 결함 진단 (확정)
1. **S11sh4 계단실 과소(야외 화장실 같음)**: figure0 featureless 스케치에 인간 스케일 앵커 부재 + layout 폴리곤에 절대 크기 개념 없음 → 스케치가 계단실을 좁고 작은 박스로 그림 → 최종 이식. plate(L10B02)의 계단실은 정상 크기.
2. **S15sh1 정류장 방향 반대(바다를 봄, 찻길을 봐야)**: 스케치부터 셸터 개방면+마네킹 시선이 바다쪽. **구조물 방향성(개구부/전면 orientation)이 layout 스키마→camera_brief→스케치 어디에도 인코딩 안 됨** + "정류장은 도로를 향한다" 같은 인접구조 관계 부재. (t2i의 시선 서술 확인 필요 — 서사상 도로를 봐야 함이 사용자 확인.)
3. **S24sh2 만화풍+스케일 붕괴**: 어제 run(07:55)의 구 스케치(c55e42a9)가 attach → **스케치 line-art 스타일이 최종 배경(바위/수풀/해안선)에 그대로 누출** + 도로가 인물 대비 과소(원근 붕괴). "composition만 취하고 스타일 금지" 계약이 실패한 케이스.

### 공통 패턴 (마네킹 스케치 실내외 전부 부정확 — 사용자 "매우 심각")
- (a) **스케일 앵커 부재**: 절대 크기 정보가 체인 어디에도 없음(마네킹=유일 앵커인데 figure0면 전무, 있어도 구조물 비례 오류)
- (b) **방향성 부재**: 구조물 개구부/전면/향이 layout에 없음
- (c) **스타일 누출**: 스케치 ref가 구도를 넘어 렌더 스타일까지 오염(S24sh2 실증)
- (d) 구조물 발명/중복(S15sh1 스케치의 이중 벤치)

### 사용자 구조 제안 (실내 개선 실험)
**FP 기반 실내 3-stage**: fp → fp를 ref로 엔티티+카메라 주입(실내판 blocking) → 배경 생성 → 배경들은 순서대로 관련 배경을 ref 체인으로 연결(일관성). 실내가 전체적으로 이상한 것의 해법 후보 — outdoor 3-stage와 대칭 구조.

### 다음 단계 (설계 방향, 미착수)
- 마네킹 스케치 전면 재리뷰: 실내 indoor_pose_guide 6장 + 실외 composition_guides 전부 육안 → (a)~(d) 패턴별 빈도 확정
- 수정 후보: ①layout 스키마에 구조물 orientation/개구부(선택 필드)+brief 반영 ②스케일 앵커(마네킹 항상 포함? or 표준 크기 참조물) ③스케치 attach 시 스타일 격리 강화(생성 지시 "line-art 스타일 절대 복사 금지" 강문+VLM readback으로 스타일 누출 검출) ④FP 기반 실내 실험(별도 스크래치 실험 후 설계)
- ★Codex는 "정말 참조만"(사용자 지시) — 설계/구현/판단 전부 Claude 주도.

---
## 마네킹 스케치 전면 재리뷰 결과 + 확정 설계 (2026-07-03, Claude 육안 — 스케치 13장+최종 8장 대조)

### 육안 판정표 (outdoor: 그룹별 최신/attach본)
| 샷 | 스케치(세대) | 판정 |
|---|---|---|
| S1sh1 | 32c4cbea(attach) | 양호 — mid-stride 포즈 정확, 최종 HELP |
| S3sh3 | 70921489(attach) | (e)프레이밍: t2i "상체"인데 4인 전신 wide. 최종 wide로 끌림(경미) |
| S4sh1 | 97c5274c(최신,미attach) | 구조 안정. 옥상 실루엣 인물 1 발명(layout figure 발명 흔적, 스케일 앵커 역할은 함) |
| S9sh1 | 8a49b673(attach,aerial직행) | (e)원경 wide vs t2i 인물중심 측면. 페달링 동세 부족. 최종 t2i 승(무해) |
| S10sh6 | 998eeb09(구,미attach) | (b)위상: 마네킹들이 창문 밖 지면(t2i=창 반사 실루엣). 최신 run은 judge_no_need로 미생성=정확 |
| S11sh4 | e1a75eec(attach) | (a)figure0 스케일 앵커 부재 → 계단실 과소 박스 + (d)물탱크/외부계단/마을지붕 발명 + 문 "반쯤 열림" 미반영 → 최종 오염(사용자 결함③) |
| S15sh1 | 6341ff3b(attach)+dc4a0add(최신) | (b)★양세대 공통: 셸터 개방면이 도로를 등지고 바다/보도 쪽 → 사용자 결함② 그대로. 최신 세대는 (d)셸터 밖 이중 벤치 발명 추가 |
| S22sh1 | 99ce3311(미attach) | 양호 — 마트 앞 자전거+마네킹 |
| S24sh2 | c55e42a9(attach,aerial직행) | (e)★t2i "얼굴 클로즈업"인데 자전거 전신+도로 wide 스케치 attach → (c)스케치 line-art가 최종 배경에 누출(사용자 결함① 만화풍). 최신 cp에선 후보 자체가 빠짐(스틸만 stale) |
| S26sh1 | 75cb5def(attach) | 양호 — 웅크림/포구 구조 정확, 최종 HELP(풀장 결함 해소 확인) |

### indoor 6장
| 스틸 | 가이드 | 판정 |
|---|---|---|
| S5 st9 | fbf7b707 | (e)손목 표식 클로즈업 샷에 전신 캐주얼 스탠딩(허리 손) — 씬 액션 무관 |
| S12 st22 | 9642a445 | (e)얼굴 클로즈업에 전신. 포즈 자체(공포 후퇴)는 반영됨 |
| S14 st27 | b8ea5ccb | (b)"커튼 응시"인데 반대편 서랍장 짚고 숙임. 최종은 가이드 무시(양호) |
| S14 st28 | 4f8747ac | (b)"빈 식탁 가리킴"인데 침실 서랍장 가리킴(식탁은 옆방). 최종은 t2i 승(양호) |
| S18 st37 | 92ebc773 | ★(f)방 선택 오류: "식탁 위 사진" 샷에 욕실 plate+세면대 선반 걸터앉기(물리 오류). 최종은 가이드 무시. 별건: 최종의 사진 속 민숙이 "변형" 아닌 정상 얼굴(t2i 미반영) |
| S29 st55 | 72ea8b7e | 양호 — 사진 가리킴 상호작용 정확(모범 케이스) |

### 패턴 빈도 확정
- **(e)프레이밍 불일치 7/16 최다(신규 패턴)**: 클로즈업/인서트 샷에 전신 구도가이드 생성·부착(S3/S9/S24 + indoor S5/S12/S18/S29). S24sh2에서 (c)의 트리거.
- **(b)방향성·위상 부재 5/16**: S15(구조물 개방면, 양세대 구조적) S10sh6(창 안↔밖) S11sh4(문 상태) + indoor S14×2(응시/가리킴 대상 방향 소실).
- **(d)구조물 발명 3**: S15' 이중 벤치, S11sh4 물탱크·외부계단·마을지붕, S4sh1 실루엣 인물.
- **(a)스케일 앵커 부재**: figure0 스케치에서 표출(S11sh4). figure 있으면 마네킹이 앵커.
- **(c)스타일 누출 1/7 치명**(S24sh2) — 조건: 프레이밍 불일치 스케치가 attach되어 이길 때.
- **(f)신규: indoor 방/plate 선택 오류**(S18) — 별건 조사.
- **(g)stale**: S1/S3/S9/S15/S24 최종 스틸=첫 run(07:53-55) 산출, 그 후 4회 force 재실행으로 cp attach 계획은 4:1/11:4/15:1(+anchor)/26:1만 남음. attach 로직은 cp SOT 정상 — "가이드 재생성→스틸 재생성 미연계"가 본질(기존 whack-a-mole 과제).
- 최종 전이: HARM 3(=사용자 3결함 정확 일치), NEUTRAL 5(가이드 무시), HELP 4(S1/S26/S29/S12부분).

### indoor 방향 소실 근본원인 (코드 확정)
`indoor_shared_pose_plan.py build_pose_brief`:
1. :292-302 `gesture_target_label`을 받고도 `f"{ga} toward a nearby object"`로 generic화 — **대상의 공간 위치를 버림**(S14 st28 가리킴 오류).
2. :320-322 `gaze_direction_kind` 있어도 `facing = "oriented per gaze direction"`이라는 **무의미 문구**(방향 정보 0)(S14 st27 응시 오류).

### ★확정 설계 (구현 스펙 — 전부 generic, 시나리오 토큰 0)
**W-A outdoor 스케치 품질** (`outdoor_site_layout_provider.py`/`outdoor_site_layout_plan.py`)
1. SITE_LAYOUT_SCHEMA landmarks items에 `faces_toward` 필드(moving_toward 패턴: `anyOf[point,null]`+required): "명시적/기능적으로 명백한 개방면·전면이 향하는 지점, 불확실=null, never guess". SITE_LAYOUT 지시문에 1-2줄(텍스트 근거/기능적 명백성 조건). validate_site_layout에 shape 검증(point or null).
2. `compute_camera_brief`: landmark 라인에 faces_toward 있으면 open_vec=faces_toward−centroid를 카메라 프레임 투영 → `; its open/front side faces toward the camera / away from the camera / toward the left(right) of frame` 산술 서술.
3. 스케치 SYSTEM 2종(_BLOCKING_SKETCH_SYSTEM/_POSED_SKETCH_SYSTEM, plan:1178/1208) 강문 3줄: ①방향 준수(brief의 open/front 방향대로, never mirror) ②스케일 앵커(문=성인 키, 벤치=무릎 높이, 도로=차폭; 마네킹 있으면 그것 기준, 없어도 성인 기준 비례 — miniature 금지) ③발명 억제(diagram/brief에 있는 요소만, 여분 벤치·탱크·계단·건물·중복 사본 금지).
**W-B 프레이밍 게이트(소비부)** — close류 샷엔 구도/포즈 가이드 attach 자체를 skip:
4. `attach_composition_guide_ref`(outdoor_site_layout_step.py:379)에 framing param — mode='sketch'이고 framing이 close류면 return False+진단(continuity_anchor는 유지, close×zoom 계약 별도 존재). 호출부에서 shot framing_scale(shot_staging SOT) 전달.
5. indoor attach(attach_indoor_pose_guide_ref, scene_image_service:~524 배선부) 동일 게이트. (생성부 게이트는 2단계 — 소비부가 결함 방지 즉효+구세대 cp에도 적용.)
6. framing 판정: `_normalize_framing`/FRAMING_CLOSE 기존 enum 재사용(글자 패턴 금지 — 정확 enum 비교).
**W-C indoor brief 방향 복원** (`indoor_shared_pose_plan.py build_pose_brief`)
7. gesture: gtl 있으면 constraints에서 label==gtl인 non-character constraint의 screen_zone/depth_plane을 찾아 `f"{ga} toward the {공간구}"`(_slot_descriptor류 재사용, 라벨/이름 미주입 유지). 미발견시 기존 문구.
8. facing: gaze_direction_kind enum→실방향 문구 매핑(looks_at_character→"facing the other figure", camera류→"facing the camera" 등 — shot_staging enum 확인 후). gaze_target_id 미주입 유지.
**W-D 스타일 격리 강문** (`prompt_service.py` composition_guide/indoor_pose_guide ref 렌더 분기)
9. 1줄: 스케치는 framing/placement/pose만 — monochrome line-art 스타일·연필선·미완성 배경·종이질감 복사 금지, 최종은 씬 조명의 full photoreal.
**W-E 검증**: 결정론(스키마/brief 방향구/게이트/gesture·facing 신규 테스트+기존 스위트) → uvicorn 재시작 → outdoor_site_layout force(L10/L11: S11sh4 스케일·발명, S15sh1 방향) 스케치 육안 → S15sh1/S11sh4/S24sh2 스틸 redo 육안(S24는 최신 cp에서 후보 제외라 가이드 없이 재생성=만화풍 해소 예상) → indoor S14 가이드 재생성 방향 확인.
**별건(이번 wave 제외)**: (f)S18 욕실 plate 선택 조사(chain_bg 매핑) / (g)가이드 재생성→스틸 재생성 연계 정책 / S18 최종 "변형 민숙" 미반영 / S9sh1 동세(경미).

---
## 4차 육안 리뷰 (2026-07-03, 사용자) — 2결함 + W-G/W-H 설계

### 결함 진단 (확정)
1. **S11sh4 여전히 "옥상 창고"(사용자: 문도 크고 옥탑방 같지 않음)**: ★배경 plate(L10B02)부터 이미 단칸 창고+물탱크로 렌더됨(직접 원인 — 사용자 "배경에 문제 있을 수도" 적중). 스케치도 동일 상상. **근본원인 = 같은 building_group의 indoor fp 미참조**: `background_classify.building_groups`에 이미 [외부 loc(현관앞), 내부 loc(fp 보유), 외부 loc(골목계단)]이 한 그룹으로 존재하는데(구조 데이터), outdoor 산출물(aerial/blocking/sketch/bg plate) 어디에도 그 fp가 참조되지 않아 건물 크기·개구부·구조가 근거 없이 축소·왜곡. 물탱크도 plate에서 최종으로 이식된 것.
2. **S2sh4 공중 부양(사용자: 비스듬하게 서 있음)**: staging="folding toward pavement, middle of collapse"(wide) → 모델이 지지 접촉 없는 45° 경직 기울기로 렌더. 씬 프롬프트에 물리 접지 계약 부재. → **W-H로 해소**(커밋 1b0a76fc, redo 육안=무릎·손 접지 collapse PASS).

### ★W-G 확정 설계 (구현 스펙 — 전부 generic 구조 조인, 시나리오 토큰 0)
**목표**: 같은 건물의 내부 fp를 외부 산출물의 구조 SOT 로 — "내외부 연결 + 같은 장소 샷 함께 관리"의 v1.
1. **building link 로더(신규 순수 함수)**: `building_groups[].members[{loc_id,is_indoor}]` → `{outdoor_loc_sid: indoor_loc_sid}` 맵(같은 group 에 is_indoor True/False 공존 시만). indoor loc→fp 매핑은 floor_plan 계열 cp 의 **구조 필드**로(파일명/라벨 파싱 금지 — floor_plan_prompt/render cp 의 data.floor_plans[fp_id] 에 location 구조 필드 있는지 확인 후 조인; 없으면 fp_id↔loc 매핑을 가진 cp 를 찾아 SOT 지정). fp 여러 개면 결정론 선택(주 fp 1장 — is_primary/정렬 구조 키).
2. **주입 A — outdoor_site_layout Stage A(aerial base)**: same-building fp 있으면 T2I→I2I 승격(`_edit_image_with_ref` 재사용, ref=fp PNG) + generic 지시("attached = top-down interior floor plan of a building on this site (structural reference): keep that building's footprint size/shape and door/window placement consistent with it; do NOT copy the plan's text/numbers/colors into the aerial"). base 정합→blocking/sketch 체인 상속. meta 에 fp_asset_id 기록.
3. **주입 B — background_render outdoor direct-plate**(`_render_direct_plate` text_only 경로): same-building fp ref 추가 + 동일 정합 지시 + `ref_used` 마킹 갱신 + `capture_input_image_ids=[fp_asset_uuid]` → 캔버스 fp→bg 자동 엣지(기존 pipeline-graph input_image_ids 렌더 — 신규 UI 코드 최소, role 필터에 기존 floor_plan 노드 이미 존재).
4. **플래그**: `outdoor_building_fp_ref_enabled`(default OFF → canary 후 .env ON). OFF/링크 없음(순수 야외)=기존 경로 byte-identical.
5. **검증**: 결정론(로더 조인/fp 선택/OFF no-op) → uvicorn 재시작 → outdoor_site_layout force(해당 building 그룹만이라도) 스케치 육안(건물이 '집'으로) → background_render 해당 bg force → plate 육안 → S11sh4 스틸 redo 육안 → 시나리오 토큰 grep 0.
6. **v2 후보(기록만)**: same-building outdoor locs 통합 aerial(하나의 site 좌표계) — 그룹핑 대변경이라 별도 wave. / fp+외부 통합 투명 뷰 신규 산출물(사용자 옵션(b))은 (a) 실패 시 fallback 설계.
