# TASK 3 — 외부 location 이미지 인프라 finding 진단 (read-only)

날짜: 2026-06-29 · run: project `a2a5cdeb-fb26-419a-9125-897bd6b603f5` / ep `41b30f18-e240-4763-b289-8b70957a4f28`
상태: read-only 진단 완료, Codex 의논 중. 구현 미착수.

## 증상
- `scene_image_pipeline` = **failed** (`STALE_UPSTREAM upstream=background_render`).
- 외부 bg(fp_l11_exterior) 필요한 scene 미생성. (전체 46 scene still은 생성됨.)

## 증거 (DB step_run + 체크포인트 manifest)
| step | status | counts | 비고 |
|---|---|---|---|
| floor_plan_geometry_readback | completed @13:11 | 12 ok / 0 fail | 12개 fp **전부 ok** (fp_l11_exterior 포함) |
| shot_aware_bg_render_plan | completed @**12:40** | **11** ok / 0 fail | **fp_l11_exterior 누락** (failed 엔트리조차 없음). readback보다 31분 **먼저** 완료 |
| background_render | **partial** | 23 ok / **1 fail** | L11B01: `render_attempts=0`, `render_error="shot_aware_plan: plan missing for fp_id='fp_l11_exterior'"`. t2i_prompt는 이미 생성됨, ref_used=text_only |
| scene_image_pipeline | **failed** | 0 / 0 | STALE_UPSTREAM. 46 still 생성됐으나 누락 bg 쓰는 scene이 stale 전파 → step 전체 failed |

`.env`: `FLOOR_PLAN_VLM_READBACK_REAL_PROVIDER_ENABLED=true`, `SHOT_AWARE_BG_RENDER_PLAN_REAL_PROVIDER_ENABLED=true`, `BACKGROUND_RENDER_REFERENCE_MODE=shot_aware_plan`.

## 근본 인과 사슬

**C1 트리거 — stochastic VLM readback 실패, 재시도 없음.**
`floor_plan_geometry_readback` step이 real VLM provider(`litellm_vlm_provider`, gpt-5.5 vision)를 fp당 1회 호출. `litellm.completion(num_retries=0)` + step `_execute` 루프에 재시도 없음. 첫 pass에서 fp_l11_exterior가 **duplicate marker NUMBER**(`validate_provider_output` line 358-359 hard blocker)로 `VlmProviderError`→`GeometryReadbackError`. 그 fp의 per_fp 엔트리는 `{error}`만, **`geometry` 키 없음**.
- 증거: 재실행으로 readback 12 ok 됨 → 영구 결함 아니라 **transient/stochastic** 확정.
- 외부 fp 상관: 외부 도면(yard/walls/terrace)이 마커 더 많고 모호 → duplicate 확률↑. 단 메커니즘은 generic, 게이팅은 모든 fp 동일 처리(외부 전용 코드 없음).

**C2 전파 — shot_aware가 실패 상태에서 빌드, 이후 재유도 안 됨.**
`assemble_planner_inputs` → `_index_geometry` (shot_aware_bg_render_plan.py:119-127)는 readback per_fp 엔트리에 **`"geometry"` 키 있는 fp만** 포함. 실패 fp는 키 없음 → 드롭 → shot_aware 11개만 (fp_l11_exterior 부재).
- shot_aware 완료(12:40) 후 readback이 resume(13:11)으로 fp_l11_exterior 고침. 그러나 RERUN_SELF/resume은 **downstream invalidate 안 함** → shot_aware는 stale 11개 plan 유지.

**C3 소비 — background_render가 plan 누락 시 fail-closed (all-or-nothing).**
`BACKGROUND_RENDER_REFERENCE_MODE=shot_aware_plan`이라 fp-anchored bg는 shot_aware plan 필수. plan None → `_build_opt_in_failed_entry`(background_render_step.py:978-1007), `render_attempts=0`.
- ★같은 step에 **비-shot-aware 렌더 경로가 이미 존재**: `surface_role_direct_plate`(text_only+prior_bg, line 900-976). site_surface bg(L10/L21)가 정상 사용. L11B01의 t2i_prompt도 이미 생성됨 — 게이트만 막음.

**캐스케이드.** partial background_render → 누락 bg 쓰는 scene이 StaleUpstreamError → coordinator가 나머지 future는 완료(46 still)하되 전파 → scene_image_pipeline **failed**. 단일 stochastic bg 실패가 에피소드 scene-image 단계를 incomplete로.

## 수정 옵션 (전부 generic / flag / 하드코딩0)

- **A (트리거) — readback step bounded retry.** per-fp 루프에서 `GeometryReadbackError` catch, `compute_readback` N회 재시도 (flag `floor_plan_geometry_readback_max_retries`, 기본 2). `_counter`가 매 VLM 호출 정직 카운트 → audit 보존. `num_retries=0`은 per-call audit용이라 step-layer retry와 직교. 첫 pass에서 self-heal. 결정론 제어흐름(TDD 유효). 가장 좁음. **주 추천.**
- **B (소비 안전망) — plan 누락 fp의 bg를 surface_role_direct_plate/text_only로 degrade.** t2i_prompt 이미 있음. flag. background_prompt overlay fix와 같은 철학. degrade bg가 catalog 들어가 partial→completed → cascade 해소. fidelity tradeoff(geometry ref 상실, 외부 bg엔 수용가능). **defense-in-depth.**
- **C (전파) — readback per_fp set 변하면 shot_aware invalidate.** 구조적 정답이나 step_runner resume 의미 변경 = broad/risky. clean 단일 run + A면 트리거 안 됨. **defer.**

추천: **A(주) + B(안전망)**, C defer. 둘 다 flag, default 결정은 Codex 의논 후.
