W21B Wave 2 Implementation Brief
W21B-wave-1에서 배경 plate의 tone/purity가 개선된 뒤, 다음 병목인 exterior/transition/site plate 누락을 좁게 복구하기 위한 구현 브리프다.
요약
이번 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_plan은 base_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_role은 background_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
- place_group / sub_region / adjacency DB schema 도입 없음.
- same-space layout consistency와
style_reference_new_spacerouter 분리는 W21B-wave-3. - per-shot scene PNG의 global cinematic tone, director coverage, shot sequencing은 W21A0/W21A1.
- scene_state_timeline, 시신 연속성, previous-shot reference 자동화는 W21E.
- entity-type-aware reference contract는 W21D-small. 이번 wave에 끼우지 않는다.
- LLM/VLM semantic gate 추가 없음. visual review와 deterministic sanity check만 사용한다.
- fresh project canary 없음. W20E7 project 재사용.
- downstream stale 5 step 자동 resume 없음. background plate 검증 뒤 별도 의논한다.
- 시나리오 literal, 금월도/옥탑방/마트/로트와일러 같은 고유 단어를 production logic 조건으로 쓰지 않는다.
- W21B-wave-1의 checkpoint-only reference audit을 behavior-changing logic으로 확장하지 않는다.
4. Touchpoints and Patch Shape
4.1 Master plan v6 pack
- 새 prompt pack:
prompts/_base/background_master_plan/6.YYYYMMDDHHmm/{schema.json, system.md, user_template.md}. backgrounds[].surface_role추가를 기본안으로 한다. 이유: exterior plate가 fp-less로 갈 경우 background 자체가 role을 carry해야 downstream prompt/render가 판정 가능하다.floor_plans[].surface_role은 이번 wave에서 추가하지 않는다. exterior/transition/site는 floor_plan stub을 만들지 않는 기본안이므로 redundant하다. wave-3 same-space layout router에서 필요해질 때 다시 검토한다.- prompt rule: role은 LLM semantic decision이다. literal outdoor keyword matching을 시스템 룰 또는 코드 source-of-truth로 쓰지 않는다.
- schema가 바뀌므로
BackgroundMasterPlanStep.SCHEMA_VERSION과step_manifest["background_master_plan"].schema_version을 함께 bump한다.
4.2 Raw validator
validate_master_plan_raw_intent가 surface_role enum을 검증한다.- 기존 invariant
background.depends_on_fpnon-empty는 role별로 완화해야 한다.interior_room은 기존처럼 required, exterior/transition/site는 optional을 허용한다. - 단, optional을 허용하면 fp link cross-check도 role-aware로 바뀐다.
depends_on_fp=[]인 plate는 fp_loc_space 검사를 건너뛰되 diagnostic에fp_policy="none_required"를 남긴다. - floor_plans[]는 여전히 fp-linked geometry를 뜻한다. single_space floor_plan 정확히 1개 invariant는 기존처럼 유지한다. exterior plate는 floor_plans[]에 넣지 않는다.
4.2a Catalog propagation
assign_bg_ids는 raw intent를 그대로 복사하지 않고 catalog entry field를 명시적으로 구성한다. 따라서surface_role을 catalog entry에 직접 복사해야 한다.surface_role은semantic_key에는 넣지 않지만, render/prompt policy에는 영향을 주므로compute_bg_catalog_hash의 render-relevant field에 포함한다.- 결과적으로 role만 바뀐 경우 bg_id는 안정적으로 유지되지만, background_prompt/background_render는 stale로 처리되어 role-specific prompt와 render path가 적용된다.
4.3 W20F6 filter replacement
- old W20F6 floor-plan scope helper를
_apply_w21b_surface_role_scope_filter로 교체한다. - 기존 reason
outdoor/low_shot/no_dep_bg를 backwards-compat 이름으로 유지하지 않는다. 새 policy는surface_role_requires_floor_plan,surface_role_allows_plate_only,no_consuming_background,low_consuming_shot같은 reason을 쓴다. - drop cascade는 유지한다. 다만 exterior background가
depends_on_fp=[]라면 fp drop cascade 대상이 아니어야 한다. - diagnostics key는 새
w21b_surface_role_scope_filter를 사용한다. W20F6-era key는 더 이상 current output으로 보존하지 않는다.
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될 수 있다.
기본 권고는 아래 순서다.
- Exterior/transition/site background는
depends_on_fp=[]를 허용한다. background_prompt는 fp PNG 없이도 prompt를 생성한다. role-specific surface guidance를 받아 plate-only prompt를 쓴다.floor_plan_overlay_payload는surface_role in {exterior_plate, transition_zone, site_surface}이고depends_on_fp=[]인 BG를 overlay 대상에서 skip한다.interior_roomfp-less는 기존처럼 fail-closed다.background_renderactiveshot_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=[])만 사용한다._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_fpfailure를 유지한다.- interior_room은 기존 W20B planner path를 그대로 유지한다.
이렇게 하면 W20B의 camera/reference graph를 exterior plate에 억지로 적용하지 않는다. exterior plate의 layout consistency는 이번 wave의 목표가 아니며, first plate 확보가 목표다.
4.5 Background prompt v9/v10
- surface_role을 background prompt 입력에 넣을 필요가 있다면
background_promptv9 pack을 만든다. v8을 직접 수정하지 않는다. - v9는 v8의 BG-only purity와 cinematic plate contract를 계승한다.
- screen/display residual guard를 같이 포함한다: TV/monitor/photo frame/screen은 physical fixture로 존재할 수 있지만, 화면 안 의미 컨텐츠는 blank, powered off, generic glare, unreadable UI, non-semantic reflection으로 처리한다. permanent signage/infrastructure로 명시된 경우만 예외다.
- v10은 v9 canary 후속 hotfix다. TV/monitor/CCTV/photo frame 내부를 black/off/blank/glare/static/unreadable blocks 중심으로 더 강하게 제한하고, news anchor/faces/maps/subtitles/readable UI/text/logos/story photos/event clues를 금지한다.
- schema output shape가 그대로라면
background_prompt_step.SCHEMA_VERSION은 유지하고 prompt selector/config hash만 바꾼다.
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는 하지 않는다.
- before snapshot: master_plan, floor_plan/render/readback 계열, background_prompt, background_render manifest와 floor_plan/background_chain PNG 백업.
background_master_planforce. 새 surface_role diagnostics 확인.- actual canary scope:
background_master_plan→floor_plan_prompt→floor_plan_render→floor_plan_overlay_payload→base_location_dossier→floor_plan_geometry_readback→shot_aware_bg_render_plan→background_prompt→background_render. master_plan 변경이 fp/readback/planner config hash에 영향을 주므로 이 9-step force가 가장 해석 가능했다. - image_call_cap: 30. 최종 v10 run은 background_prompt/background_render tail force에서 21/30 사용, denied 0.
- after snapshot과 compare HTML 또는 contact sheet 생성.
- 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
- prompt pack v6 load + schema parse.
surface_roleenum validator: valid 4개 통과, missing/invalid fail.interior_roombackgrounds는 기존depends_on_fpinvariant 유지.- exterior/transition/site backgrounds는
depends_on_fp=[]허용 + fp link validator skip. - scope filter helper: exterior role은
is_indoor=False만으로 drop되지 않는다. - drop cascade: dropped fp를 참조한 interior BG는 여전히 drop되고 orphan
depends_on_fp가 남지 않는다. - schema bump sync:
BackgroundMasterPlanStep.SCHEMA_VERSION과step_manifestentry 일치. - background_prompt v9를 만들 경우 selector/config Literal/update tests 통과.
- 이 sanity check는 schema/validator/filter shape 확인용이다. wave 완성도 평가는 visual acceptance로만 판단한다.
git diff --checkclean.
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/.env를 os.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
- visual acceptance가 명확히 나빠지면 rollback은 prompt selector와 forced checkpoints 기준으로 한다. 기존 v8/v7 pack은 보존되어야 한다.
- exterior plate가 master_plan에는 생겼지만 render에 도달하지 못하면, code rollback보다 first fix는 render path diagnostic이다.
- image cap 초과 시 scene downstream은 건드리지 말고 background_render 결과만 보고한다.
- fresh project canary 또는 downstream resume는 이 wave closure 뒤 별도 의논으로 넘긴다.
- root duplicate PDF 같은 사용자 파일은 건드리지 않는다.
12. Claude Review Checklist
- surface_role을 backgrounds에만 넣고 floor_plans에는 넣지 않는 narrow 기본안에 동의하는가?
- exterior plate를 floor_plan stub이 아니라 background-only/direct plate queue로 두는 데 동의하는가?
- W20B shot_aware_plan은 interior_room에 한정하고 exterior fp-less BG는 직접 render queue로 보내는 설계가 narrow한가?
- screen/display content guard를 v9에 묶는 것이 wave-1.1 별도 hotfix보다 나은가?
- canary cap 30과 W20E7 BG-only 재실행 범위가 적절한가?