# P2 진단 계획 (Codex 합의, 2026-07-01) — 코드 전 진단 우선

프로젝트 a7f80ab9 / ep 286f3ba4. S15=해안가 버스정류장, S19=마트(sh5 broken), S6=해안가도로(outdoor 체인 발동됨), S12=옥탑방시신.
★시나리오 의존 금지. 게이팅 완화는 canary+육안 반복(TDD 결정론만). P2 커밋은 P0(3538bd81)/P1(44b4f7e9)과 분리.

## 우선순위 & 방법 (Codex)
### 1. 4a/4b outdoor/indoor guide under-generation 진단
- S15가 왜 outdoor aerial→blocking→sketch 후보/attach에서 탈락했는지 **manifest + candidate signals + judge decisions + generated image calls를 테이블로** 뽑기.
- "복잡샷=실내외 무조건 마네킹" 사용자요구 vs 현 default-deny 게이트 차이 분해. ★바로 전샷 강행으로 열지 말고: **candidate 생성 기준 / judge admit 기준 / attach 기준** 중 어디가 과소인지 분리.
- 참고: outdoor shared_model은 cross-shot 후보그룹(same scene+loc, valid cam 2+) 필요. detect_site_seeds seed0 원인=scene_director가 outdoor location을 present_entity_ids엔 넣고 VE(visible_entity_ids=frame-visible)엔 안 넣음([[session-20260629-phase2-rebase-v2-committed]] dormancy=by-design 2026-05-13 frame-visible SOT). registered_pose_guide(실내)는 immobilized_subject anchor 게이트(dead/injured만). indoor_pose_guide는 shared-model precompute(batch main thread).
- 관련 파일: outdoor_site_layout_step.py(shared_model_candidate_groups/shot_complexity_signals/judge_shared_model_guide), visual_continuity_anchor_step.py(registered attach), indoor_shared_pose_guide_context.py.

### 2. 3a background_render prev/related bg reference 연결 리뷰
- bg 생성 lineage/prev-bg 참조 누락이 (a)pipeline_graph 복원 문제 vs (b)background_render가 실제 입력으로 prev/related bg 안 씀 문제인지 분리.
- SOT=checkpoint background_render.data.groups[*] + ImageAsset input_image_ids/pipeline_metadata. 라벨 파싱 금지.

### 3. 4d S19 sh5 broken(수리영 벽 갇힘) 재생성
- 원인 진단 후 targeted regen. ★먼저 scene prompt/ref/input lineage 저장해 broken 원인=guide 누락 vs bg/ref 오염 확인.

## ★★ 4a 완전 진단 (2026-07-01, SOT=outdoor_site_layout checkpoint diagnostics)
전체 outdoor shared-model **딱 1번 발동=S1sh4(숲, 씬1)** = 사용자가 "안 중요"라 한 산. seed_group_count=1(osl-l01만). image_calls=base1/blocking1/sketch1(=실제 outdoor guide 3개).

**병목=detect_site_seeds(outdoor_site_layout_plan.py:111). candidate/judge/attach는 정상(S1sh4 admit=true single_shot_complexity high).** candidate 입력 member_keys(step:1271)는 오직 seed 그룹 멤버 → cross-shot도 single_shot_complexity_candidates(plan:1105)도 seed 밖 샷은 절대 후보 안 됨. seed 못 만들면 layout 미생성→complexity signal 없음→candidate 0.

