W21B Wave 2 Implementation Brief

W21B-wave-1에서 배경 plate의 tone/purity가 개선된 뒤, 다음 병목인 exterior/transition/site plate 누락을 좁게 복구하기 위한 구현 브리프다.

작성일: 2026-05-28
상태: 구현 + canary closure brief
기준 문서: docs/w21-background-first-plan-20260528/index.html
검증 대상: W20E7 project BG-only canary

요약

이번 wave의 목표는 W20F6에서 생긴 indoor AND shot_count>=2 AND dep_BG_count>=1 hard filter를 surface_role 기반으로 완화해, 옥상/외부 계단/마트 외부/deck 같은 exterior 또는 transition plate를 다시 배경 생성 대상에 올리는 것이다.

핵심 구현 축은 background_master_plan이다. LLM raw intent에 surface_role을 추가하고, W20F6 filter를 surface-role aware로 바꾼다. background_render legacy 경로는 이미 fp_path=None 렌더를 허용하지만, 현재 W20 opt-in shot_aware_plan 경로는 fp 단위 planner에 묶여 있으므로 exterior plate를 fp-less로 밀 때는 별도 우회 또는 최소 stub 정책이 필요하다.

이번 wave는 place_group/sub_region DB schema를 만들지 않는다. 먼저 surface_role만으로 exterior plate 누락이 해결되는지 확인한다.

1. Current State

영역 현재 사실 W21B-wave-2 영향
Master plan schema prompts/_base/background_master_plan/5.202605201759/schema.json에는 surface_role이 없다. floor_plans/backgrounds는 loc_id, space_key_hint, depends_on_fp 중심이다. v6 pack 추가 + validator 업데이트가 필요하다.
W20F6 scope filter W20F6 hard filter가 is_indoor=False면 reason outdoor로 floor_plan과 dependent BG를 drop했다. direct root cause. 구현에서는 _apply_w21b_surface_role_scope_filter로 교체했다.
Render legacy path background_render_step.py legacy render는 fp_first가 없거나 fp_path가 없으면 fp_path=None으로 render_one_background 호출 가능하다. legacy fallback은 이미 plate-only 렌더에 가깝다. 큰 변경 금지.
W20 shot-aware path shot_aware_bg_render_planbase_location_dossier와 geometry/readback이 있는 fp_id 단위 bundle만 계획한다. background_render의 active opt-in path도 depends_on_fp[0]로 BG를 묶는다. exterior fp-less plate는 direct plate queue로 분기했다. 이 과정에서 floor_plan_overlay_payload도 fp-less non-interior BG를 skip하도록 보강했다.
W21B-wave-1 residual L05B07의 TV 화면 안 뉴스 컨텐츠처럼 physical display 자체가 아니라 display 내용이 BG plate에 의미론적으로 베이크되는 잔여 issue가 있었다. v9에 screen/display guard를 넣었고, canary에서 L14B02 monitor가 남아 v10으로 guard를 강화했다.
W21B-wave-1 baseline 기준 chain_bg는 12장: L05 6장, L09 3장, L13 2장, L20 1장. 사용자 1차 review는 "이전보다 좋아짐". wave-2 acceptance의 no-regression 기준이다.

2. Scope

기본 방향: surface_rolebackground_master_plan raw intent에서 생성한다. dossier/overlay 단계에서 파생하지 않는다. W20F6 filter가 master_plan 후처리 단계에 있으므로, filter가 읽을 수 있는 가장 이른 producer가 master_plan이다.

2.1 surface_role enum

surface_role 의미 floor_plan 필요성 예상 plate
interior_room 실내 방, 사무실, 조타실처럼 구조/가구/동선이 floor plan과 강하게 연결되는 공간. 필수. 기존 W20B path 유지. L05 옥탑방 내부, L09 마트 내부, L13 경찰서, L20 조타실.
exterior_plate 외부 facade, 거리, 옥상, deck, 마트 외부처럼 reference plate는 필요하지만 실내 도면은 부자연스러운 표면. 선택. 기본은 plate-only. 옥탑방 외부/옥상, 마트 외부, deck.
transition_zone 계단, 문턱, 입구, 복도-외부 사이처럼 내부/외부를 연결하는 이동 표면. 선택. 구조 marker가 있으면 fp stub 허용. 외부 계단, 건물 입구, 마트 입구.
site_surface 건물/부지 주변의 넓은 환경. orientation/establishing용 plate. 불필요. wide establishing text/photo plate 중심. 골목, 주변 주거지, 항구 주변.

2.2 Proposed keep rule

기존 W20F6 rule은 너무 강하다. wave-2에서는 background 후보를 먼저 surface_role로 판정하고, floor_plan trim은 interior_room background가 실제 참조하는 fp에 한정한다.

조건 대상 role 판정
background가 consuming shot 0개 all drop 또는 not_applicable. render 대상이 아니다.
surface_role == interior_room interior_room 기존 fp-linked path 유지. depends_on_fp가 필요하며, 그 fp가 살아남아야 한다.
surface_role in {exterior_plate, transition_zone, site_surface} exterior/transition/site is_indoor=False만으로 drop하지 않는다. applies_to_shots 또는 background의 consuming shot이 1개 이상이면 keep.
surface_role missing/invalid all fail closed. LLM retry 대상. 코드가 literal keyword로 보정하지 않는다.

