# W21B-w6 — BG 재설계 production 배선 설계 brief (geometry → camera → VLM text → T2I)

> 상태: **설계 (코드 0 / commit 0)**. 2026-06-05. 작성=Claude, 리뷰 대기=Codex + 사용자.
> 선행 스파이크 검증 완료(전부 `/tmp`, 육안 PASS): task1(validator) · task2(카메라 계산 연결) · A(누출 차단) · B(per-room) · C(옥탑방 실샷 pose 매핑) · F(generalization: 외부/사무실/조타실).

---

## 1. 배경 — 왜 바꾸나

기존 BG 경로는 **floor-plan marker 번호 / zone / partition** 기반이다(`floor_plan_prompt → floor_plan_render(이미지 FP) → floor_plan_vlm/readback → shot_projection_card → bg_zone_space_partition → shot_aware_bg_render_plan → background_render`). 사용자 육안에서 반복 실패한 근본 원인:

- 이미지 FP를 다시 VLM이 읽어 번호를 매기는 과정이 비결정적(번호 비결정성, partition over-merge).
- 이미지 모델이 배치를 발명 → TV가 철문 앞 등 비정합. i2i·3D direct 둘 다 사용자 반려(이미지 모델은 정밀 배경에 약함).

**검증된 새 방향**: 좌표(metric geometry)를 코드가 top-down으로 그리고, 그 각도에서 **실제로 보이는 객체를 코드가 계산**해 VLM에 주면, VLM이 정확한 배경 텍스트를 쓰고 T2I가 plate를 만든다. 이미지 모델의 약점(정밀 배치)을 피하고 강점(텍스트→이미지)만 쓴다.

## 2. 검증된 흐름 (스파이크 → production 모듈 매핑)

| 단계 | 스파이크 자산(/tmp) | production 모듈(신규) | 입력 | 출력 |
|---|---|---|---|---|
| ① 좌표 생성 | `geum_geometry_spike.py` (LLM + validator + `_draw_topdown`) | `metric_geometry_plan` step + provider + module | `space_model`(v10) + 샷 원문 scene_text | geometry JSON(좌표/zone/opening/object) + top_down.png |
| ② 카메라 계산 | `geum_camera.py`(select/score) + `geum_camviz_c.py`(pool+Stage1) | `camera_visibility_plan` step + provider | geometry + 샷별 camera_direction/scene_text + top_down | 샷별 chosen_camera + visible/hidden(코드 ground-truth) |
| ③ 배경 텍스트 | `geum_camviz_c.py` Stage2(2층 VLM) | `background_text_prompt` step + provider | chosen camera별 visible/hidden + top_down + scene heading | `always_style_sot` + per_shot background |
| ④ plate 렌더 | `geum_camviz_c.py` `t2i()` | `background_render`(신규 reference_mode 분기) | style + per_shot visible-only | 배경 plate PNG |

핵심 설계 원칙(스파이크에서 검증):
- **always_style_sot(재질/팔레트만, 인벤토리 0)** vs per_shot(보이는 것만) 분리 → 다른 방 누출 차단(A).
- per-shot T2I에 **전체 인벤토리 미주입**(primary), doorway 제약은 보조.
- camera 계산 = occlusion(interior_room만) + visibility. weight는 archetype(있으면) 또는 fixed flag(스파이크 대용) — **글자매칭 0**.
- Stage1 카메라 선택 = LLM 의미판단, **expected_visible == 코드 ground-truth 재확인**으로 검증.
- per-shot 조명(scene heading의 낮/밤/해질)은 반영, 재질 팔레트는 고정.

## 3. 신규 경로 — step 4개 (전부 default OFF)

기존 step 패턴(`StepRunner` 서브클래스: `_config_hash`/`_load_prev_checkpoint`/`_execute`/`verify_completion`, provider는 `modules/pipeline/*_provider.py`)을 따른다. 체크포인트는 `projects/<pid>/checkpoints/episodes/<eid>/<step_id>/manifest.json`.

```
(v10 space_model, shot_staging, scene_save 존재 전제)
  → metric_geometry_plan      (LLM 좌표 + 코드 validator + top_down 렌더)
  → camera_visibility_plan    (코드 후보풀 + LLM 샷별 선택 + 코드 visible 검증)
  → background_text_prompt     (VLM 2층: always_style_sot + per_shot)
  → background_render          (T2I: style + visible-only)  ← 신규 reference_mode 분기
```

### 3.1 `metric_geometry_plan`
- provider(LLM, gpt-5.5 json_schema): space_model topology + 샷 scene_text 원문(★자르지 않음) → 좌표 geometry. SYSTEM은 **generic space_type-aware**(interior_room/exterior_plate/site_surface/vehicle 적응; 주거 템플릿 강제 금지) — 스파이크 `geum_4space` SYSTEM 검증됨.
- module: deterministic validator(through-path corridor 등, HARD/diag) + 1-repair + `_draw_topdown`(matplotlib).
- 출력: geometry JSON + top_down PNG(이미지 산출물 디렉토리).
- **v10 essential 분리(주의점 ①)는 여기서**: SYSTEM이 `essential_elements`를 scene evidence로 **fixed_background vs story_prop/state** 분류(SCENE TEXT PRIMARY). 코드 lexicon 금지. (upstream v10 자체 분리는 §6 참고 — 별도/후속.)