seed 조건(plan:131-156): 선택샷 + VE에 outdoor location(L##, frame-visible) + non-zoom + **character_angles≥2(2+figure)**.
- S15 sh1: staging angles=1(수리영 혼자) framing=wide, VE=L11 있음 → **2+figure 게이트 탈락**.
- S15 sh5: staging angles=2(혜수+수리영) framing=wide, but VE=C02만(location L11 없음) → **location-in-VE 게이트 탈락**(scene_director가 present엔 넣고 frame-visible VE엔 안 넣음=2026-05-13 SOT).
- S1sh4(발동): angles=2 + location VE 있음 → 통과. single_shot_complexity가 이 seed멤버 중 복잡샷 픽.
- skipped 로그=S6sh1/S9sh1/S24sh1(single_figure_moving), S28sh1(zoom). S15는 로그조차 없음(비이동 1인/location無는 silent).

single_shot_complexity_candidates pre-filter(plan:1134-1143): valid camera + summary + entity_count≥1 + is_complex(multiple figure OR depth_planes≥2 OR has_motion). ★단 member_keys(seed멤버)에서만 → seed 없으면 무의미.

**4a fix 방향(Codex 의논): 사용자 요구="한샷이라도 구도/복잡 있으면 실내외 무조건 마네킹". 현 gate 2개가 과소:**
(A) seed 2+figure 요구 완화 → 1인 복잡/구도샷도 seed(staging framing/camera 복잡 or composed 신호). 위험=과발동(S1 숲처럼).
(B) location-in-VE → present_entity_ids(scene-present)도 seed 대상(sh5 케이스). 위험=과발동/dormancy trade-off(메모리 기록).
(C) 둘 다. ★단 layout chicken-egg: single-shot complexity signal(depth_planes)은 layout 필요→layout은 seed location 필요. 그래서 seed 자체를 넓혀야(단순 후보만 넓히면 layout 없어 무효).
★4b(실내 마네킹 과소)=별도 gate: registered_pose_guide=immobilized(dead/injured)만, indoor_pose_guide=shared-model precompute. 실내 일반 복잡샷 마네킹 경로 존재여부 별도 진단 필요.

## ★★ 4d 진단 = 4a의 증상 (2026-07-01)
S19 sh5(3d0e0f5b) 프롬프트="Overhead high angle steeply down from exterior wall, 수리영 chin raised facing lens, plain mart exterior wall drops vertically behind her, steep height difference, tile floor far below". VE=L08(마트 외부 거리 outdoor)+C01(수리영). lineage=배경plate+face ref만, **composition/pose guide 없음**. → 극단 오버헤드+수직벽 복잡구도의 단일 figure 아웃도어 샷인데 detect_site_seeds 2+figure 게이트로 seed 안 됨 → guide 미발동 → T2I가 "벽 사이 갇힘" 구도. **4a/4b/4d = 하나의 근본**(단일 복잡/구도샷 마네킹 게이트 과소, 실내외 공통). 4a fix로 seed 넓히면 S19 sh5도 guide 받음 + targeted regen 필요.

## ★★★ 4a/4b/4d fix 계획 (Codex 합의 2026-07-01) — C: deterministic seed 확장 + judge/QC fail-closed
**병목=seed/candidate 생성 전단(judge 아님). 방향=복잡/구도 후보를 seed에 올리고 judge/QC가 마지막 안전망(전샷 강행 X).**
1. **outdoor seed 2-lane 분리**(detect_site_seeds):
   - cross_shot_continuity: 기존(same location 2+ selected, camera/framing 차이). ★location source를 frame-visible VE만 아니라 primary_location/scene-present도 fallback 허용.
   - single_shot_complexity: selected outdoor shot 1개라도 후보화. deterministic prefilter 좁게: outdoor location evidence + figure_count≥1 + staging/camera 복잡신호(2+ chars OR gesture/action/motion OR non-trivial depth/framing/camera movement/fg-bg relation). ★layout 없으니 shot_staging/scene_director.primary_location/render card/bg binding 구조필드만.
2. **location-in-VE=B로 완화**: primary_location outdoor면 frame-visible VE에 location 없어도 seed 후보. metadata `location_source: frame_visible|primary_location|scene_present`. judge payload에 source 넣어 non-frame-visible은 더 엄격히(구조필드, 라벨파싱 X).
3. **pre-seed LLM judge 반대**: seed 전 LLM X(비용/지연/layout없어 품질애매). deterministic broad seed→기존 shared-model judge가 single_shot_complexity까지 admit.
4. **"무조건 마네킹" 해석**: 복잡샷이 seed에서 조용히 탈락 금지→반드시 candidate+judge까지. 단 final attach=candidate AND judge admit AND guide/QC pass 유지(trivial 강행=guide harm 재발 방지). judge가 single_shot_complexity를 정상 attach lane 인정.
5. **indoor 동일 철학**: bg plate 이미 있으니 same bg_id/camera plate + single-shot complexity lane. cross-shot 그룹만 보지 말고 selected indoor shot 단독이라도 figure≥1+gesture/contact/support/multi-depth/framing complexity면 candidate(hand/contact류 single-shot lane).
6. **검증순서**: ①dry-run/manifest로 S15 sh1/sh5가 candidate+judge_decision 찍히는지 ②targeted generation S15 aerial→blocking→sketch ③scene regen으로 composition_guide가 final input_image_ids에 붙는지(P0 graph 검증).
★시나리오 의존 0, 게이팅 완화는 canary+육안. 커밋 P0/P1과 분리.

## ★★★ 4a/4b/4d 구현 설계 LOCKED (Codex 확정 2026-07-01)
**broad deterministic seed + judge/QC 위임(코드 free-text 파싱 0).**
- outdoor detect_site_seeds: single-shot lane broad seed = **selected outdoor + figure_count≥1** (2+figure 요구 제거). location_source=frame_visible(VE에 L##) → 없으면 **primary_location fallback**(scene_director.primary_location, S15 확인=L11 / present_entity_ids=[L11,C01,C02]). ★location fallback 소스=scene_director cp(shot_director엔 primary_location 없음, visible_entity_ids만).
- manifest 기록(prefilter, 의미판정0): why_candidate="single_shot_outdoor_figure_present", location_source(frame_visible|primary_location|scene_present), figure_count, framing_scale, character_angle_count, frame_spatial_contract_present, available_structural_signal_names.
- camera_direction 등 free-text=judge payload에만(코드 파싱X).
- attach 유지: candidate AND judge.needs AND decision_type∈{single_shot_complexity,both,cross_shot_continuity} AND confidence≥medium AND grounded evidence(shot_key==candidate) AND guide/QC pass. broad seed=judge 대상이지 무조건 생성 아님(deny→manifest+image_call 0).
- lane group_id 분리: single=`osl-single-{loc}-s{scene}-sh{shot}`(이미 그럼), cross-covered shot은 single에서 exclude(이미 exclude_keys). 
- indoor 동일: selected indoor + actual bg plate + figure≥1 seed, 접촉/지지/복잡=judge, bg plate 없으면 no-guide degrade.
- ★flag 게이팅: shared_model_enabled(outdoor_composition_guide_shared_model_enabled) 경로 안에서만. OFF=byte-identical. broad는 single_shot_lane_enabled 새 플래그 or 기존 flag 재사용.
- 검증: dry-run manifest S15 sh1(frame_visible)/sh5(primary_location) candidate+judge_decision 확인 → targeted S15 guide 생성 → scene regen composition_guide input_image_ids(P0 graph).

## ★★ 4a outdoor seed 구현+검증 완료 (2026-07-01, 미커밋)
- outdoor_site_layout_plan.py: detect_site_seeds(single_shot_lane_enabled/primary_location_by_scene 파라미터, broad=figure≥1 seed + primary_location fallback + seed_meta 반환[why_candidate/location_source/figure_count/framing_scale/frame_spatial_contract_present/available_structural_signal_names], legacy byte-identical) + single_shot_complexity_candidates(broad param: is_complex 게이트 완화).
- outdoor_site_layout_step.py: _primary_location_by_scene 로더(scene_director), detect_site_seeds 3-tuple 배선(seed_meta), single_shot_complexity_candidates broad 전달(_settings_bl 로컬import), diagnostics에 seed_prefilter_meta/single_shot_seed_lane_enabled 기록.
- config.py: outdoor_single_shot_seed_lane_enabled(default False).
- 테스트: test_outdoor_site_layout_plan.py 3개(legacy byte-identical + broad lane + no_figure) PASS. ★전체 파일 pytest는 무관한 다른 테스트에서 hang(pre-existing, 내 3개는 격리 PASS).
- ★실 E2E 데이터 검증: OFF=2 seed(L01,L16), ON=9 seed 22 shots(L11 S15 포함: sh1 frame_visible/sh5 primary_location fallback, S19 sh5 L08 frame_visible). 4a/4d seed 진입 확인.
- ★미완: (1)judge payload에 location_source threading(non-frame-visible 엄격화, 지금 seed_meta에만) (2)LLM dry-run(step 재실행 flag ON→candidate+judge_decision manifest 확인, layout 9콜+judge) (3)indoor 4b broad lane(indoor_shared_pose_plan candidate_groups 동형) (4)targeted S15/S19 guide 생성+scene regen(4d). flag는 아직 .env 미설정(OFF).

## ★★★ 다음 세션 즉시 할일 (2026-07-01 clear 핸드오프, 4a dry-run 실행중)
**환경**: .env OUTDOOR_SINGLE_SHOT_SEED_LANE_ENABLED=true(+shared_model/judge ON). uvicorn 8000 실행중(신코드, 로그 scratchpad/uvicorn_p2.log). vite 3000. flag 켜져 있음. 미커밋 4a 변경파일: outdoor_site_layout_plan.py/outdoor_site_layout_step.py/config.py + tests/pipeline/test_outdoor_site_layout_plan.py(3 seed test). P0(3538bd81)/P1(44b4f7e9) 커밋됨.

1. **dry-run 완료 확인+4a acceptance**: `psql ... SELECT status FROM step_run WHERE step_id='outdoor_site_layout' ORDER BY updated_at DESC LIMIT 1`(running→completed 대기). 완료시 outdoor_site_layout/manifest.json diagnostics 검증: shared_model_candidate_signals/judge_decisions에 **S15 sh1/sh5(L11), S19 sh5(L08)** 있는지 + seed_prefilter_meta에 location_source(sh5=primary_location) + shared_model_image_calls 폭증없는지(judge deny 정상). ★진행중 확인=broad lane 새 그룹 osl-shared-l01-s1 발동함(guide 1→2). manifest=step END에 씀.
2. **indoor 4b broad lane**: indoor_shared_pose_plan.py candidate_groups(103)도 cross-shot 그룹만→single-shot lane 추가(selected indoor + actual bg plate + figure≥1, bg plate 없으면 diagnostics만 guide_fn 0콜, attach는 judge+QC 후). outdoor와 동형. indoor step 파일 확인 필요.
3. **targeted 4d**: S15/S19 sh5 scene regen(/stills/{id}/generate-image)→P0 graph로 composition_guide가 input_image_ids/generated_input에 붙는지. S19 sh5 id=3d0e0f5b-0af6-4d53-b353-658e1dd281d1, S15 sh1=... (scene_still 조회). 육안=벽갇힘 해소.
4. **테스트3(Codex)**: location_source payload 전달(step) / figure0 제외(있음) / judge deny→0 image·attach. 
5. **커밋**: P2 단독 scope, Codex GO 의논. 메시지에 outdoor broad seed lane+primary_location fallback+judge payload seed_meta+indoor lane 명시.
★Codex 합의: broad seed=judge 대상(무조건 이미지X), judge/QC fail-closed. 시나리오/free-text파싱 0.

## (이력) 진행 상태
- (2026-07-01) 4a 첫 쿼리 완료. ★초기 발견: S15는 5샷 중 sh1/sh5만 is_selected. sh1 VE=L11(정류장벤치 location 포함)+entities, sh5 VE=C02(location 없음), sh2/3/4=미선택(VE 빈). → **두 선택샷이 same-location 아님**(sh1만 L11) → outdoor shared_model cross-shot 그룹(same scene+loc 2+샷) 미형성 가능성 = 체인 미발동. dormancy 원인(scene_director가 outdoor location을 present엔 넣고 VE엔 안 넣음)과 일치. ★outdoor guide asset(aerial/blocking/sketch)은 still_id NULL이라 scene 조인 0(P0는 registered만 링크, outdoor guide still 링크는 미해결=별도).
- **다음 진단 스텝(next context)**: ①manifest(scene_detail render_prompt_card)+shot_staging_map에서 S15 각 샷 camera/framing/complexity 신호 추출 ②outdoor_site_layout_step의 shared_model_candidate_groups 로직 읽고 S15가 candidate 생성/judge/attach 중 어디서 탈락하는지 분리(코드+로그) ③S6(발동)와 S15 차이(S6는 몇 샷 same-loc?) 대조 ④shot SELECTION(gpt-mini)이 구도연결 샷(sh2/3/4)을 왜 드롭했는지(4a의 "구도 연결" 요구 vs 선택). 4b(복잡샷 무조건 마네킹)=candidate/judge/attach 기준 어디가 과보수인지. 그 후 Codex 공유→수정방향.

## ★★★ 세션 진행 (2026-07-01, clear 이후) — 4a PASS + 4b 완료 + 4d B' 진행중
**환경**: uvicorn 재기동됨 PID 21765(신 B' 코드, 로그 scratchpad/uvicorn_p2b.log, flag 전부 ON: OUTDOOR_COMPOSITION_GUIDE_ENABLED/SHARED_MODEL_ENABLED/JUDGE_ENABLED/SINGLE_SHOT_SEED_LANE_ENABLED). admin 쿠키 /tmp/p2_cookie.txt. %0=Claude %1=Codex.

**★4a acceptance PASS (Codex 4기준 전부)**: manifest SOT=scratchpad/outdoor_manifest_4a.json. seed_group 8, candidate/judge 11, attach 10, image_calls 23(base10+blocking3+sketch10, 폭증X). S15 sh1/sh5(L11 osl-shared-l11-s15) admit both/high→attach. S19 sh5(L08 osl-single-l08-s19-sh5) candidate+judge 도달했으나 judge DENY(1인1depth무모션). primary_location fallback 9샷 location_source 기록. 미커밋: outdoor_site_layout_plan.py/step.py/config.py + test_outdoor_site_layout_plan.py.

**★4b indoor broad lane 구현+테스트 완료(미커밋, Codex 승인)**: config.py indoor_single_shot_pose_lane_enabled(default False, 상위 indoor_shared_pose_guide_enabled 안에서만). indoor_shared_pose_plan.candidate_groups single_shot_lane_enabled param. indoor_shared_pose_guide_context: per-lane gid(isp-single-*), judge payload seed_prefilter_meta, single-lane bg-plate 가드. 테스트 55 passed(plan 6+context 4 신규). 파일: config.py/indoor_shared_pose_plan.py/indoor_shared_pose_guide_context.py + test_indoor_shared_pose_plan.py + test_indoor_pose_guide_attach.py.

**★4d B' 구현(미커밋, Codex GO)**: 진단=seed는 S19 sh5를 judge까지 올렸으나 judge admit 기준에 camera-extremity gap(극단 오버헤드가 free-text camera_direction에만). 코드 free-text 파싱 금지 원칙 하 judge 계층만 의미판정. 구현: outdoor_site_layout_provider.py SHARED_MODEL_GUIDE_JUDGE_SCHEMA reasons enum에 camera_or_framing_risk 추가 + SHARED_MODEL_GUIDE_JUDGE_SYSTEM에 "single figure/depth라도 camera/framing directive 자체가 extreme viewpoint/wall-floor relationship/foreshortening risk면 guide 정당" 일반원칙(시나리오/벽갇힘/인물명 0). outdoor_site_layout_step.py payload_shots에 raw_director_fields_for_judge{camera_direction/framing_scale/shot_type} 번들(코드 파싱0).
- ★B' acceptance 1(judge-only 재평가) PASS: scratchpad/p2_bprime_judge_eval.py → S19 sh5 needs=true/single_shot_complexity/high/reasons=['camera_or_framing_risk']/evidence source_field=camera_direction shot_key=19:5. 코드 free-text 파싱 없이 judge가 극단앵글 admit.
- ★B' 급성버그 확인: S19 sh5 guide-less regen(63312baa/3d0e0f5b) 육안 = 벽갇힘(상하반전 끼임)은 reroll로 해소되나 극단오버헤드 구도 불안정(좌 마트top-down+인물정면 원근불일치). guide 필요 확정.
- ★진행중: outdoor_site_layout force 재실행(신 B' 코드)→S19 sh5 guide 생성 확인 대기(워커 bbgxm6461, manifest→scratchpad/outdoor_manifest_bprime.json). 완료시 B' acceptance 2(guide gen marker leakage0)+3(scene regen composition_guide input_image_ids P0 graph+육안 원근/벽갇힘 개선) 검증.

**★남은 순서**: ①B' 재실행 완료→S19 admit/attach/guide 확인 ②S19 sh5 scene regen(/stills/3d0e0f5b/generate-image)→composition_guide 붙는지+육안 ③최종 테스트 스윕(indoor 4b+outdoor seed, pre-existing test_composition_guide_first_admitted_shot_is_sketch는 baseline 동일실패=P2 무관 분리) ④P2 커밋 Codex GO: scope=4a(outdoor seed)+4b(indoor lane)+4d(B' judge). 커밋메시지에 "S19 seed→judge 도달했으나 camera_or_framing_risk reason 추가로 admit" finding 명시.

## ★★★ 3a 배경 star anchor 구현 (2026-07-01, 미커밋, canary 진행중)
**환경**: uvicorn PID64630(신코드 scratchpad/uvicorn_3a.log), .env BACKGROUND_RENDER_STAR_ANCHOR_ENABLED=true 추가. P2(d1ca0806/ad8a5940) 푸시 완료.
**진단**: 배경 마스터플랜 LLM이 sub_location 전부 None→체이닝 불변식 미발동→22개 bg depends_on_bg=[] & input_image_ids=[fp만]. 메커니즘(depends_on_bg→prior_bg_paths→i2i)은 존재하나 입력이 빈 것. Codex 합의=depth-1 star anchor(loc_id 전체 anchor)+6가드(flag/anchor선택/preserve/metadata/lineage/canary).
**구현(미커밋)**: config.py background_render_star_anchor_enabled(default OFF). background_render_step.py: _inject_star_anchors 헬퍼(같은 loc_id 그룹 2+면 자연정렬 첫=B01 anchor, 나머지 depends_on_bg=[anchor] empty일때만 inject+_star_anchor_meta, anchor자신 불변, single그룹/loc없음 제외) + _execute서 flag ON일때 renderable 계산 후 호출(star_anchor_by_bid) + _register_image_assets 2-phase 기록(phase1 bg_id→UUID맵+parent_id pending 수집, phase2 anchor UUID resolve해 input_image_ids=[fp,anchor] 재기록, 실패시 fp+unresolved_inputs[bg:anchor]). OFF=미호출 byte-identical.
**테스트**: tests/core/test_background_render_star_anchor.py 6 passed(그룹/anchor우선/preserve/single제외/loc없음/renderable) + 기존 bg render 38 passed(byte-identical OFF).
**canary 진행중**: flag ON force 재렌더(워커 bkxow76c2, ~40min). acceptance=①L04 bg input_image_ids=[fp,anchor] 2개(캔버스 엣지) ②전체 chained 통계 ③L04B01/B02/B03 육안: 과동질화(모든 배경 같은 카메라/방으로 붕괴?) vs 벽/바닥/조명 continuity 개선. 통과시 Codex 리뷰→커밋(3a 단독 scope). L04 파일경로는 canary 출력에.
**남은**: canary 완료→엣지검증+육안→Codex 리뷰→3a 커밋. 그 후 캔버스 3b(완료)/3c/3d(P0 해소) 최종 확인.

## ★★★ 3a 정정 (2026-07-01, canary가 star anchor 결함 드러냄→워크플로 매핑 후 recording-only로 pivot, 미커밋)
**canary 실패 교훈**: flag ON 배경 재렌더(PID64630, 신 star-anchor 코드) 결과 input_image_ids 여전히 fp만(엣지0). 2버그 발견: ①등록루프 `_star_uuid_by_bgid[bid]`(잔여 bid)→맵에 마지막 bg만, anchor resolve 전부 실패(Pyright "bid possibly unbound" 정확했음) ②parent_id를 실제첨부로 오인.
**워크플로 매핑(wf_806c9839, 5에이전트) 확정**: 이 에피소드 BACKGROUND_RENDER_REFERENCE_MODE=shot_aware_plan. shot_aware는 prior_bg를 plan node(substrate resolve_render_substrate의 ref_tree_parents / adapter materialize_decision의 selected_refs)에서 뽑고 depends_on_bg를 attach에 안 씀(parent_id 메타+legacy _render_direct_plate line988만). 배경들은 이미 서로 i2i 참조 중(manifest attached_reference_lineage.prior_bg_ids에 bg:Lxx 실재). 실제첨부 단일 SOT=groups[bid].attached_reference_lineage.prior_bg_ids(FP제외, prefix없는 bg_id, p.stem 유도). parent_id/reference_decision.source_bg_ids는 substrate ON서 diverge→신뢰불가.
**정정 구현(background_render_step.py, 미커밋)**: ①_inject_star_anchors 호출을 `reference_mode=='w18j_overlap'` 전용 격리(shot_aware 미주입, 모듈삭제안함). ②순수함수 _compose_bg_input_image_ids(prior_bg_ids,fp_uuid,uuid_by_bgid,reuse)→([fp,*prior_uuids], meta{bg_lineage_policy/prior_bg_ids/lineage_kind[reused_plate→reuse_alias]/unresolved_inputs}). ③_register_image_assets phase1: `_star_uuid_by_bgid[bg_id]`(오타수정)+attached_reference_lineage.prior_bg_ids 수집(flag ON). phase2: 배치맵+DB variant_type in_() fallback resolver→_compose→annotate(input_image_ids). flag `background_render_star_anchor_enabled` 재사용(config무변경, OFF byte-identical). ★기록만 변경, 생성 무변경=과동질화 시각리스크 0.
**검증**: 테스트 tests/core/test_background_render_star_anchor.py 13 passed(helper6+compose7), 기존 bg render 48 passed(OFF byte-identical). ★오프라인 검증(재렌더0, scratchpad/p3a_offline_verify.py, production 순수함수를 기존 manifest+실DB로): 22 ok bg중 배경엣지 10개 정확(L04 B01→B04/B03→B01/L12 B02→B03/L03 B01·B03→B02), reuse_alias 3, unresolved 0.
**남은**: Codex 리뷰 답신(recording SOT/reuse 포함/legacy격리/재렌더 선택성 4점)→3a 단독 커밋. E2E 에피소드 엣지 채우려면 flag ON 재렌더 1회(선택, recording 검증엔 불필요). 환경: uvicorn PID64630(구 star-anchor 코드, 정정 반영하려면 재기동), .env BACKGROUND_RENDER_STAR_ANCHOR_ENABLED=true.