diagnostics는 silent drop을 금지한다. 기존 reason 이름을 보존하려고 끌고 가지 않는다. 새 diagnostics는 dropped_floor_plans[] / dropped_backgrounds[]surface_role, surface_role_policy, reasons를 함께 남긴다.

3. Non-goals

4. Touchpoints and Patch Shape

4.1 Master plan v6 pack

4.2 Raw validator

4.2a Catalog propagation

4.3 W20F6 filter replacement

4.4 Exterior plate path

중요: legacy background_render는 fp 없이도 렌더 가능하지만, 현재 opt-in shot_aware_plan path는 fp/dossier/geometry/readback에 묶여 있다. wave-2 구현에서 이 차이를 무시하면 exterior plate가 master_plan에는 살아남아도 render 단계에서 bg has no depends_on_fp 또는 planner missing으로 skip될 수 있다.

기본 권고는 아래 순서다.

  1. Exterior/transition/site background는 depends_on_fp=[]를 허용한다.
  2. background_prompt는 fp PNG 없이도 prompt를 생성한다. role-specific surface guidance를 받아 plate-only prompt를 쓴다.
  3. floor_plan_overlay_payloadsurface_role in {exterior_plate, transition_zone, site_surface}이고 depends_on_fp=[]인 BG를 overlay 대상에서 skip한다. interior_room fp-less는 기존처럼 fail-closed다.
  4. background_render active shot_aware_plan 경로에서 surface_role != interior_room이고 fp가 없는 BG는 shot_aware_plan 그룹 밖의 direct plate queue로 처리한다. direct plate queue는 render_one_background(..., fp_path=None, prior_bg_paths=[])만 사용한다.
  5. _run_shot_aware_plan_queue의 partition은 surface_role-aware가 되어야 한다. interior_room은 planner queue, 그 외 role + fp 부재는 direct plate queue, interior_room + fp 부재만 기존 bg has no depends_on_fp failure를 유지한다.
  6. interior_room은 기존 W20B planner path를 그대로 유지한다.

이렇게 하면 W20B의 camera/reference graph를 exterior plate에 억지로 적용하지 않는다. exterior plate의 layout consistency는 이번 wave의 목표가 아니며, first plate 확보가 목표다.

4.5 Background prompt v9/v10

5. Decision Questions Before Code

질문 권고 이유
surface_role을 어디에 둘 것인가? backgrounds only. fp-less exterior plate는 background 자체가 role을 carry해야 한다. floor_plans role은 이번 wave에서 redundant하고 wave-3에서 재검토한다.
exterior plate에 floor_plan stub을 만들 것인가? 기본은 no. background-only plate. stub fp는 floor_plan_prompt/render/readback/dossier/planner를 모두 통과시키는 큰 변경이다.
shot_aware_plan을 exterior plate에 적용할 것인가? no. exterior fp-less는 direct plate queue. W20B graph는 interior fp geometry를 전제로 한다. exterior first plate에는 과하다.
v9 prompt pack이 필요한가? yes, surface_role을 prompt에 넣고 screen guard를 묶는다면 v9. v8 canary 결과를 보존하고 rollback을 쉽게 한다.
surface_role을 semantic_key에 넣을 것인가? no. bg_id 안정성을 위해 기존 semantic_key인 loc_id/space_key/time_phase/state_class를 유지한다. role은 policy/diagnostic/context다.

6. Canary Plan

실행 단위: W20E7 project 4f948193-6809-4ae3-a3c6-2ca4e8af1c1a / episode dc70c0b3-5c09-4664-8c0f-9cac38c0c6ca 재사용. fresh project canary는 하지 않는다.

  1. before snapshot: master_plan, floor_plan/render/readback 계열, background_prompt, background_render manifest와 floor_plan/background_chain PNG 백업.
  2. background_master_plan force. 새 surface_role diagnostics 확인.
  3. actual canary scope: background_master_planfloor_plan_promptfloor_plan_renderfloor_plan_overlay_payloadbase_location_dossierfloor_plan_geometry_readbackshot_aware_bg_render_planbackground_promptbackground_render. master_plan 변경이 fp/readback/planner config hash에 영향을 주므로 이 9-step force가 가장 해석 가능했다.
  4. image_call_cap: 30. 최종 v10 run은 background_prompt/background_render tail force에서 21/30 사용, denied 0.
  5. after snapshot과 compare HTML 또는 contact sheet 생성.
  6. downstream scene steps는 자동 resume하지 않는다.

7. Visual Acceptance

통과/실패는 사용자 + Codex visual review로 판단한다. grep 토큰, literal substring, LLM/VLM semantic judge는 이번 wave의 acceptance가 아니다.