### 3.2 `camera_visibility_plan`
- module(코드, deterministic): 후보 카메라 풀 생성(zone establishing + 그리드 eye×anchor target, exterior는 overhead 보장) + 각 후보 visible/hidden 계산(occlusion+weight).
- provider(LLM vision): 샷별 camera_direction+scene_text+top_down+후보 요약 → chosen_camera_id + reason + expected_visible.
- 코드가 `expected_visible == ground-truth visible` 재확인(불일치 = 신뢰도 낮음 플래그).
- 출력: 샷별 {chosen camera pose, visible[], hidden[], reason}.

### 3.3 `background_text_prompt`
- provider(VLM): chosen camera별 visible/hidden + top_down + scene heading → `always_style_sot` + per_shot background(보이는 것만).
- 출력: always_style_sot + per_shot[].background.

### 3.4 `background_render`
- **신규 `background_render_reference_mode` 값 `"metric_geometry"`** 분기(§5). T2I 입력 = `always_style_sot` + per_shot background + doorway 제약 + DO-NOT. 기존 marker/zone/overlay/shot_aware 경로는 무변경.

## 4. 데이터 계약 (요지)
- 입력 SOT: `floor_plan_prompt.space_model`(v10), `shot_staging`, `scene_save`(scene_text 원문), `physical_space_cluster_plan`(있으면 location 그룹핑).
- 샷 소스: 기존 `build_shot_context(shot_id, shot_staging, scene_save)` **재사용**(helper만; floor_plan_vlm/readback/shot_projection_card 경로는 미사용 — §6).
- 각 step은 sibling 출력, 기존 master_plan/marker/zone 체크포인트 **불침**.

## 5. default OFF / opt-in (byte-identical 보존)
검증된 패턴: `background_render._config_hash`는 opt-in reference_mode일 때만 신규 키를 stamp → legacy v6/v7 및 비-opt-in은 payload byte-identical.
- `settings.background_render_reference_mode`에 `"metric_geometry"` 추가(config `Literal`, **default 불변**).
- 신규 3 step은 selector OFF면 skip(기존 zone/marker step들과 동일 gate 패턴) — 활성 시에만 실행.
- 활성 시에만 신규 config 키 stamp; OFF 경로는 모든 기존 step의 marker/zone/payload byte-identical(회귀 0 증명을 완료 보고에 별도 섹션).

## 6. 기존 자산 재사용 / 회피 경계 (주의점 ②)
- **재사용(helper만)**: `build_shot_context`, `llm_deadline.call_with_deadline`, T2I 클라이언트(gpt-image-2) 인프라, config/step_runner/gate 패턴, 이미지 산출물 경로.
- **회피(억지 재사용 금지)**: `floor_plan_vlm`/`readback`/`shot_projection_card`/`bg_zone_space_partition`/`shot_aware_bg_render_plan` — 번호/zone/partition 흔적이 많아 신규 경로를 다시 복잡하게 만든다. 신규 경로는 **좌표가 SOT**라 번호/zone 조인키가 필요 없다.
- v10 space_model **자체** 분리(fixed_background vs story_prop)는 기존 marker/zone 경로까지 영향(blast radius 큼) → E에서는 **신규 geometry_gen step 안에서 LLM scene-evidence 분류**로 격리하고, upstream v10 변경은 별도 후속으로 분리(둘 다 코드 lexicon 금지).

## 7. 리스크 / 비검증 영역 (절대규칙: TDD로 완성도 주장 금지)
- T2I는 정확 metric 좌표를 안 지킨다(침대 좌우 flip 등) — 공간 identity/재질은 유지. 연구 기준 허용, **완성도는 육안**.
- 좌표 LLM·VLM·T2I는 통계적/비보장 → deterministic 부분(validator, 후보 생성, visible 계산, default-OFF byte-identical)만 단위 테스트. 핵심 출력 완성도는 **fresh E2E canary + 육안 + 미세조정 반복**.
- 비결정성: geometry/카메라 선택 재현성(seed/캐시) — 후속.

## 8. 구현 순서 (canary-first, 각 단계 육안 + Codex 리뷰)
1. `metric_geometry_plan` step+provider+module → 1 location canary(좌표+top_down 육안).
2. `camera_visibility_plan` → 후보풀+선택 dry-run(expected==code) 육안.
3. `background_text_prompt` + `background_render` 분기 → 옥탑방 fresh canary(C 재현).
4. generalization 2공간(사무실/외부) module canary(F 재현).
5. default-OFF byte-identical 회귀 증명(marker/zone 경로 무변경).
6. fresh full E2E → 갤러리 육안 → commit 그룹 분리(GO 후).

## 9. 미해결 / 리뷰 포인트 (Codex/사용자 의견 요청)
- (a) v10 essential 분류를 geometry_gen 내부(격리)로 두는 §6 안에 동의? upstream v10 변경은 후속 분리에 동의?
- (b) `background_render` 신규 분기 vs 완전 신규 step `metric_geometry_bg_render` — 어느 쪽이 기존 경로 오염이 적나(분기는 한 파일에 모드 증가, 신규 step은 selector 라우팅 추가).
- (c) 카메라 weight: production은 archetype(LLM enrich, geum_4space 검증) vs fixed-flag(스파이크 대용) — archetype 권장(F에서 효과 확인)인데 enrich step 추가 비용 의견.
- (d) 후보풀 크기/overhead 보장 등 휴리스틱의 generic 안전성(특정 공간 하드코딩 0 유지).
