TheRoad Scene Lab · W21B-wave-4 · 2026-05-30 · Claude 초안 → Codex cross-review 합의 반영
DRAFT v0 DOC ONLY — 코드/DB/render 변경 0 design brief = why/schema SOT
shot_projection_card의 왜 / schema는
docs/w21b-wave4-shot-projection-card-20260530/index.html (design brief v0, §1~§10 lock)이 SOT다.
pack(prompts/_base/shot_projection_card/1.202605302212/)·dry A/B/C·real-BG E2E(b2)·사용자 육안(8797 "fp랑 배경 정합 좋아졌어")까지 PASS했다.
본 문서는 그 위에서 "정확히 어느 파일 / contract가, 어떤 순서·acceptance로 바뀌는가"만 다루는 production integration blueprint다.
여전히 코드/DB/API/render 변경은 0이며, 변경의 명세만 동결한다.
Scope: shot_projection_card를 production 파이프라인에 default-OFF로 끼워넣기 위한 step 등록 / config / manifest / contract delta / cache / acceptance matrix / rollout 순서.
render_action / reuse_target_bg_id / route_render_actions) 재정의.변경 대상 파일과 그 성격. order/flag는 backend/app/core/step_manifest.py·config.py grep 실측.
| 파일 | 변경 | commit |
|---|---|---|
backend/app/core/steps/shot_projection_card_step.py | 신규 step (semantic_readback_step.py 패턴 미러). SCHEMA_VERSION/PROMPT_VERSION 상수 + provider 호출 + validator. | C2 |
backend/app/modules/pipeline/shot_projection_card.py | 신규 순수 로직: card envelope 조립 / source_hash / deterministic gate / leakage check. | C2 |
backend/app/modules/pipeline/shot_projection_card_provider.py | 신규 real VLM provider(default 미사용; _real_provider_enabled gating). | C2 |
backend/app/core/step_manifest.py | card entry order 21.593 추가(semantic 21.591 < card < plan 21.595). | C2 |
backend/app/core/config.py | 3-flag 추가: shot_projection_card_enabled=False / shot_projection_card_real_provider_enabled=False / shot_projection_card_prompt_version="1". | C2 |
backend/app/core/steps/__init__.py | registry 등록("shot_projection_card": ShotProjectionCardStep). | C2 |
shot_aware_bg_render_plan_step.py + plan module | plan vNext: card-aware fields 추가, camera_decision demote(§5). | C3 |
background_prompt step/module | anchor card bg_plate_visible_description 주입 consumer(§6). | C4 |
scene_detail step/module | 같은 card scene_visible_description + card_hash 소비(§7). | C5+ |
현 manifest 순서 (실측 order): floor_plan_prompt 19.61 → floor_plan_render 21.55 → overlay_payload 21.57 → base_location_dossier 21.58 → geometry_readback 21.59 → semantic_readback 21.591 default OFF → shot_projection_card 21.593 (신규) → shot_aware_bg_render_plan 21.595 → background_prompt 21.60 → background_render → scene_detail 21.70.
shot_projection_card| 항목 | 값 |
|---|---|
| step id | shot_projection_card |
| order | 21.593 — semantic_readback(21.591) 이후 / plan(21.595) 이전 (design brief §10 결정1) |
| default | OFF — 3-flag 전부 false/"1". 첫 land=dry/schema only, real VLM은 explicit force/cap(기존 wave 패턴) |
| granularity | (bg_id, shot_id) per-shot(design brief §4.1) |
| 입력 | 성격 | 없을 때 |
|---|---|---|
floor_plan_render (detailed FP PNG) | hard dep — BG visual anchor / substrate | card 생성 불가 → skip |
floor_plan_overlay_payload (번호/label legend) | hard dep — VLM 입력 legend | card 생성 불가 → skip |
base_location_dossier | hard dep — expected_label SOT | card 생성 불가 → skip |
floor_plan_geometry_readback | hard dep — marker grid sanity(deterministic grounding) | card 생성 불가 → skip |
floor_plan_semantic_readback | optional gate — enabled면 gate 입력, disabled면 pass-through | not hard dep. disabled → semantic_gate_state=not_available |
floor_plan_prompt.camera_recommendations | hard dep — pose 후보(VLM 선택·서술, 생성 아님) | card 생성 불가 → skip |
| light_fp analysis raster | substrate(있으면 grounding↑) | detailed FP fallback + confidence downgrade/needs_review(design brief §10 결정5) |
state=needs_fix(FP가 dossier에서 drift) → card fail-closed(§9).
enabled & pass/needs_review → 통과(needs_review는 diagnostic).
disabled → semantic_gate_state=not_available, hard 전제로 쓰지 않음.
projection_card_state = not_applicable로 기록하고 기존 plate-only / direct path로 빠진다.
이는 card 실패가 아니다 — §9 acceptance matrix에서 별도 행으로 취급.
step의 SCHEMA_VERSION ↔ pack schema.json, PROMPT_VERSION ↔ pack dir(1.202605302212) 동기. semantic_readback_step이 manifest 주석에 명시한 sync 의무와 동일 패턴.
2-pass로 VLM 콜이 늘어나므로 cache가 필수다. active 21 전부가 아니라 변경된 FP/BG부터 재실행할 수 있어야 한다(design brief §6).
source_hashes = {
fp_render_hash, # detailed FP PNG
substrate_hash, # light_fp (or "not_available")
overlay_hash,
geometry_hash,
semantic_hash, # or "not_available" (gate disabled 시)
camera_rec_hash,
shot_context_hash, # ★ raw text 아님 = normalized (shot text/shot_guides/visible_entities)
prompt_version, schema_version, model, provider
}
card_cache_key = hash(source_hashes + bg_id + shot_id)
| 항목 | 결정 |
|---|---|
| shot text 포함? | YES — 정합 SOT이므로 입력 변경이 card를 무효화해야 함(design brief §10 결정3). 단 raw 금지, shot_context_hash로 normalize. |
| invalidation trigger | 위 source_hash 中 하나라도 변경 → card 재생성. prompt/schema version bump도 trigger. |
| changed-only rerun | cache hit이면 VLM 콜 skip, 기존 card envelope 재사용. |
| 저장 위치 | semantic_readback sidecar/cache 패턴 미러(구현 세부는 C2에서 확정). card envelope이 provenance(card_id/hash/state) 포함. |
shot_aware_bg_render_plan(21.595)는 카메라 결정에서 손 떼고 reference graph / reuse / render_action 전역 결정만 한다. 단 v0에서 기존 필드를 삭제하지 않는다.
camera_decision — v0 삭제 금지. authority는 card로 demote하되 shape 유지. 이유: ① 현 validator가 camera_decision 필수 shape 요구 ② route_render_actions가 camera_unit/look_at_unit으로 reuse 결정 ③ background_prompt 소비자 호환. 즉시 제거 시 blast radius 큼(코드 교차확인).render_action / reuse_target_bg_id — W21B-w3 contract. card wiring에서 재정의 금지.| 필드 | 의미 |
|---|---|
anchor_shot_id | plate별 대표 shot. background_render가 이 shot의 card만 주입(sibling은 diagnostic). |
projection_card_id | 주입할 anchor card 식별자. |
projection_card_hash | 소비자(C/D)가 같은 card 따르는지 검증용. 불일치 → diagnostic/fail-closed. |
projection_card_state | pass | needs_review | blocked | not_applicable(fp-less). |
projection_card_fallback_reason | fail-closed 시 사유(low_confidence / missing_inputs / semantic_needs_fix / stale / leak / contradiction). |
projection_card_source_bg_id | reuse 상속 시 실제 픽셀을 만든 target bg_id(=reuse_target_bg_id). non-reuse면 self. |
projection_card_inherited | true면 이 plate가 target anchor card를 상속한 reuse(§8 decision-lock). |
planner 주 역할 = reference graph / reuse / render_action + 어떤 card를 같은 plate로 묶을지 / anchor 선택. camera_decision은 demote된 audit/compat field.
| 항목 | 내용 |
|---|---|
| 주입 대상 | plate의 anchor shot card의 bg_plate_visible_description — plate-only(base 구조/고정 가구/재질/조명/framing만, transient 제외). |
| 주입 방식 | card prose를 BG t2i_prompt에 자연스럽게 통합(design brief §3.1 C). full scene_visible_description은 BG에 쓰지 않음(transient 누수 방지). |
| leakage guard | internal token(marker 번호 / 영어 enum literal / card_id) exact 누출 0 검사(design brief §5.1). 위반 시 fail-closed. |
| fail-closed | card blocked/stale/leak/semantic_needs_fix → card 주입 안 하고 기존 v10 prompt path로 fallback(design brief §5.2). image 검증 완료된 v10이 안전망. |
BG와 최종 scene t2i가 같은 shot contract를 따르게 하는 정합 SOT 단계.
| 항목 | 내용 |
|---|---|
| 소비 필드 | scene_visible_description(FULL — base + transient 모두) + card_hash. |
| 정합 검증 | scene_detail의 card_hash가 BG가 쓴 anchor card_hash와 같은지 확인 → 같은 SOT 보장. |
| phase 분리 | scene_detail consumer는 C5+ 별도 phase. BG path(C2~C4)가 안정된 후 land(Codex 보강 #4). |
| edge | 처리 |
|---|---|
| fp-less fallback | projection_card_state=not_applicable → plate-only/direct path. 실패 아님(§3.2). |
| same-space / reuse (L20 edge) | W21B-w3 reuse alias 유지 → image call 0. ★ decision-lock(v0, Codex review): reuse plate는 target anchor card를 상속한다(별도 card 안 만듦). 실제 픽셀을 만든 건 target이므로 provenance도 target을 가리켜야 함. enum 안 늘리고 projection_card_state=pass + projection_card_source_bg_id=reuse_target_bg_id + projection_card_inherited=true 기록. child shot 자체의 scene_visible_description card는 scene_detail/I2I용 diagnostic로만(BG plate block 조건으로 쓰지 않음 — image 0이 W21B-w3 contract 핵심). |
| transient split | card schema가 marker_layer(base/transient/ignored)를 echo. C(BG)=base-only(bg_plate_visible_description), D(scene)=full(scene_visible_description). 코드가 prose를 slice하지 않음 — VLM이 layer 알고 분리 작성(schema §3b). |
| multi-shot BG anchor 선택 | plan vNext(B)가 plate별 anchor 1개 선택. sibling card는 compatibility diagnostic(§9). |
| sibling diagnostic | anchor 아닌 shot card는 BG 주입 안 함. anchor와 모순되면 diagnostic 기록(v0 block 아님). |
| 입력 조건 | card_state | BG path |
|---|---|---|
| card pass + anchor selected + leak 0 + hash match | pass | background_prompt vNext path (card 주입) |
card blocked / missing / stale(hash mismatch) / leak / semantic needs_fix / self_consistency=contradictory | blocked | v10 fallback (검증된 기존 prompt path). fallback_reason 기록. v0=fail-closed |
card 생성됐으나 confidence 낮음 / semantic needs_review | needs_review | v0=diagnostic only(block 아님). card 주입하되 needs_review 플래그. 후속 hard gate에서 강화 |
| fp-less BG | not_applicable | direct/plate-only fallback. card 실패로 취급 안 함 |
| sibling-only fail(anchor는 pass) | anchor=pass | BG plate block 금지. sibling은 diagnostic only |
| same-space reuse (decision-lock: 상속) | pass + inherited=true | image call 0 유지. projection_card_source_bg_id=reuse_target_bg_id provenance 기록(§8) |
self_consistency=contradictory self-report는 blocked → v10 fallback(prose가 structured와 모순이면 BG에 주입 금지, D dry/validator sketch 기준). confidence 낮음·semantic needs_review만 needs_review diagnostic. 코드 레벨 deep contradiction 검증은 후속.
| commit | 내용 | 테스트 |
|---|---|---|
| C1 | doc-only wiring brief (본 문서) | — |
| C2 | step/config/manifest registration default OFF + card module + provider(미사용) | deterministic validator tests(envelope shape / source_hash / leakage / gate) |
| C3 | plan vNext anchor fields(anchor_shot_id 등) + camera_decision demote | dry no-real-call tests(plate grouping / anchor 선택 / reuse 상속 결정) |
| C4 | background_prompt vNext consumer + fail-closed | leakage / fallback(v10) tests |
| C5+ | scene_detail / I2I consumer (별도 phase로 분리 가능) | card_hash 정합 tests |