통과 기준 실패 신호
Exterior plate recovery 이전 W20E7에서 chain_bg 0이었던 exterior/transition/site surface가 1개 이상 PNG로 생성된다. master_plan에는 남았지만 background_render에서 skip, 또는 여전히 외부 plate 0.
Existing BG no regression W21B-wave-1에서 좋아진 L05/L09/L13/L20 12 BG의 purity가 무너지지 않는다. 손/팔/얼굴/시신/현재 사건 흔적이 다시 BG plate에 보임.
Screen/display guard TV/monitor/photo frame은 물체로만 남고, 내부 화면 의미 컨텐츠는 non-semantic 처리된다. 뉴스 앵커, 사건 사진, 인물 얼굴, 텍스트 UI가 BG 자체에 베이크됨.
Role sanity surface_role diagnostics가 사람이 보기에도 맞다. interior/exterior/transition/site 샘플을 각각 spot-check한다. 실내가 exterior로, 외부 계단이 interior_room으로 분류되는 등 prompt-level confusion.
No scenario-specific logic production code/prompt rule에는 특정 작품, location label, 한국어 키워드 list가 source-of-truth로 들어가지 않는다. 옥상/마트/deck 같은 literal을 조건문으로 직접 분기.

8. Deterministic Sanity Check

9. Sub-steps and Commit Units

Commit 내용 비고
Commit 1 background_master_plan v6 + surface_role schema/validator + surface-role-aware scope filter. LLM output shape, schema bump, bg_catalog surface_role carry/hash, diagnostics, helper rename, and deterministic guards.
Commit 2 background_prompt v9/v10 + surface plate prompt context + screen/display content guard. v9 surface_role prompt context, fp-less prompt branch, v10 screen/display guard hotfix, and v6/legacy smoke pin.
Commit 3 exterior direct plate queue + fp-less overlay skip + stale chain_bg verify metadata. _run_shot_aware_plan_queue partition, floor_plan_overlay_payload fp-less non-interior skip, and write-free extra row/file diagnostics.
Commit 4 docs and closure retrospective. canary 1~4 results, active-only URL, stale list, and retrospective items.

실제 delivery 는 단일 PR / 4개 분리 commit 으로 정리했다. canary 는 implementation commit 적용 뒤 실행했고, 마지막 docs commit 은 결과와 retrospective 를 고정한다.

10. Canary Results and Retrospective

Run 결과 후속 처리
1차 181311 master_plan/floor_plan_render까지 진행. fp-less BG 4개가 확인됐지만 floor_plan_overlay_payload가 모든 BG에 depends_on_fp를 요구해 fail. floor_plan_overlay_payload fp-less non-interior skip patch 추가.
2차 overlay skip은 통과. standalone runner가 backend/.envos.environ에 로드하지 않아 VLM provider에서 OPENAI_API_KEY missing. runner-only dotenv load 보강. production settings 변경 없음.
3차 184718 mechanical pass. chain_bg 12 → 26, active 21. fp-less direct plate 4개 생성. v9 visual에서 screen content guard가 L14B02 monitor에는 약했다. v10 prompt hotfix 작성.
4차 v10 195936 background_prompt + background_render completed. cap 21/30, denied 0. active 21 set 기준으로 L05B02 TV blank, L14B02 monitor abstract mosaic. 사용자 review용 active-only compare 생성. closure 기준. stale 5 row/file은 deletion 없이 verify metadata로 노출.

최종 active-only artifact: /tmp/w21b_wave2_bg_canary_20260528_195936/compare_active.html. 외부 URL은 http://192.168.35.42:8769/w21b_wave2_bg_canary_20260528_195936/compare_active.html.

최종 active BG는 21개이며, surface_role 분포는 exterior_plate 5 / interior_room 13 / site_surface 2 / transition_zone 1이다. fp-less direct plate는 L04B02, L09B04, L09B05, L15B02다.

stale chain_bg row/file은 5개: L05B01, L05B07, L09B02, L09B03, L20B03. production loader와 verify completion은 active checkpoint의 data.groups 기준으로 동작하므로 runtime blocker는 아니다. 다만 visual review/UI audit 혼선을 막기 위해 background_render.verify_completion() metadata에 extra row/file 진단을 추가했다. 삭제는 하지 않는다.

Retrospective: brief 작성과 cross-review에서 floor_plan_overlay_payload fp-less consumer를 놓쳤다. runner는 production server와 달리 dotenv를 명시 로드해야 했다. canary scope/cap/backup 산정은 초기에 floor_plan 재렌더 비용과 실제 artifact path를 과소평가했다. v9 visual review에서는 stale L05B07을 active failure처럼 해석해 active-only artifact가 필요해졌다.

11. Rollback and Stop Conditions

12. Claude Review Checklist

  1. surface_role을 backgrounds에만 넣고 floor_plans에는 넣지 않는 narrow 기본안에 동의하는가?
  2. exterior plate를 floor_plan stub이 아니라 background-only/direct plate queue로 두는 데 동의하는가?
  3. W20B shot_aware_plan은 interior_room에 한정하고 exterior fp-less BG는 직접 render queue로 보내는 설계가 narrow한가?
  4. screen/display content guard를 v9에 묶는 것이 wave-1.1 별도 hotfix보다 나은가?
  5. canary cap 30과 W20E7 BG-only 재실행 범위가 적절한가?