
    Ojr             	         d Z ddlmZ ddlZddlZddlZddlZddlZddlm	Z	m
Z
 ddlmZmZ ddlmZ ddlmZmZmZmZmZ ddlmZ dd	lmZ dd
lmZ ddlmZ  ej:                  e      ZdZ dZ! ejD                  d      Z#ddZ$ddZ%ddddddddd	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 ddZ&	 	 	 	 	 	 	 	 	 	 ddZ'	 	 	 	 	 	 	 	 	 	 ddZ(	 	 	 	 d dZ)	 	 	 	 	 	 	 	 d!dZ*d Z+ G d de      Z,y)"uS  BackgroundRenderStep — Phase 7 Step 6.

각 master plan background를 gpt-image-2로 PNG 생성. ``depends_on_bg`` DAG →
``compute_dag_levels`` 로 level 분할 후 level 내부는 ThreadPool 병렬.

출력 shape는 Phase 5 ``chain_bg_render`` 와 호환:
``data.groups[bg_id].{status, location_id, png_path, t2i_prompt,
shot_guides, shot_ids, parent_id, ref_used, ...}``.
이렇게 해야 Phase 6 ``scene_context_loader._load_chain_bg_guide_by_shot``
가 변경 없이 동작.

Phase 7 ImageAsset UPSERT (Phase 5 chain_bg 패턴 미러):
  - asset_type='chain_bg'
  - entity_id = loc_id의 EntityCanon.id
  - variant_index = loc_id 단위 1+ counter (sorted bg_id, gen_order). v00은
    floor_plan(primary)에 예약.
  - variant_label = state_label
  - variant_type = bg_id (UPSERT 매치 키, 재실행 idempotent 보장)
  - is_primary = 0 (chain_bg는 항상 0; v00 floor_plan만 1)
  - t2i_guide = shot_guides[]를 newline join (Phase 6 scene_detail consumer 가
    이를 prepend하여 chain_bg PNG 가구 위치 가이드를 scene t2i에 주입)
  - file_path = projects_root 기준 relative
    )annotationsN)ThreadPoolExecutoras_completed)datetimetimezone)Path)AnyDictListOptionalTuple)BG_ID_RE)bind_current_budget)
StepRunner)annotate_generated_asset   z3.202607231950z^[a-z0-9][a-z0-9_]*$c                ^    | xs i j                  di       xs i }d|v sd|v rt        S t        S )u'  D6 marker-gated bg_id filter.

    plans_cp 의 data 에 D6 sibling marker (`background_catalog` 또는
    `bg_catalog_hash`) 가 있으면 D6 strict (`BG_ID_RE` = `^L\d{2,3}B\d{2,3}$`)
    적용. 없으면 legacy `_LEGACY_SAFE_BG_RE` (transitional compat) — 옛 cp 를
    silent reject 안 함.

    review iter4 note: T-pre-1 단독 commit 시 background_master_plan 가 여전히
    legacy `bg_*` 출력 → BG_ID_RE 강제 시 모든 bg silent skip → empty completed
    silent no-op. marker-gating 으로 D6 atomic transition 안전.
    databackground_catalogbg_catalog_hash)getr   _LEGACY_SAFE_BG_RE)plans_cpr   s     [/Users/manta/Documents/Projects/TheRoad-I1/backend/app/core/steps/background_render_step.py_select_bg_id_filterr   <   s:     N+1rDt#'8D'@    c                    ddl m}  ||       S )uQ   무인 계약 감사 3필드 CP 영속 subset (E2E10 실측 fix — lazy import).r   )audit_fields)(app.modules.pipeline.background_unmannedr   )infor   s     r   _unmanned_audit_fieldsr!   N   s    Er    )building_fp_idbuilding_fp_pathbuilding_anchor_bg_idbuilding_anchor_pathsame_loc_anchor_bg_idsame_loc_anchor_pathaerial_loc_idaerial_pathc                .   g }g }|$|j                         r|j                  d|
        |$|j                         r|j                  d|         |D ]G  }||j                         s|j                  }|j                  |       |j                  d|        I |	$|	j                         r|j                  d|        |$|j                         r|j                  d|        |$|j                         r|j                  d|        | |||ddS )	u  W21B-wave-1 — checkpoint-only attached reference lineage diagnostic.

    Codex 결정 2(c): ImageAsset.reference_image_ids / llm_call_log columns 는
    이번 wave 에서 건드리지 않는다. attached_reference_lineage 는 step 의
    groups_out entry / checkpoint manifest 에만 기록되어 chain_bg / scene
    visual review 시점에 "이 BG 가 실제로 어떤 reference 를 첨부해서 생성됐는지"
    를 역추적할 수 있게 한다.

    attached_ref_labels 는 실제로 첨부된 ref 만 포함한다 — fp_path 가 존재하면
    ``fp:<fp_id>``, 첨부된 prior_bg PNG 마다 그 stem 을 ``bg:<bg_id>`` 로 기록.
    PNG path 의 stem 이 bg_id 와 일치하는 것은 step 자체가 그렇게 저장하기
    때문 (``image_dir / f"{bid}.png"``). prior_bg_paths 가 비어 있고 fp 가
    없으면 attached_ref_labels 는 빈 list — ref_used 가 ``text_only`` 인 것과
    consistent.
    zaerial:zfp:bg:zsame_loc_anchor:zbuilding_anchor:zbuilding_fp:checkpoint_only)fp_idprior_bg_idsattached_ref_labelsref_useddb_write_policy)existsappendstem)r.   fp_pathprior_bg_pathsr1   r#   r$   r%   r&   r'   r(   r)   r*   r0   r/   pbg_ids                   r   !_build_attached_reference_lineager:   U   s;   < &( L ;#5#5#7""W]O#<=w~~/""S=1988:FFE&&&UG}5  ',@,G,G,I""%56K5L#MN ',@,G,G,I""%56K5L#MN #(8(?(?(A""\.1A#BC$2, r   c                    i }|D ]j  }||vrt        | j                  |      xs i j                  d      xs d      j                         }|sJ|j                  |g       j	                  |       l i }|j                         D ]w  \  }}t        |      dk  rt        |      d   }	|D ]P  }||	k(  r	| j                  |      xs i }
|
j                  d      r0|	g|
d<   dd|	dd	|
d
<   ||v r|	||   d<   |	||<   R y |S )u  3a fix (2026-07-01, Codex 합의) — depth-1 star anchor 주입 (flag-gated caller).

    같은 ``loc_id`` 그룹의 anchor(bg_id 자연정렬 첫 = B01 우선)를, 그룹 내 나머지
    bg 가 ``depends_on_bg`` 로 참조하도록 결정론 주입한다. render loop 이 이 필드로
    prior_bg_paths(i2i) + DAG parent 를 구성하므로 생성/lineage 가 함께 흐른다.

    ★가드(Codex): (1) 그룹 renderable bg 2개 미만이면 skip. (2) anchor 자신은
    depends_on_bg 불변. (3) 기존 depends_on_bg 가 있으면 preserve — **empty 일 때만**
    inject(순환/기존 체인 파괴 방지). (4) loc_id 없는 bg 는 그룹 대상 아님.
    반환: ``{bid: anchor_bid}`` (실제 주입된 것만). 호출측이 flag ON 일 때만 부른다.
    loc_idr"      r   depends_on_bgTlocation_star_depth1 sub_location_missing_or_no_chain)anchor_injectedanchor_policyanchor_bg_idanchor_reason_star_anchor_meta	parent_id)strr   strip
setdefaultr4   itemslensorted)bg_specsrJ   order
renderableby_locbidlocinjectedbidsanchorspecs              r   _inject_star_anchorsrW      s(   " $&Fj 8<<$*//9?R@FFH#r"))#.   "H\\^	Tt9q=aCf}<<$*Dxx(%+HD!#'!7 &!C	)D$% e|*0c
;'"HSM 	 $( Or   c               P   g }g }t               }| D ]Q  }||v r|j                  |       |j                  |      }|r|j                  |       >|j                  d|z          S g }	|g|D ]  }
|
s|
|	vs|	j                  |
        dt	        |       |rdndd}|r||d<   |	|fS )u  3a fix (2026-07-01, 워크플로 스펙) — 실제 첨부 prior_bg_ids 를 background_render
    ImageAsset.input_image_ids([fp_uuid, *prior_uuids]) + lineage 메타로 조립 (순수).

    prior_bg_ids = groups[bg_id].attached_reference_lineage.prior_bg_ids (실제 i2i/alias
    첨부된 BG 의 **prefix 없는 bg_id 리스트**, FP 제외 — 라벨/substring 파싱 0). uuid_by_
    bgid = bg_id→ImageAsset UUID resolver(배치맵 + DB variant_type fallback 합성). 미해결
    bg_id 는 unresolved_inputs 구조키("bg:<id>")로 기록(입력없음 [] 과 구분). reuse=
    구조 필드 ref_used=="reused_plate"(copy-less alias — i2i 아님)면 lineage_kind 태깅.
    반환: (input_image_ids, pipeline_metadata). fp_uuid None 이면 prior 만.
    r,   attached_prior_bgreuse_aliasi2i_reference)bg_lineage_policyr/   lineage_kindunresolved_inputs)setaddr   r4   list)r/   fp_uuiduuid_by_bgidreuseprior_uuids
unresolved_seen_bgpbuiidsxmetas               r   _compose_bg_input_image_idsrm      s    "  KJEH>RR q!ebj)  D%%$KKN & 1\*).OD
 $. !:r   c                2   t               }| xs i j                  di       xs i j                  dg       xs g }|D ]Y  }|j                  d      xs g D ]?  }|j                  d      xs d}|s|j                  d      du s/|j                  |       A [ |S )u   W22 W4b — background_classify cp 에서 실외 loc_id 집합 추출.

    is_indoor 판정의 유일 원천 = classify cp (설계 §1). cp 부재/빈 데이터 = 빈
    집합 → skip 미발동 (보수적).
    r   building_groupsmembersr<   r"   	is_indoorF)r_   r   r`   )classify_cpoutgroupsgmlids         r   _outdoor_loc_ids_from_classifyrx      s     uC		+1r	c
R '$&  %%	"(b(A%%/'RCquu[)U2 ) 
 Jr   c                   i }t        |       D ]m  }|j                  |      xs i }|j                  d      xs d|v s0d|j                  dd      |j                  dd      |j                  dg       xs g d||<   o | t        |      z
  |fS )u   W22 W4b — renderable 에서 야외 loc bg 를 분리 (순수 함수, 테스트 잠금).

    Returns (남은 renderable, {bg_id: skipped 마커 entry}).
    r<   r"   skipped_outdoor_directsub_locationapplies_to_shots)statuslocation_idlocation_nameshot_ids)rL   r   r_   )rO   rM   outdoor_locsskippedrQ   rV   s         r   _split_outdoor_direct_skipr     s     *,Gj!||C &BHHX$"52#xx"5!%."!= HH%7<B	GCL " G$g--r   c                 R    ddl m}  ddlm}  | t	        |j
                              S )u  OpenAI 이미지 클라이언트 resolve.

    T11 FloorPlanRenderStep와 동일 패턴. api_key 는 `openai_keys` 브로커가
    정한다(2슬롯 failover, 2026-07-30) — bare `OpenAI()` 는 os.environ 만 읽어
    .env 키도 슬롯 전환도 놓친다. timeout 은 settings.llm_timeout_image_gen
    (env LLM_TIMEOUT_IMAGE_GEN override 가능) — single source. default 600s 의
    long hang 회귀 가드.
    r   )openai_clientsettings)timeout)app.core.openai_keysr   app.core.configr   floatllm_timeout_image_gen)r   r   s     r   _resolve_openai_clientr   "  s%     3(h445 r   c            	      6   e Zd ZddZddZ	 	 	 	 ddZddZdddZddd		 	 	 	 	 	 	 	 	 	 	 	 	 	 	 dd
Z	 	 	 	 ddZ	ddZ
ddZddddddddd	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 ddZ	 d	 	 	 	 	 	 	 d dZ	 	 	 	 	 	 d!dZd"dZd Zd#dZy)$BackgroundRenderStepc                L   dd l }dd l}ddlm} |j                  t
        t        d}t        t        |dd            rd|d<   t        t        |dd            r	d	|d<   |j                  |d
<   |j                  |d<   |j                  |d<   ddlm}  |       |d<   ddlm}m}  |       |d<   ||d<   |j                  rBt        t        |dd            r,ddlm} ||d<   ddlm}	  |	       |d<   ddlm}
  ||
      |d<   |j                  rVt        t        |dd            r@ddlm} ddlm} ||d<    ||      |d<   ddlm} ||d<   t-        t        |d d!            |d"<   t        t        |d#d            rd	|d#<   t        t        |d$d            rOdd%lm}  |d&      |d'<   t        t        |d(d            r(dd)lm} d	|d*<   ||d+<   t-        |j4                        |d,<   |j6                  d-v r|j6                  |d.<   |j6                  d/k(  rt        t        |d0d            |d0<   |j6                  d/k(  rt        |j8                        rd	|d1<   |j6                  d/k(  rt        t        |d2d            rd	|d2<   |j6                  d/k(  rt        t        |d3d            rd	|d3<   |j6                  d/k(  rt        t        |d4d            rd	|d4<   |j6                  d/k(  r&t        t        |d5d            rd	|d5<   dd6lm} ||d7<   t        t        |d8d            rCdd l }dd9lm } d	|d8<   |jC                  |jE                  d:            jG                         d d; |d<<   |j6                  d/k(  rt        t        |d=d            rd	|d=<   t        t        |d>d            r7d	|d><   	 | jI                  d?      }|xs i jK                  d@      xs d!}|r||dA<   |jC                  |jO                  |d	B      jE                  d:            jG                         d dC S # tL        $ r d!}Y Vw xY w)DNr   r   )background_modeschema_versionprompt_versionplate_structure_facts_enabledF   plate_structure_factsplate_multiroll_enabledTplate_multiroll_roll_countplate_multiroll_critiqueplate_multiroll_nb2_model)resolve_judge_pack_versionplate_multiroll_judge_pack) CROSS_MODEL_ORDER_POLICY_VERSION#resolve_select_judge_model_physical"plate_select_judge_models_physicalplate_select_order_policymultiroll_fix_rejudge_enabled)FIX_REJUDGE_POLICY_VERSIONplate_multiroll_fix_rejudge)r   &plate_fix_rejudge_judge_model_physical)FIX_REJUDGE_HEADER_PACK_VERSIONplate_fix_rejudge_header_pack!multiroll_gpt_composition_enabled)GPT_COMPOSITION_PACK_VERSION)GPT_COMPOSITION_POLICY_VERSIONplate_gpt_compositionplate_gpt_composition_pack)GPT_COMPOSITION_MODELplate_gpt_composition_modelopenai_modelr"   $plate_gpt_composition_model_physicaloutdoor_direct_compose_enabledbackground_no_people_enabled)resolve_prompt_version1background_no_people_pack!background_no_people_gate_enabled)JUDGE_MODELbackground_no_people_gate%background_no_people_gate_judge_model.background_no_people_gate_judge_model_physicalw18j_overlapshot_aware_plan background_render_reference_moder   :background_render_missing_shot_aware_plan_fallback_enabledbg_render_substrate_enabledoutdoor_building_fp_ref_enabled#outdoor_building_anchor_ref_enabledsame_place_render_chain_enabled outdoor_aerial_reference_enabled)AERIAL_PROMPT_VERSIONlocation_aerial_prompt_version$outdoor_seed_plate_reference_enabledSEED_SITE_GUIDANCEutf-8   seed_site_guidance_sha!outdoor_plate_stage_chain_enabled floor_plan_light_sidecar_enabledfloor_plan_light_sidecarconfig_hash$floor_plan_light_sidecar_config_hash)	sort_keys   )(hashlibjsonr   r   r   SCHEMA_VERSIONPROMPT_VERSIONboolgetattrstill_recipe_roll_countstill_recipe_critique_enabledgemini_image_model%app.modules.pipeline.multiroll_geminir   r   r   %app.modules.pipeline.multiroll_selectr   r   r   r   r   rG   r   r   r   gemini_text_modelr   r   $app.modules.pipeline.location_aerialr   +app.modules.pipeline.outdoor_structure_seedr   sha256encode	hexdigest_load_prev_checkpointr   	Exceptiondumps)selfr   _jsonr   payloadr   _plate_order_policy_plate_sel_phys_frj_policy
_sel_phys2_frj_hdr_sel_gc_sel
_gc_policy	_gc_model_unmanned_pack_unmanned_judge_modelr   _hashlibr   
sidecar_cpsidecar_hashs                        r   _config_hashz!BackgroundRenderStep._config_hash3  s   ,  (77,,
 "A5IJ/0G+, ";UCD15G-.00 01 66 ./ 4<3N3NG/0
 +, 01
 =L<MG893FG/0
 55$"A5I; :E56 L @A
 /|< 78 55$"E; 4>/0.w7 45 :C56BEHnb9C>?
 "BEJK8<G45 "@%HI 4B#3FG/0G=u  8<34) ?@ 223 D 44 9
 

 99 2 448II P L" 559JJX99:59G12 559JJWX'H%PQ9=G56
 559JJW?H I >BG9:
 559JJW;UD E :>G56 559JJW<eE F ;?G67 9NG45 @%I J& ?CG:;08"))'21ik#21G,- 559JJW=uF G <@G78 "DeLM:>G67"!77.0
 * 0b55mDJ BN>?~~KK4K077@

)+cr 		  "!"s   "*P P#"P#c                L   ddl m} t        |j                        | j                  z  dz  dz  | j
                  z  |z  dz  }|j                         r&	 t        j                  |j                  d            S y # t        $ r!}t        j                  d||       Y d }~y d }~ww xY w)	Nr   r   checkpointsepisodeszmanifest.jsonr   )encodingz&background_render: %s parse failed: %s)r   r   r   projects_dir
project_id
episode_idr3   r   loads	read_textr   loggerwarning)r   step_idr   cpexcs        r   r   z*BackgroundRenderStep._load_prev_checkpoint<  s    , &&'oo  oo	
   	 99;zz",,,"@AA
 	  <gs  	s   $A9 9	B#BB#c                   ddl m} t        t        |dd            si S | j	                  d      }|xs i j                  di       xs i j                  di       xs i }|si S ddlm} i }d}t        |j                               D ]  }|j                  |      }	t        |	t              r|	j                  d	      d
k7  r*dt        |	t              r|	j                  d	      ndd||<   b|	j                  d      }
|
r ||
      nd}||j                         s	ddd||<   t        |      ||<   d|
d||<   |dz  } |rt        j                  d|       |S )u  W21B-w5 STEP5-B: swap the FP anchor PNG to the simplified light sidecar.

        Mutates ``fp_paths_str`` IN PLACE: for each fp whose floor_plan_light_sidecar
        entry is ``rendered`` with a resolvable PNG on disk, the detailed FP path
        is replaced by the light PNG's absolute path (the same key the legacy and
        substrate render paths both read). Returns a per-fp provenance map for the
        checkpoint (audit). A missing/invalid sidecar falls back to the detailed
        FP for that fp only.

        Flag OFF (default): returns ``{}`` and does not touch ``fp_paths_str`` —
        the render path is byte-identical to the pre-STEP5-B behaviour.
        r   r   r   Fr   r   per_fpresolve_image_pathr}   rendereddetailedabsent)usedreasonlight_png_relative_pathNlight_png_missinglight)r  	light_pngr   z;background_render: swapped %d FP anchor(s) to light sidecar)r   r   r   r   r   r   app.core.file_pathsr	  ra   keys
isinstancedictr3   rG   r  r    )r   fp_paths_strr   r  r  r	  
provenanceswappedfidentryrelabs_paths               r   _apply_light_fp_sidecarz,BackgroundRenderStep._apply_light_fp_sidecarQ  sd    	-H@%H
 I''(BC8..,277"EKI:%'
))+,CJJsOEeT*eii.AZ.O&/9%/F		(+H#
3 ))56C25)#.4Hx'8&1#
3  #HL'.SAJsOqLG) -, KKM r   c                    ddl m} t        |dd      sy| j                  | j                  | j
                  t        | dd      dk(  d	S )
u   plate_multiroll(레시피) 컨텍스트 — flag OFF 면 None(기존 무영향).

        Codex 1차 리뷰 MEDIUM-6: 프로젝트 귀속(llm_call_log)·judge 모델
        override·force 전파를 render_one_background 에 스레드.
        r   r   r   FN_render_moderesumeforce)r   r   project_configr"  )r   r   r   r   r   r#  )r   r   s     r   _plate_multiroll_ctxz)BackgroundRenderStep._plate_multiroll_ctx  sI     	-x!:EB////"11T>8<G	
 	
r   r!  c                   DEFGHIJK ddl m} | _        |j                  dvrdddt         j                         ddddS ddlm}  ||      }| dddt         j                         |dd|d	d
S  j                  d      } j                  d      } j                  d      } j                  d      }|xs i j                  di       xs i j                  di       xs i }	|xs i j                  di       xs i j                  di       xs i J|xs i j                  di       xs i j                  di       xs i j                         D 
ci c],  \  }
}|j                  d      dk(  r|
|j                  dd      . c}}
G j                  G      }|xs i j                  di       xs i j                  di       xs i }i E|j                         D ]  \  }
}t        |t              r|j                  d      dk7  r+|j                  d      xs g D ]  }t        |t              s|j                  d      xs d}|s,|Ev rt        j                  d||
       H|j                  dd      xs d|j                  dd      xs d|j                  dd      xs d|j                  dd      xs ddE|<     t!        t#        |dd            }i }i }|r|j                         D ]  \  }
}t        |t              r|j                  d      dk7  r+|j                  d       xs g D cg c]  }t        |t              r| }}|r|||
<   |j                  d      xs g D ]X  }t        |t              s|j                  d      xs d}|s,||vs1t        |j                  d!      t$              sQ|d!   ||<   Z  t'        |      }|t(        u }i }g }i D|	j                         D ]  \  }}|j                  d      dk7  r|j                  d"      xs i }|j                  d      xs g D ]  }|j                  d      }|r|j+                  |      s+|rt-        d#|d$|d%      t        j/                  d&|       R||v rW|j                  d'      xs g }d(|r|d   ndi||<   |j1                  |       |D|<     |D ch c])  }Jj                  |i       j                  d      dk(  s(|+ } }i }!t!        t#        |d)d            rWt3         j                  d*            }"|"r;t5        | D|"      \  } }!|!r)t        j7                  d+t9        |!      t;        |!             i }#t!        t#        |d,d            r?t#        |d-d      d.k(  r/t=        D|||       }#|#rt        j7                  d/t9        |#             | sj|xs i j                  di       xs i }$dddt         j                         t        |!      |$j                  d0d      xs d|$j                  d1d      xs dd2dS dd3lm }% dd4l!m"K tG               F |%||| d(5      }&tI        |jJ                         jL                  z  d6z   jN                  z  d7z  d8z  HHjQ                  d9d9:       HjS                         Ii }'i }(d})dd;l*m+}*  |*d<d=>      }+	 	 	 	 	 	 dgDEFGHIJK f	d?},g }-i }.|jX                  d.k(  rW|D ]P  }|| vrDj                  |      xs i }/Jj                  |i       xs i }0 j[                  ||/|0Ed@A      |(|<   |)dz  })R n|jX                  dBk(  r͉ j                  dC      }1|1xs i j                  di       xs i j                  dDi       xs i }2 j]                  DJGE|2| |HIF j_                  |       ja                          jc                         |.|| j                  dE      xs i j                  di       xs i j                  dF      xs i |G      \  }(}'})}-n|&D ]  }3|3st        |'      }4te        dtg        |+t9        |3                  }5ti        |5H      5 }6tk        |,      }7|3D ci c]  }|6jm                  |7||4      | }8}to        |8      D ]\  }9|8|9   }	 |9jq                         \  }:};|;|(|<   |;j                  d      dk(  r#|;j                  d      rtI        |;d         |'|<   X|)dz  })^ 	 d d d         |(jy                  |!       |D ci c]  }||(v s||(|    }=}	  j{                  |=||.xs d _       |xs i j                  di       xs i }@|=|@j                  d0d      xs d@j                  d1d      xs dd2}A|jX                  dcv r|-Add<   |r|Ade<   |.r|.AdF<   t9        |       }Bt}        df |=j                         D              }Cte        d|B      |C|)t         j                         AdS c c}}
w c c}w c c}w c c}w # tr        $ r;}<t        j/                  dI||<       Dj                  |i       }/Jj                  |i       xs i }0i ddJdK|/j                  dLd      dM|/j                  dNd      dddO|0j                  dOd      dP|0j                  dPg       xs g dQ|/j                  dRg       xs g dSg d(|/j                  d'      xs dgd   dTdUdVddWtu        |<      d dX dY|/j                  dZd      d[ddEj                  |i       d\tw        |/j                  d]      xs dgd   d g dU^      };Y d }<~<d }<~<ww xY w# 1 sw Y   @xY wc c}w # tr        $ r}<t}        d` |=j                         D              }>t        j/                  dat9        |=      |>|<t        j                                	  j                  j                           # tr        $ r }?t        j/                  db|?       Y d }?~? d }?~?ww xY wd }<~<ww xY w)hNr   r   >   onfloor_plan_anchoredr"   )consumed_bg_catalog_hashconsumed_shot_binding_hash)applicable_countcompleted_countfailed_countr   r   r   )detect_w19b3_w20b_conflictr   )r(  r)  selector_conflict)r*  r+  r,  r   r   errorr   background_master_planbackground_promptfloor_plan_renderfloor_plan_promptr   plansbackgroundsfloor_plansr}   okpng_pathcamera_recommendationsr9   uf   background_render: duplicate camera_recommendation for bg_id=%r (fp=%r) — first-wins, dropping latercamera_positioncamera_height	lens_hintframing_notes)r:  r;  r<  r=  r   Fnumbered_elementsuse_numbered_elementsplanu2   background_render: D6 marker cp 에 invalid bg_id z (group=u~   ) — fail-fast. master_plan post-processing handshake 미완료 또는 cp 손상. force re-run background_master_plan 의무.u+   background_render: unsafe bg_id %r — skipr>   rF   r   background_classifyu@   background_render: W22 직행 — 야외 bg %d개 plate skip: %s%background_render_star_anchor_enabledr   r   u>   background_render: star anchor 주입 %d bg (legacy w18j only)r   shot_binding_hash)rt   r(  r)  )compute_dag_levels)render_one_background)parent_fieldr   imagesbackground_chainT)parentsexist_ok)resolve_workers      )defaultcapc                  	 |    }j                  | i       xs i }|j                  dd      }|j                  dg       xs g }|j                  dg       xs g }|j                  d      xs dgd   }|j                  dd      }|j                  dd      }	|j                  d	d      }
|j                  d
      xs dgd   }d }|rj                  |      rt        |         }g }|j                  d      xs g D ]8  }|j                  |      }||j                         s(|j                  |       : |  dz  }	 |j	                         j                          d ||||| j                         !      }|j                  dd      }| i d|j                  dd"      d|d|	d|j                  d      d#k(  r|j                  dd      ndd|d|d|dg d|d|d|j                  d$d      d|j                  d%      xs dd|
d|d uxr |j                         dj                  | i       dt        ||||      t        |      fS # t        t        f$ rj t        j                  d|        | i ddd|d|	ddd|d|d|dg d|ddddddd|
dddj                  | i       dt        |d g d      fcY S w xY w)&N
t2i_promptr"   shot_guidesr|   r>   r   r<   r{   state_labeldepends_on_fp.png4background_render: out_path escapes image_dir for %sr}   rejected_pathr~   r   r8  r   scenesrF   r1   	text_onlyrender_attemptsrender_errorout_path escapes image_dirvariant_labelfloor_plan_usedFr9  attached_reference_lineager.   r6   r7   r1   gpt-image-2.5-sunburst)r   image_modelpromptout_pathr6   r7   r9   plate_multiroll_ctxfailedr7  attemptsfinal_block_reason)r   r   r3   r4   resolverelative_to
ValueErrorOSErrorr  r/  r:   r$  r!   )rQ   snapshotrV   prompt_entryrQ  rR  r   rF   r~   r   r]  fp_firstr6   r7   depr8   rd  r    r1   rM   camera_recs_by_bgclientr  	image_dirimage_dir_resolvedprompts_maprE  r   s                      r   _processz/BackgroundRenderStep._execute.<locals>._process  s    C=D&??339rL%)),;J&**="=CKxx 2B7=2H/2:rdA>I((8R0K HH^R8M HH]B7M19bT1=H&*GL,,X6|H56)+Nxx06B6LL%=QXXZ"))!, 7
 !cU$</H   "../ABB )$4!!-$($=$=$?	D xx
K8H $((8X6{   040Bd0JDHHZ,PR j { H " Y H "488J#: )= > D"    "7$#6#K7>>;K!$ )*;*?*?R*H%* -.O"##1%	/+: ).;  W ( JC  o!; $] 	
 !* ";  b    &q #$@ $] &u  -.?.C.CC.L!( 12S& $')!,	3)  	s   I A6KKu(  background_render_reference_mode_deprecated: w18j_overlap_deprecated — the W19B-3 deterministic reference planner path is no longer an active production option (W20E7-A). Set background_render_reference_mode to 'shot_aware_plan' (W20C) or leave the default 'legacy'. Zero image calls were made.rQ   rV   rn  rq  r/  r   shot_aware_bg_render_planr  background_renderlocation_aerials)rM   ru  r  rq  plans_per_fprO   rN   rs  rt  rr  building_fp_by_locgroup_membership_by_locaerial_loc_contextaerial_diag_outnumbered_by_fpfacts_use_by_bgprior_location_aerialsmode)max_workersz*background_render: bg %s thread raised: %srf  r~   r<   r   r{   rQ  rR  r   r|   rX  r1   rY  rZ  r[     r]  rS  r^  r_  rT  r`  )rz  c              3  J   K   | ]  }|j                  d       dk(  sd  yw)r}   r7  r   Nr   ).0vs     r   	<genexpr>z0BackgroundRenderStep._execute.<locals>.<genexpr>  s$      +aquuX$/F+s   ##u   [BG_RENDER_SYNC_FAIL] background_render: chain_bg ImageAsset INSERT 실패. PNG는 디스크에 있으나 DB out of sync — downstream(scene_image_pipeline)이 참조 이미지를 못 찾음. groups_total=%d ok_status=%d exc=%s
%sz.[BG_RENDER_SYNC_FAIL] rollback also failed: %sr   bg_reference_cataloglight_fp_sidecar_provenancec              3     K   | ];  }t        |t              r)|j                  d       dk(  r|j                  d      rd = yw)r}   r7  r8  r   N)r  r  r   )r  es     r   r  z0BackgroundRenderStep._execute.<locals>.<genexpr>  s<      
'!!T"quuX$'>155CT 's   AA)rQ   rG   rm  zDict[str, Path]returnzTuple[str, Dict[str, Any]])Dr   r   r   r   r   r   app.core.steps._selector_guardsr-  r   r   rJ   r  r  r  r  r  r   r   ra   r   r   matchrk  r/  r4   rx   r   r    rK   rL   rW    app.modules.pipeline._dag_levelsrD  &app.modules.pipeline.background_renderrE  r   r   r   r   r   mkdirri  app.modules.pipeline._workersrK  r   _build_opt_in_failed_entry_run_shot_aware_plan_queue_load_building_fp_by_loc_load_group_membership_by_loc_load_aerial_loc_contextmaxminr   r   submitr   resultr   rG   r:   update_register_image_assetssumvalues	traceback
format_excdbrollback)Lr   r  r   r-  conflict_msgr   
prompts_cpfp_render_cpfp_prompt_cp	plans_mapr  r  light_fp_provenancefp_prompts_mapfp_entrycrr9   structure_facts_onr  r  r  els_fbbg_filter_red6_strict_moderJ   rN   gidr@  bgrQ   depsrO   _direct_skipped_outdoor_locsstar_anchor_by_bidplans_data_emptyrD  levelsrendered_paths
groups_outrf  rK  r  rv  catalog_dumprz  rV   rn  plan_cpr{  levelrm  level_workerspool_submit_processfuturesfut_bidresr  ordered	ok_groupsrb_exc
plans_datar   	total_bgscompleted_bgsrM   rq  rr  r  rs  rt  ru  rE  sL   `                                                                   @@@@@@@@r   _executezBackgroundRenderStep._execute  s   , !##+HH$%#$ !"0#0020224
 
" 	O1(;#$%#$ !"0#002%0224)5  --.FG//0CD
112EF 112EF n"!!&"-388"EK 	 B##FB/52::="MSQS 	 $"))&"5;@@PRS eg

U yy"d* :r**
& #::<H  b%%fb17R<<]BO  	 8:+113MCh-h1G41Oll#;<BB!"d+w-2--NN As ')vv.?'D'J%'VVOR%@%FB!#R!8!>B%'VVOR%@%FB	,!%( C 4: "'5u#> ?:<02!/!5!5!7X!(D1 X.$6'||,?@FBFF!!!T* F   *-N3'",,'?@FBFB%b$/ &&//RCs/9jFF#:;T?C/12I/J, G "8( ,H5 '(2+-.0#//+JCyy"d*99V$*Dhh}-33ffWo,"4"4S"9%(P"gXcW 5JK  LLEs %<vvo.4"Dabc
 S! "- 4	 ,< !
 CKOOC$<$@$@$Jd$RC5 	 
 68"BEJK:**+@AM .H-/+
O #KKZO,f_.E .0#JERSH&H"M!"!5%
"4!T*+-  !)B33FB?E2$%#$ !"0#002"?30@0D0DEVXZ0[0a_a2B2F2FGZ\^2_2ece  	HP')#5*;

 &&'oo oo 	
 !! 	 	t4&..0*,%'
A%aQ7e	e	 /e	'e	 e	b .0 ,.44Fj(||C(.B*sB7=2"&"A"A!-&7@ #B #
3 !) * 66:KK00+G -R$$VR06B;;HbI   //!')"3)%##5 $(#@#@#J )-(J(J(L $(#@#@#B 0  . /
 001DEKc&"o,)+SS1C-DKHJA 0 !H  / #As;E
'C D'MBd ':(&COTYTYSOS(CSHTY    ,G4%cl%(+

ID#J +.
3778,49L26s:2GN3/"aKFY  5 CB  | 	/* 49N5CC:<M3
3'5N	''!1!9T ( 4 n"))&"5;
(27H"(M(SQS*4..9Lb*Q*WUW 
 44 9
 
 ,8D'( 2ED./ '7D#$  
O	 
~~'
 

 !$Ay 1,",,,.
 	
m
Hh
z  ) #"LL L # #
 $,<<R#8D+6??3+C+IrL# ((# -txx"/E# !0."1M# !+B	#
 !-l.>.>|R.P# !.|/?/?r/R/XVX# !+DHH5G,L,RPR# !)"# !,dhh.G.OB4QR-S# !+K# !21# !/C## !0-1L# !25#  !9:K:O:OPSUW:X!#* !=>_+/88O+D+La*P,035-8	?"+#C# CBv O  	 ">>+ I LLZ Gii.B.B.D	  "
 	  Df  		s   1g0,g6)g;0g;m#h >mh'Am
	mmm  m
m
	D0m	?mm
	
mm		p	(Ap=op	p!o<7p<ppp	rf  N)r}   decision_dictc                  i d|d|j                  dd      d|j                  dd      ddd|j                  dd      d	|j                  d	g       xs g d
|j                  dg       xs g dg d|j                  d      xs dgd   ddddd|d d d|j                  dd      ddd|j                  |i       dt        |j                  d      xs dgd   d g d      }|||d<   |S )Nr}   r~   r<   r"   r   r{   r8  rQ  rR  r   r|   rX  rF   r>   r   r1   rY  rZ  r[  r  r]  rS  r^  Fr9  r_  rT  r`  reference_decision)r   r:   )	r   rQ   rV   rn  rq  r/  r}   r  r  s	            r   r  z/BackgroundRenderStep._build_opt_in_failed_entry  s~   !
f!
488Hb1!
 TXXnb9!
 	!

 ,**<<!
 <++M2>D"!
 !3R8>B!
 b!
 $((?3;tQ?!
 !
 q!
 E$3K!
 TXXmR8!
 u!
 %&7&;&;C&D!
$ )*Kxx08RD!<!$	+%!
2 $*7E&'r   c                   ddl m} t        t        |dd            ri S t        t        |dd            s.t        t        |dd            st        t        |dd            si S 	 ddlm}m} | j                  d	      }|xs i j                  d
i       xs i j                  d      xs i } ||xs i j                  d
i       xs i j                  d      xs g  ||            }|si S | j                  d      }|xs i j                  d
i       xs i j                  d      xs i }	i }
|j                         D ]k  \  }}|	j                  |j                  d            xs i }t        |j                  d      xs d      }|j                  d      dk(  s]|s`i ||dd|
|<   m |
si S 	 ddlm} |
j                         D ch c]  }|d   	 }}| j                  j                  |j                   |j"                        j%                  |j&                  | j&                  k(  |j(                  | j(                  k(  |j*                  dk(  |j                   j-                  t/        |                  j1                         D ]>  \  }}|
j                         D ]&  }|d   t        |xs d      k(  st        |      |d<   ( @ 	 t4        j9                  dt;        |
      |
j                         D ci c]  \  }}||d    c}}       |
S c c}w # t2        $ r }t4        j7                  d|       Y d}~pd}~ww xY wc c}}w # t2        $ r"}t4        j7                  d|       i cY d}~S d}~ww xY w)u  flag ``outdoor_building_fp_ref_enabled`` (W-G) **또는**
        ``outdoor_building_anchor_ref_enabled`` (W-I) **또는**
        ``outdoor_aerial_reference_enabled`` (W-L) ON 일 때 outdoor loc →
        same-building indoor fp 컨텍스트를 구성한다. W-I 는 이 링크 맵을
        outdoor 멤버십 + group_id 판정에 재사용하고, W-L 은 mixed 그룹
        aerial 생성의 I2I fp ref 소스로 재사용한다(plate 에의 fp 첨부 여부는
        큐의 W-G flag 게이트가 별도 결정).

        반환: ``{outdoor_loc_sid: {"fp_id", "indoor_loc_sid", "group_id",
        "png_path", "fp_asset_id"}}`` — ``png_path`` 는 floor_plan_render cp 의
        status=='ok' entry 만, ``fp_asset_id`` 는 ImageAsset(asset_type=
        'floor_plan', variant_type=fp_id) 구조 조인(미해결이면 빈 문자열 —
        ref 첨부는 진행하되 UUID lineage 만 생략). 세 flag OFF/실패 = {}
        (비차단, 기존 경로 byte-identical).
        r   r   r   Fr   r   r   )build_outdoor_building_fp_linkindoor_fp_ids_by_locrA  r   r   ro   r2  r6  r.   r8  r"   r}   r7  )r8  fp_asset_id
ImageAsset
floor_planr  u\   background_render: building fp asset UUID resolve 실패 (비차단, lineage 만 생략): %sNu3   background_render: building fp 링크 %d loc — %suC   background_render: building fp 링크 로드 실패 (비차단): %s)r   r   r   r   %app.modules.pipeline.building_fp_linkr  r  r   r   rJ   rG   app.models.projectr  r  r  queryvariant_typeidfilterr   r   
asset_typein_rL   allr   r  r  r    rK   )r   r   r   r  r  bgc_cpcataloglinkfpr_cpfpr_maprs   oloclkr  pngr  neededvtaidr  kr  s                         r   r  z-BackgroundRenderStep._load_building_fp_by_loc(  sT   $ 	- "BEJKI #DeLMG?H IG<eE F I=	
 //0EFFR$$VR06Bc&'.+-  2,B##FB/52::;LM $W-D
 	//0CDF2""62.4"c- '$&  .0C JJLbBFF7O4:%))J/52699X&$.3 J2 J3r JCI	 )
 	@903

=""W+=GGMM*"9"9:==IV"--@"--@"--="//33F6NC	 SU B "jjlg;#bhB-703CB}- +  KKEC+.99;7;41aAgJ;7
 J/ >  @:;>@ @@ 8  	NNU I		s   $BL> (B,L> L> L> +L LCL -L ?.L> -L8=	L> L 	L5L0+L> 0L55	L> >	M)M$M)$M)c                   ddl m} t        t        |dd            si S 	 ddlm} | j                  d      } ||xs i j                  di       xs i j                  d      xs g       }|rEt        j                  d	t        |      |j                         D ci c]  \  }}||d
    c}}       |S c c}}w # t        $ r"}t        j                  d|       i cY d}~S d}~ww xY w)uX  flag ``same_place_render_chain_enabled`` (W-K) ON 일 때
        ``background_classify.building_groups`` 의 **전 멤버**(실내 포함) loc
        멤버십을 로드한다. W-K 의 그룹 anchor 등록(outdoor ok 렌더만)·첨부
        (그룹 전 멤버)·lane 재배열 정렬 키(mixed 그룹 outdoor 우선) 판정에
        쓴다 — W-G 링크 맵(outdoor loc 만, fp png 필수)으로는 실내 첨부를
        판정할 수 없다. flag OFF/실패 = {} (비차단, 기존 경로 byte-identical).

        반환: ``{loc_sid: {"group_id", "is_indoor", "group_mixed"}}``.
        r   r   r   F)build_group_membership_by_locrA  r   ro   u<   background_render: same-place 그룹 멤버십 %d loc — %sgroup_iduL   background_render: same-place 그룹 멤버십 로드 실패 (비차단): %sN)r   r   r   r   r  r  r   r   r  r    rK   rJ   r   r  )r   r   r  r  
membershipr  r  r  s           r   r  z2BackgroundRenderStep._load_group_membership_by_loc  s     	-G;UD EI	 //0EFF6,B##FB/52::;LM J R
O2<2B2B2DE2D$!QQ*%2DE
  F  	NN"#&( I		s0   A9B9 B3)	B9 3B9 9	C$CC$C$c                   ddl m} t        t        |dd            ri S t        t        |dd            si S 	 ddlm} | j                  d      } ||xs i j                  di       xs i j                  d	      xs g       }t        d
 |j                         D              }|r t        j                  dt        |      |       |S # t        $ r"}t        j                  d|       i cY d}~S d}~ww xY w)uz  flag ``outdoor_aerial_reference_enabled`` (W-L) ON 일 때
        ``background_classify.building_groups`` 에서 loc별 aerial 컨텍스트
        (is_indoor/group_mixed/label/summary)를 로드한다. 야외 판정
        (is_indoor==False)과 aerial 프롬프트의 location 데이터 소스.
        flag OFF/실패 = {} (비차단, 기존 경로 byte-identical).
        r   r   r   Fr   )build_loc_aerial_contextrA  r   ro   c              3  N   K   | ]  \  }}|j                  d       du s|  yw)rq   FNr  )r  rR   cs      r   r  z@BackgroundRenderStep._load_aerial_loc_context.<locals>.<genexpr>  s(      "-Q{1Cu1L+s   %%u:   background_render: aerial 컨텍스트 %d loc (outdoor %s)uD   background_render: aerial 컨텍스트 로드 실패 (비차단): %sN)r   r   r   r   r   r  r   r   rL   rJ   r  r    rK   r   r  )r   r   r  r  ctxoutdoorr  s          r   r  z-BackgroundRenderStep._load_aerial_loc_context  s     	- "BEJKIG<eE FI	 //0EFF*,B##FB/52::;LM C  "%))+ G PHg J 	NNV I		s   BC 	C1C,&C1,C1)r|  r}  r~  r  r  r  r  r  c               @   	
 ddl m} ddlmmmmmm ddl	m
 ddlm}mm}m}m} ddlm} ddlm}m}m}m}m i i dg t3        t5        |dd	            xs i xs i dfd}t7        |      }i }g |D ]  } | |vrj9                  |       xs i }!|!j9                  d      xs g }"|"sa|!j9                  dd      xs d}#|#dv rj;                  |        `j9                  | i       xs i }$ j=                  | |!|$d      | <   dz  |j?                  |"d   g       j;                  |         d|xs i t3        t5        |dd	            d舞fdt3        t5        |dd	            t3        t5        |dd	            t3        t5        |dd	            |xs i i i 	 	 	 	 	 	 	 	 d鈜fd	 	 	 	 	 	 	 	 d鈢fd	 	 	 	 	 	 	 	 dꈜfd	 	 	 	 	 	 	 	 dꈢfdddd숗fdt3        t5        |dd	            |xs i }%i i t3        t5        |d d	            r	 dd!l	m }&  jC                  d"      }' jC                  d#      }( |&|'xs i j9                  d$i       xs i j9                  d%      xs i |(xs i j9                  d$i       xs i j9                  d&      xs g       r)tD        jG                  d'tI              tK                     ||ni }*r|%rt7               }+D ]B  },|+jQ                  tS        j9                  |,      xs i j9                  d*      xs d+             D |jU                         D ]I  }-|-D ]B  },|+jQ                  tS        j9                  |,      xs i j9                  d*      xs d+             D K i }.tK        |+      D ]s  }/|%j9                  |/      }0|0r|0j9                  d,      d	ur*tS        |0j9                  d-      xs d+      }1|1sK|.j?                  |1g |0d.      }2|2d/   j;                  |/       u tK        |.      D ]x  }1|.|1   d/   }3|.|1   d0   }0tW        jX                  d1|1      r|1}4nOdd)l-}5d2|5j]                  |1j_                  d3            ja                         d)d4 z   }4tD        jO                  d5|1|4       d6|4 d7z  }6	 |6jc                         je                  	       d)}7|0j9                  d9      r+|3D ]&  }8j9                  |8      sj9                  |8      }7 n d)}9|79tm        tS        |7j9                  d      xs d+            }:|:jo                         r|:}9 ||1tq        |0j9                  d:      xs g       tS        |0j9                  d;      xs d+      tS        |7xs i j9                  d<      xs d+      =      };|xs i j9                  |1      xs i }<tS        |<j9                  d>      xs d+      }=tS        |<j9                  d?      xs d+      }>|6js                         r|d@k7  r|=|k(  r|>|;k(  r|3D ]  }8tS        |6      dA|1dB|8<    dCtS        |6      dAt3        |9      |7rtS        |7j9                  dD      xs d+      nd+||;tq        |3      tS        |0j9                  d;      xs d+      dE	|*|1<   y |
dF|1tq        |0j9                  d:      xs g       |6|9|7r,|7j9                  dD      rtS        |7j9                  dD            gnd)G      }?|?j9                  dH      dCk(  r|?j9                  d      r|3D ]  }8|?d   d	|1dB|8<    dC|?d   d	t3        |?j9                  dI            |7rtS        |7j9                  dD      xs d+      nd+|?j9                  dJd      |?j9                  dKd+      tS        |?j9                  d>      xs d+      |;tq        |3      tS        |0j9                  d;      xs d+      dL|*|1<   tD        jG                  dM|1|3t3        |9             dNd	t3        |?j9                  dI            |?j9                  dJd      tS        |?j9                  dO      xs d+      d)dP tq        |3      tS        |0j9                  d;      xs d+      dQ|*|1<   tD        jO                  dR|1|?j9                  dO             { d툚fdSd+d)dT	 	 	 	 	 	 	 	 	 d
	 fdUdfdV}@t7               rfrcr`d숚fdW}Ai }Bt7               }C|ju                         D ]  \  }D}E|j9                  |D      }F ||F      s 	  |F      }Gt7        E      }HGD ]  }I|Ij9                  dX      }Jtw        |JtR              rJrJ|vsJHvsJCv r3Ij9                  dYdZ      dZk7  rI Aj9                  J      xs i       }K|KsgCjQ                  J       Bj?                  Kg       j;                  |Jd[DId\         D ]\  }J|JCv r Aj9                  J      xs i       }K|Ks&CjQ                  J       Bj?                  Kg       j;                  |Jd]d+d)d\       ^ tK        B      D ]  }KB|K   }L|LD Mcg c]  }M|Md
   	 }N}MLD Mci c]  }M|Md
   |M
 }O}Mt7        N      }Pg }QLD ]$  }Mj9                  |Md
         xs i }R|%j9                  tS        |Rj9                  d*      xs d+            xs i }SQj;                  Md
   tS        |Sj9                  d^      xs d+      tS        Sj9                  d_      xs d+      tS        Rj9                  d      xs d+      tS        Rj9                  d`      xs d+      Rj9                  da      xs g D Tcg c]  }T|TPv rT
 c}Tj9                  Md
   i       xs i j9                  dbd+      dc       ' 	 dddl<m=}U  |KQ|U j|                   j                  de|Kif      g      }VVj9                  dk      xs ND Wcg c]  }W|WOv rW
 }X}WtD        jG                  dlK|XVj9                  dm             |*j9                  |K      }Ytw        |Yt              rgtq        X      tS        Vj9                  dm      xs d+      tS        Vj9                  dn      xs d+      tS        Vj9                  do      xs d+      djYdp<   i }Zd+}[t        X      D ]z  \  }\} O|    }]jQ                  |        j9                  |       xs i }!j9                  | i       xs i }$|$j9                  dbd+      }^ |!      }_d)}`]dq   d[k(  r`	  |]d[   |]d<   |j9                  |]d<         xs d)Zju                         D Waci c]  \  }W}a|WtS        |a       c}a}Wd	 || ]d<         r      }`d+}bd+}c|!j9                  da      xs g D ]  }d|dZv stS        d      }bda}c n bs[r[}bdu}cbrZj9                  b      nd)}e|  d7z  }f	 fjc                         je                  	       ``j                  ^z   }gn^}gg_j9                  dq      dzk(  rnz   }gg }heejs                         reg}hgz   }g 
dFgfd)h| d{__d|   nd) j                         }
      }?|?j9                  dHdN      }i|idCk(  r|?j9                  dd+      nd+}j|?j9                  d~d      }ki dHidd	dYdZd|!j9                  d*d+      d|!j9                  dd+      d|jdb^d|$j9                  dg       xs g d|!j9                  dg       xs g dg d|!j9                  da      xs d+gd   d~kd|?j9                  dJd      d|?j9                  dO      xs d+d|!j9                  d`d+      dd	dj9                  | i       gt        ]d<   d)hk_xs i j9                  d-d+      __d|   nd)      K\bctS        Vj9                  dm      xs d+      ddt        |?      }l`q`j                         ld<   |`j                  |ld<   t        |`j                        |ld<   |`j                  |ld<   |`j                  |ld<   t        |`j                        |ld<   n(d|!j9                  dd+      xs d+d+brbgng dld<   d|ld<   _,|?j9                  d      r_d*   |_d-   dld<   ]dq   d[k(  rdAld<   l| <   idCk(  r{jrytm        j      | <   tm        |j      Z| <   | }[ | |!|j        | |!|j       j;                  | ]d<   |jlj9                  d      |lj9                  d      brbgng dd       dz  vdz  }  tq        |ju                               }mr(dfdtK        fd      tK        mfd      }mn @        t3        t5        |dd	            }nmD ]  \  }o}p|j9                  |o      }q ||q      sddlKmL}r tw        qt              xr* qj9                  d      dk(  xr qj9                  d      rk(  }sqdo}tn6sr
dodr d}tn*dodqj9                  d      d|qj9                  d      d}ttD        jk                  dot       pD ]`  } j9                  |       xs i }!j9                  | i       xs i }$sr|$j9                  db      xs d+j                         rd | dd+dArod      \  }l}j}u|l| <   |lj9                  dH      dCk(  r1jr/tm        j      | <   j;                  | d+o|jdd)udd	       dz  ndz  nrq|$j9                  db      xs d+j                         rd | dd+dAdod      \  }l}j}u|l| <   |lj9                  dH      dCk(  r0jr.tm        j      | <   j;                  | d+|jdd)udd       dz  ndz  C j=                  | |!|$t      | <   dz  c  	  |q      }vvD wch c]C  }wtw        |wj9                  dX      tR              r"wj9                  dX      rwj9                  dX      E }x}wpD ]V  } | xv rj9                  |       xs i }!j9                  | i       xs i }$ j=                  | |!|$d| do      | <   dz  X |j9                  o      xs d)}yi }zvD ]  }{|{j9                  dX      } tw        | tR              r| s(| |vr-| v r2j9                  |       xs i }!j9                  | i       xs i }$|$j9                  dbd+      }^{j9                  dYdZ      }|||dk(  r6{j9                  d      xs d+}}j9                  |}      }~|~tm        ~      js                         sc j=                  | |!|$d}ddy      }ldA|ld<   d|ldY<   |}|ld<   |}|ld<   {j9                  d«      |ld<   |{j9                  dë      |ld<   |l| <   dz  +tS        ~      }{j9                  d      xs i }i dHdCddAdYdd}d|}d|!j9                  d*d+      d|!j9                  dd+      ddb^d|$j9                  dg       xs g d|!j9                  dg       xs g dg d}d~dēdddd+d|!j9                  d`d+      d	j9                  | i       {j9                  dë      d|}j9                  dg       dƜ|{j9                  d«      |{j9                  dë      t        |{j9                  d      xs i       t        od)tm              gdĬǫ      dȜ| <   tm        |      | <   |z| <   j;                  | |o|{j9                  dë      |{j9                  d«      }gdd       dz  t3        |j                        }|rdtw        {j9                  dʫ      t2              fdtw        |{j9                  d˫      tp              fdtw        |{j9                  d̫      t              ffD cg c]	  \  }}|s }}}|r' j=                  | |!|$d| d dϝ      | <   dz  s	  |{oyz  || |o      r      }`d)}rR |{o|oyizѫ      }|d   rtm        d         nd)}d   D acg c]  }atm        |a       }}adD ci c]  }||   
 }}n`j                  D acg c]  }atm        |a       }}a|D acg c]  }a|ajs                         rtS        a        }}a|r2 j=                  | |!|$d `j                         ֫      | <   dz  _`j                  rd   }g }nd)}}|  d7z  }f	 fjc                         je                  	       `j                  ^z   }g |!      }_d)}|_"_d|   }d)}g|_j9                  dq      dzk(  rnz   }g |!      }r_d)}d)}tm        d         } | |!g      }d)}|
d|   }gz   }g | |!g      }d)}|d|   }grnz   }ggz   }gg |!      z   }g 
dF|gf| d{ j                         j9                  dD      rdD   gnd)ث      }?|?j9                  dHdN      }i|idCk(  r|?j9                  dd+      nd+}j|?j9                  d~d      }ki dHidd	dYdZd|!j9                  d*d+      d|!j9                  dd+      d|jdb^d|$j9                  dg       xs g d|!j9                  dg       xs g dg d|!j9                  da      xs d+gd   d~kd|?j9                  dJd      d|?j9                  dO      xs d+d|!j9                  d`d+      dd)uxr js                         dj9                  | i       `j                         |`j                  gt        |`j                        |`j                  |`j                  t        |`j                        t        okxs i j9                  d<d+      xs i j9                  dXd+      xs i j9                  dXd+      _xs i j9                  d-d+      ٫      dڜt        |?      }l_$|?j9                  d      r_d*   |_d-   dld<   dA|ld<   N|?j9                  d۫      r=d<   |j9                  dd+      |j9                  d-d+      |j9                  dDd+      dݜld<   |?j9                  d߫      rdX   |d-   dld<   |?j9                  d      rdX   |d*   dld<   ld<   l| <   idCk(  rqjrotm        j      | <   |jz| <    | |!|j        | |!|j       j;                  | o|j`j                  |`j                  tq        |`j                        dd       dz  dz    r @        fS # tL        $ r#})tD        jO                  d(|)       i Y d)})~)d)})~)ww xY w# tf        th        f$ r tD        jk                  d8|1       Y w xY w# |$ r Y w xY wc c}Mw c c}Mw c c}Tw # tL        $ r>})tD        jO                  dhK|)       tq        N      did+tS        |)      d)dP dj}VY d)})~)@d)})~)ww xY wc c}Ww c c}a}Ww # |$ rC})tD        jk                  ds| |)        j=                  | |!|$dt|)       | <   dz  Y d)})~)d)})~)ww xY w# tf        th        f$ r9 tD        jk                  dv|         j=                  | |!|$dwdxy      | <   dz  Y w xY w# |$ ru})tD        jk                  do|)       pD ]N  } j9                  |       xs i }!j9                  | i       xs i }$ j=                  | |!|$dt|)       | <   dz  P Y d)})~)d)})~)ww xY wc c}ww c c}}w # |$ rC})tD        jk                  d| |)        j=                  | |!|$dt|)       | <   dz  Y d)})~)d)})~)ww xY wc c}aw c c}w c c}aw c c}aw # tf        th        f$ rH tD        jk                  dv|         j=                  | |!|$dwdx`j                         ׫      | <   dz  Y tw xY w)u  W20C opt-in render pass. Consumes the W20B
        ``shot_aware_bg_render_plan`` checkpoint and renders each
        plan node sequentially in ``node_index`` order. The reference
        graph SOT is the LLM-emitted plan; this method does NOT
        re-classify / re-score / fall back. ``render_one_background``
        runs with ``max_attempts=2`` — normal path is still exactly one
        image call per BG (W20 contract); the 2nd attempt fires ONLY on a
        moderation rejection, where the render module sanitizes the prompt
        and retries once (2026-07-11 실측: 상태 bg safety 거부 시 산출 0 방지).

        W-L: ``aerial_loc_context`` (flag OFF = {} = 전부 비활성)가 주어지면
        큐 시작 시 야외 loc(is_indoor==False)마다 실사형 aerial establishing
        1장을 생성/재사용(mode=='force' 만 재생성)하고, 야외 bg 렌더의 ref 를
        fp(평면도) 대신 aerial **1순위** 로 교체한다. ``aerial_diag_out``
        (mutable dict)에 loc별 산출 진단을 채운다.
        r   r   )BUILDING_ANCHOR_PLATE_GUIDANCEBUILDING_FP_PLATE_GUIDANCE*BUILDING_INTERIOR_EXTERIOR_ANCHOR_GUIDANCE$INTERIOR_SAME_BUILDING_TEXT_GUIDANCESAME_PLACE_PLATE_GUIDANCErE  r   )r   AERIAL_SITE_GUIDANCEcompute_aerial_context_hashdecide_group_plate_orderrender_location_aerial)resolve_render_substrate)ShotAwareRenderAdapterErroris_plan_production_clearmaterialize_decisionordered_nodesselect_structure_factsr   FrQ   c                Z    sy  j                  |d      j                  |             S )N r  )rQ   r  r  r  r  r  s     r   
_facts_forzCBackgroundRenderStep._run_shot_aware_plan_queue.<locals>._facts_for4  s4    %)""3+##C( r   rT  surface_roleinterior_room>   site_surfaceexterior_platetransition_zonez(shot_aware_plan: bg has no depends_on_fprw  r   r   c                    syj                  t        | j                  d      xs d            }|syt        t        |j                  d      xs d            }|j                         r|S dS )uG   spec.loc_id 기준 building fp 컨텍스트 (W-G flag ON + png 실재).Nr<   r"   r8  )r   rG   r   is_file)rV   r  r8   _bfp_by_loc	_wg_fp_ons      r   _building_fp_forzIBackgroundRenderStep._run_shot_aware_plan_queue.<locals>._building_fp_fora  s`    TXXh%7%=2!>?BS
+1r23A2.$.r   r   r   r   r8  c                   sr|syt        |j                  d      xs d      }rM
j                  |      }t        |xs i j                  d      xs d      }|r|xs i j                  d      dur7y	j                  |      }t        |xs i j                  d      xs d      }|sy|v ry| |d|<   t        j                  d||        y)	uc  ok 렌더 직후 호출 — 그룹 무등록 시 이 bg 를 anchor 로 등록.

            W-K ON 이면 멤버십 맵 기반 + **outdoor 렌더만** 등록(실내 렌더가
            건물 외관 anchor 가 되는 것을 구조적으로 차단). OFF 면 기존 W-I
            게이트(_bfp_by_loc = mixed 그룹 outdoor loc) 그대로.
            Nr<   r"   r  rq   F)r9   r8  u<   background_render: building anchor 등록 group=%s anchor=%srG   r   r  r    )rQ   rV   r8  rR   rv   r  r  _anchor_by_group
_anchor_onr  _membership_by_loc_wk_ons          r   _register_building_anchorzRBackgroundRenderStep._run_shot_aware_plan_queue.<locals>._register_building_anchor  s      6xdhhx(.B/C&**3/17--
39r:qwBmmK8E __S)28..4:;&&.1x$HS!KKNSr   c                    r|syt        |j                  d      xs d      }|r|v ry| | |      d|<   t        j                  d||        y)uM   W-K: ok 렌더 직후 호출 — loc 무등록 시 이 bg 를 loc anchor 로.Nr<   r"   )r9   r8  interioru@   background_render: same-place loc anchor 등록 loc=%s anchor=%sr  )rQ   rV   r8  rR   _is_interior_render_loc_anchor_by_locr  s       r   _register_loc_anchorzMBackgroundRenderStep._run_shot_aware_plan_queue.<locals>._register_loc_anchor  sh     xdhhx(.B/C#!33$ 05's# KK #r   c                h   ssyr	 |      ryt        |j                  d      xs d      }r4j                  |      }t        |xs i j                  d      xs d      }n3j                  |      }t        |xs i j                  d      xs d      }|rj                  |      nd}|r|j                  d      | k(  ryt        t        |j                  d      xs d            }|j                         sy|D 	ch c]  }	|	t        |	       }
}	t        |      |
v ry|d   ||dS c c}	w )u  이 bg 렌더에 첨부할 그룹 anchor (자기 자신/중복 경로 제외).

            반환: ``{"bg_id", "group_id", "path": Path}`` 또는 None.
            dedup — anchor png 가 이미 ref 목록(자기 fp/substrate prior/building
            fp/loc anchor)에 있으면 None (같은 PNG 이중 첨부 방지, 경로 비교만
            — 구조적). W-K ON 이면 첨부 대상이 그룹 **전 멤버**(실내 포함,
            멤버십 맵 판정), OFF 면 기존 W-I(_bfp_by_loc outdoor)만.
            Nr<   r"   r  r9   r8  )r9   r  pathrG   r   r   r  )rQ   rV   existing_ref_pathsrR   rv   r  r  regr8   rk   existingr  r  r  r  r  r  _wm_ons              r   _building_anchor_forzMBackgroundRenderStep._run_shot_aware_plan_queue.<locals>._building_anchor_for  s.    & -d3dhhx(.B/C&**3/17--
39r: __S)28..4:;/2"&&s+C#'''*c1S,234A99; 2 21amA 2   1v! \sAFFs   D/	D/c                   
syt        |j                  d      xs d      }|r	j                  |      nd}|r|j                  d      | k(  ryr|j                  d      r	 |      syt        t        |j                  d      xs d            }|j                         sy|D ch c]  }|t        |       }}t        |      |v ry|d   ||dS c c}w )u_  W-K: 이 bg 렌더에 첨부할 같은 loc anchor (자기/중복 경로 제외).

            반환: ``{"bg_id", "loc_id", "path": Path}`` 또는 None. dedup —
            anchor png 가 이미 ref 목록(자기 fp/substrate prior/depends_on_bg
            prior)에 있으면 None (같은 loc prior 체인과의 이중 첨부 방지).
            Nr<   r"   r9   r  r8  )r9   r<   r#  r$  )rQ   rV   r%  rR   r&  r8   rk   r'  r  r   r  r(  s           r   _loc_anchor_forzHBackgroundRenderStep._run_shot_aware_plan_queue.<locals>._loc_anchor_for  s     dhhx(.B/C14$((-$C#'''*c1
 #''*-6I7S,234A99; 2 21amA 2   1v! \S!DDs   'C/Cc                8    | j                  dd      xs d}|dk(  S )u9  W-M: '실내 렌더' 판정 — bg ``surface_role`` 구조 필드(SOT).

            interior_room(또는 필드 부재 = interior 기본 — W21B-wave-2 의
            direct-plate 분기와 동일 규칙)만 실내 렌더로 본다. 실내 분류
            loc 에 걸린 exterior_plate/transition_zone/site_surface bg
            (예: 실내 anchor 건물의 저녁 외관 plate)는 실내 렌더가 아니다
            — loc is_indoor 로 판정하면 그런 외관 plate 의 anchor 연속이
            끊긴다(간판/외관 연속 회귀).
            r  r  r  )rV   roles     r   r  zLBackgroundRenderStep._run_shot_aware_plan_queue.<locals>._is_interior_render  s)     9L_  ?**r   c                    rsy |       syj                  t        | j                  d      xs d            }|r|j                  d      rS y)u  W-M(1): mixed 그룹 **실내 렌더** bg 의 문구-only 연속 계약.

            그룹 anchor(외부 렌더) 첨부에서 실내 렌더가 제외된 뒤, 실내
            plate 의 실내↔실외 연속성은 이미지 ref 없이 이 문구만으로
            유지한다. 판정 = 실내 렌더(surface_role) ∧ mixed 그룹 멤버십
            (구조 데이터) — W-M ∧ W-K ON 일 때만(멤버십 맵이 W-K 로더
            산출).
            r"   r<   group_mixedr   rG   )rV   rv   r  r  r  r  r(  s     r   _interior_text_guidance_forzTBackgroundRenderStep._run_shot_aware_plan_queue.<locals>._interior_text_guidance_for"  sR     v&t,"&&s488H+=+C'DEAQUU=);;r   r   r   )build_seed_plate_refsoutdoor_structure_seedrA  r   rt   ro   u9   background_render: seed 플레이트 참조 %d loc — %suO   background_render: seed 플레이트 컨텍스트 로드 실패 (비차단): %sNr<   r"   rq   r  )locsr  r4  r  z[A-Za-z0-9_\-]+hr   r   uX   background_render: aerial group id %r 비안전 문자 — 파일명 해시 평탄화 %saerial_rU  uJ   background_render: aerial out_path escapes image_dir for group %s — skipr/  group_members
anchor_locr.   )r  rp   r8  fp_sotr   context_hashr"  T)r8  cachedr  r7  r  )	r}   r8  r;  building_fp_usedr  r   r:  r4  r8  ra  )r   rb  place_idrp   rd  r$   capture_input_image_idsr}   r<  rg  prompt_used)r}   r8  r;  r<  r  rg  r?  r   r:  r4  r8  u=   background_render: aerial 생성 group=%s locs=%s (fp_ref=%s)rf  rh  r  )r}   r;  r<  rg  r/  r4  r8  u^   background_render: aerial 생성 실패 group=%s — 기존 fp 경로로 진행(fail-safe): %sc                   t        | j                  d      xs d      }|rormj                  |      }|rZt        t        |j                  d      xs d            }|j                         r#|t        |j                  d      xs d      |ddS sy|rj                  |      nd}|syt        t        |j                  d      xs d            }|j                         sy|t        |j                  d      xs d      |d	dS )
u  이 bg 렌더에 1순위로 첨부할 그룹 공간·룩 참조 (야외 loc 만).

            2026-07-19 재설계 A: **장소 seed(정면 실사)가 우선** — 사용자
            확정(위성/항공 배치도 형태 참조 금지). seed 없거나 flag OFF 면
            기존 aerial 경로(레거시, 별도 flag). 반환:
            ``{"loc_id", "group_id", "path": Path, "kind": "seed"|"aerial"}``
            또는 None. 호출부는 kind 로 guidance 절을 분기한다.
            r<   r"   r#  r  seed)r<   r  r#  kindNr8  aerialr$  )	rV   rR   sregspr&  r8   _aerial_by_loc_seed_plate_by_loc_wl_ons	         r   _aerial_forzDBackgroundRenderStep._run_shot_aware_plan_queue.<locals>._aerial_for  s     dhhx(.B/C))--c2c$((6"2"8b9:Bzz|&)(+DHHZ,@,FB(G$&$*	   -0.$$S)dCS,234A99;
 3 9r: 	 r   )decision_fp_iddegrade_metac               	   +j                  |       xs i }0j                  | i       xs i }|j                  dd      }|j                  dd      xs d}g }|j                  d      xs g D ]8  }	2j                  |	      }
|
|
j                         s(|j                  |
       : .|  dz  }	 |j                         j	                  /        $|      }|} "|      }*r|d}d}|t        |d         }d}| |d   }||j                  d      dk(  r!nz   } &| ||g||      }d}|
|d   }| z   } #| ||g|||      }d}||d   }|)rnz   }||z   }| %|      z   } 1-d||d|| d||||3j                         ||j                  d      r|d   gnd      }|j                  dd      }|dk(  r|j                  dd      nd}|j                  dd      }|D 
cg c]  }
|
j                   }}
i d|d|j                  dd      d|j                  dd      d|d|d|j                  dg       xs g d|j                  dg       xs g dg d |j                  d      xs dgd!   d|d"|j                  d#d!      d$|j                  d%      xs dd&|j                  d'd      d(d)d*,j                  | i       d+||||d,d-|d.|it        |      d/t        |d|||xs i j                  d0d      ||xs i j                  d1d      ||xs i j                  d1d      ||xs i j                  d2d      |3      i}||j                  d4      r|d   |d2   d5|d6<   |N|j                  d7      r=|d0   |j                  d8d      |j                  d2d      |j                  dd      d9|d:<   ||j                  d;      r|d1   |d2   d<|d=<   ||j                  d>      r|d1   |d   d?|d@<   |r|j                  |        '| ||        (| ||       |||fS # t
        t        f$ r5 t        j                  d|        3j                  | ||,dd	
      }|dg fcY S w xY wc c}
w )Au  Render one bg via the direct-plate (text_only + prior-bg)
            path and build its group entry. Shared by the surface-role
            direct-plate lane and the TASK3-B missing-shot_aware_plan
            fallback. Returns ``(entry, png_path, source_bg_stems)`` —
            ``png_path`` is '' when the render did not succeed (failed /
            rejected path); the caller owns ``rendered_paths`` registration,
            catalog growth, ``ingestion_counter`` and ``failed``.
            ``mode_label`` stamps ``shot_aware_plan_mode`` +
            ``reference_decision.mode``; ``degrade_meta`` (optional) is
            merged into the entry for visible graceful-degradation marking.
            rQ  r"   r  r>   NrU  rV  r\  rW  rQ   rV   rn  rq  r/  r}   r8  r#  rB  rA  ra  r=   r  r   rb  rc  rd  r6   r7   r9   max_attemptsr$   r&   same_place_anchor_pathaerial_ref_pathre  r>  r}   rf  r7  r1   rY  r~   r<   r   r{   rR  r   r|   rX  rF   r   rZ  rg  r[  rh  r]  rS  r^  Fr9  r  r  r  r.   source_bg_idseffective_render_promptshot_aware_plan_moder_  r.   r9   r  r.   r6   r7   r1   r#   r$   r%   r&   r'   r(   r)   r*   aerial_ref_attachedr<   r  
aerial_refbuilding_fp_attachedindoor_loc_sidr.   r[  r  r  building_fp_refbuilding_anchor_attachedrC   r  building_anchor_refsame_place_anchor_attachedrC   r<   same_loc_anchor_ref)r   r3   r4   ri  rj  rk  rl  r  r/  r  r   r$  r5   r!   r:   r  )4rQ   
mode_labelrJ  rK  rV   rn  rQ  r  r7   rp  r8   rd  rejectedbfpeffective_promptrC  bfp_pathr*   	sp_anchorsp_anchor_pathrU   anchor_pathr    r}   r8  r1   source_bg_stemsr  r  r  r  r  r  r   rI  r)  r  r1  r+  r  r!  r  r(  rM   rq  rr  rs  rt  ru  rE  r  r   s4                               r   _render_direct_platezMBackgroundRenderStep._run_shot_aware_plan_queue.<locals>._render_direct_plate+  s8   $ <<$*D&??339rL%)),;J88NB7=2L)+Nxx06B6"&&s+=QXXZ"))!, 7
 !cU$</H(  "../AB$ #4(C) !&F&, '+HJ0*.K!$Vn#3zz&)V3 '-$/  (TKC.C(CEI-1N$!*6!2$'@@ ! *TH~HxHHJF +/K!$Vn#3 ?#A$  $'AA ! !#>t#DD  )$4'!-
 !)%0'5 +$($=$=$? 377=+A '(+D0 XXh1F39T>txx
B/rHxx
K8H/=>~!qvv~O>(&(txx"5(  ."!=( H	(
 j( |//rBHb( DHH%7<B( "( dhh7?B4C( H( "488J#:( )= > D"(  -!<( "5( )*;*?*?R*H(  %&$0+%4	'!(, *+;-(. '
/(2 ).3(4 -.O( #1%$'I2??7B#?%-+1<R*<*<Wb*I)4+4?*?*?*L)7#)<R"4"4Z"D +/5(ER !dhh/D&E %X. &z 2'l# 488,B#C !\&)gg.>&C #
B 7#&77="#=	,'( !dhh/I&J %+7O &z 20+, $2N)O %.g$6'10+, \*%c4: dH5(O33Y ( (JC  ::!-&76* ;   R''(H ?s   0P5 -Q<5AQ98Q9c                     D ]c  } | v r | d      \  }}}|	| <   |j                  d      dk(  r0|r.t        |      | <   j                  | d|dd|
dd       
dz  
_dz  e y)	uN  direct-plate lane — fp 없는 non-interior surface bg 렌더.

            W-K OFF: 기존 위치(fp lane 앞)에서 즉시 실행(byte-identical).
            W-K ON: fp lane **뒤**로 재배열 — 외부 establishing(fp lane 의
            outdoor)이 먼저 렌더되어 loc/그룹 anchor 의 기준이 되도록.
            surface_role_direct_plate)rd  r}   r7  r"   Nr9   r.   r8  r  
node_indexrS  ingestion_ordersource_kindr   )r   r   r4   )rQ   r  r8  rl  rm  _stage_chain_handledr  direct_plate_bidsrf  r  ingestion_counterr  s       r   _run_direct_plate_lanezOBackgroundRenderStep._run_shot_aware_plan_queue.<locals>._run_direct_plate_lane  s     )..3G$?40x #(
399X&$.8*.x.N3' ''!$!#$, ;&*)8+<'B	) 	 &*%aKF- )r   c                    j                  t        | j                  d      xs d            }|r"t        |xs i j                  d      xs d      S dS )Nr<   r"   r  r0  )rV   r&  rF  s     r   _chain_gid_forzGBackgroundRenderStep._run_shot_aware_plan_queue.<locals>._chain_gid_for%	  sJ    $((TXXh-?-E2)FGADsCI2??:6<"=L"Lr   r9   render_actionrender_new_platenode)rQ   rB  r.   r|  directlabelsummaryrS  r>   rQ  )r9   location_labellocation_summaryr  rS  
depends_onrQ  )call_structuredplate_order_group)extra_metadata)r  
candidatescall_structured_fnr#  opik_metadatauT   background_render: plate order 결정 실패 group=%s — 구조 순서 fallback: %sfallback_structural)rN   order_sourcefirst_reasonr/  rN   z<background_render: stage chain group=%s order=%s (source=%s)r  r  r/  stage_chainrB  )r|  r.   base_fp_png_strr  validate_reference_catalogstructure_factsz7background_render stage chain decision failed bg=%s: %szshot_aware_plan: chainrV  r\  rW  rM  rA  r=   r#  )
r   rb  rc  rd  r6   r7   r9   rO  rQ  re  r1   rY  is_reuser~   r   r{   rR  r   r|   rX  rF   rZ  r[  r]  r^  r9  )r.   r6   r7   r1   r)   r*   )r  chain_index
prev_bg_idprev_sourcer  )rT  r_  r  r  reference_guidance_prefixcamera_decisionshot_aware_plan_node_indexrU  render_guidancero  rR  rW  rX  rY  fp_ref_replaced_by_aerialstage_chain_platerp  c                    j                  t        j                  |       xs i j                  d      xs d            }t        |xr& |j                  d      xr |j                  d      du       S )Nr<   r"   r/  rq   F)r   rG   r   )brv   r  rM   s     r   _is_mixed_outdoor_loczNBackgroundRenderStep._run_shot_aware_plan_queue.<locals>._is_mixed_outdoor_loc
  so    &**a.B33H=CDF 4!%%. 4k*e35 5r   c                     |       rdS dS )Nr   r   r
  )r  r  s    r   <lambda>zABackgroundRenderStep._run_shot_aware_plan_queue.<locals>.<lambda>
  s    #8#;aBBr   )keyc                :    t        fd| d   D              rdS dS )Nc              3  .   K   | ]  } |        y wNr
  )r  r  r  s     r   r  zTBackgroundRenderStep._run_shot_aware_plan_queue.<locals>.<lambda>.<locals>.<genexpr>
  s      (=6;)!,es   r   r   )any)kvr  s    r   r  zABackgroundRenderStep._run_shot_aware_plan_queue.<locals>.<lambda>
  s,    C (=68e(= %=q  DBC Dr   r   )#CAMERA_LOOKAT_NOT_APPLICABLE_REASON shot_aware_bg_render_plan_statusnot_applicablenot_applicable_reason_codez(shot_aware_plan: plan missing for fp_id=z6shot_aware_plan: camera geometry not plannable (fp_id=z reason_code=u   ) — direct-plate routez2shot_aware_plan: plan not production_clear (fp_id=z status=z production_clear=production_clear)z7background_render shot_aware_plan gate failed fp=%s: %scamera_geometry_direct_plate)render_degradedfallback_reasonsource_fp_id)rd  rJ  rK  )	r9   r.   r  r8  r  rq  rS  rr  rs  "missing_plan_direct_plate_fallbackshot_aware_plan_missing)r  r  missing_fp_idz=background_render shot_aware_plan node order failed fp=%s: %szshot_aware_plan: bg_id=z# missing from plan graph for fp_id=reuse_existing_platereuse_target_bg_idzshot_aware_plan: reuse target z has no rendered platereuse_target_missingreused_from_bg_idrq  r  reused_plateselected_refs)r  rz  r  r  r`  )r^  r9  r  r  rU  r  r_  shot_aware_plan_reuseneeds_new_plateref_tree_parentsref_role_per_parentz3substrate_requires_schema9_plan_fields: node bg_id=z missing/malformed u`    — re-run shot_aware_bg_render_plan (SCHEMA_VERSION>=9) before enabling the substrate consumerz;background_render shot_aware_plan decision failed bg=%s: %s)	plan_noder.   fp_png_by_fprendered_plate_png_by_bgr6   ordered_prior_bg_paths)
node_classr1   r  missing_parent_bg_idsordered_parent_bg_idsr0   z,shot_aware_plan: reference path unresolved: )rQ   rV   rn  rq  r/  r  )rQ   rV   rn  rq  r/  r}   r  rN  rV  )r  r  rT  r  r  rU  r  r_  rZ  r[  r\  r]  r^  r_  r`  ra  rb  rc  substrate_decisionr   )rQ   rG   r  rG   )rV   Dict[str, Any]r  zOptional[Dict[str, str]])rQ   rG   rV   r  r8  rG   r  None)rQ   rG   rV   r  r%  zList[Optional[Path]]r  Optional[Dict[str, Any]])rV   r  r  r   )rV   r  r  rG   )rV   r  r  r  )
rQ   rG   rd  rG   rJ  rG   rK  r  r  z%Tuple[Dict[str, Any], str, List[str]])r  r  )r  rG   r  r   )Rr   r   r  r  r  r  r  r  rE  r   r   r   r   r  r   r  r  0app.modules.pipeline.background_render_substrater  1app.modules.pipeline.shot_aware_bg_render_adapterr  r  r  r  r  r   r   r_   r   r4   r  rI   r2  r   r  r    rK   rL   r   r  r`   rG   r  re	fullmatchr   r   r   r   ri  rj  rk  rl  r/  r   r  ra   r3   rJ   r  app.modules.llm.llm_clientr  r#  build_opik_metadatar  	enumerater  r$  r:   r!   to_dictr  rq  r  r  .app.modules.pipeline.shot_aware_bg_render_planr  rH   r   reference_pathsfp_includedrS  )r   rM   ru  r  rq  r{  rO   rN   rs  rt  rr  r|  r}  r~  r  r  r  r  r  r   r   r   r  r  r  r  r  r  r  r  renderable_set	bgs_by_fprQ   rV   deps_fpr  rn  _aerial_ctxr2  _seed_cp_bgc_cpr  _aerial_diag_wl_locs_b_bids
_wl_groups_locr  _gid_g	_grp_locs_fn_gidr   
aerial_outr  _l_fp_ref_path_p	_ctx_hash_prior
_prior_ver
_prior_ctxr    rw  ry  _chain_cands_chain_seen_c_fp_id_c_bids_c_plan_c_nodes
_c_bid_set_c_node_c_bid_c_gidcandsr  cand_idscand_by_bidcand_id_set_order_cands_o_spec_o_ctxdr  
_order_resr  _c_order_g_diag_chain_ok_paths_last_ok_bid_c_idxcandrQ  rC  decisionr8   	_prev_bid_prev_source_dep
_prev_pathrd  rg  _priorsr}   r8  ref_used_auditr  fp_lane_itemsmissing_plan_fallbackr.   	fp_bg_idsr@  r  camera_geometry_nar  rl  nodesnplan_bg_idsbase_fp_strr  r|  rz  	target_idtarget_pathtarget_path_str	ref_auditsubstrate_onfr7  missing_fieldsr  subr6   r7   r  ref_path_objsmissing_refsr*   rf  rh  ri  rj  rU   rk  r  r  r  r  r  r  r   rF  rI  r  r  r  r)  r  r1  r  r  r   r+  r  r  r!  rm  rG  rt  r  r  rH  r(  r  ru  rf  r  rv  rE  r  r  r  s   ``` `   ```     ``                                                                                                                                 @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@r   r  z/BackgroundRenderStep._run_shot_aware_plan_queue  s1(   V 	-	
 	
	
	
 	
	
	
 	
 13
*,-/
 "'5u#> ?'-2)/R	 	 Z
 +-	')C.(<<$*Dhh/52G#xxH[O#XX%,,S1*sB7=2"&"A"A!-&7D #B #
3 !  R077<) ,  ).BH?GI		/4 HCUKM
H?GI HA5IK4:688:		*	69		 	<		*	69		,,	G,	G ,	G !5,	G &	,	G ,	G\ 	E 	E  	E !5 	E &	 	E  	ED	+	 	0 g8%A B(.B 57 9;@%I J(  55,.445JK%:n"))&"5;@@ " (%'m((4:??)+ 1.0	&" &KKS./12  /:O 	 kEH'b)/R44X>D"EG ( #))+BLLX\\"-388BHbIK   , 57Jx(!ood+cggk2%?377:.4"5**4"S1IJ6
!!$' ) z*'1$'7'?	 &u-
 << 2D9"G.!HOOG,%..7ik#2%? ?GNN<=A7L '77)4)@@
&&(445GH 77=)'&??2.!,!4B! ( 04>c"&&"4":;<Bzz|')
 8! !9!?R@"377<#8#>B?b~~g6<"=		 16B;;DAGR ,<!=!CD
 N!;!ArB
%%'"&;;"i/ ((+J&*(,.r* ( #'$'
O"&,0,>@BC} 5 ;<*?(1 $Y&)#'',*?*E2&F*L& -"( 8! !9!?R@'%1 "&&"7 RVVM234=A 88H%-$((:2F'(,Z(8&+(,.r* ( #'$($4"',0 HH%78-: ACC} 5 ;<$(HHZ$;'+xxr'B*- HH%56<"+>(1 $Y&)#'',*?*E2&F*L&  KK&'+Y\8JL #+"',0 HH%78-:$(HHZ$;!$ HH%9:@b"BBF3"H $Y&)#'',*?*E2&F
*L& NNDdhh';<>S +\"	P #%59K	4K	4 K	4  	K	4
 3K	4 3K	4 K	4 K	4 K	4Z	  	 V %(EfM =?L"uK%.__%6!'&**84/8,W5H !\
'G$[[1F&vs3%!7!3![0 {{');+, !+HLL,@,FBGF! OOF+ ++FB7>>%v!)7@ %  ( &7> ,[('V(<(BC'''3::!8b <  , !.$V,.34eAeHe449:Eqqx{E:!(m57A&ll1U84:G(__GKK17R8: @=?  ''!"5*-fjj.A.GR*H,/

90E0K,L(+#KK7=2)?'*7;;}+E+K'L(/O(D(J(J'(J! K/ (J'
 (OOAeHb9?R#lB/) 	 &J!9!'#/+:'+':':&*&>&>,?+H '? 'J"J& !+w 7 C8 C C!K'  C   "#)8NN>24 '**62gt,!%h(+&NN>:@b)B(+&NN>:@b)B!$Z^^G%<%B!C.GM* 46!#,X#6KFC&s+D(,,S1#<<,2D#.??3#;#ArL!-!1!1,!CJ(.F#HF|v-%';%)&\&*7m$0$4$4T']$C$Kt 1@0E0E0G)"0G1 %&s1vI0G)" <A0:$'g18(HD !#I#%L!%/!:!@b!@?2(+D	I+:L!	 "A
 %$0	'.:C++I6   )cU$<7H! ((*667IJ   +$>>K ) ,6('7zz&)V3 '-(/$ +-G!-*2C2C2E#-,,/HH ) 1&,$</!) $'.!
 .4.@F6Nd,0,E,E,G!D$ "XXh9F4:dNR0  &*XXj+%FN/ &/"E/ ();/ &txx"'=	/
 (.")E/ #H/ %j/ &(,,]B?E2/ #DHH-?$D$J/ !"/ $dhh&?&GB4%K/ #N/ *488J+B/  '1E(F(L"!/" (-)D#/$ *5%/& 12C2G2G3%'/* 4D=&*7m(,/6)7%+\r$6$6z2$F (.'9 %+6N?C )/+1*3+7,/ *~ > D"-F(K/\ 16]/E`  +6>6F6F6H23$>> 9: 48$4446/0 %// :; 9A4537$4446/0 %@ $ < B%'/8b723 8 45 )dhh7L.M
 '-X&6(.z(:/l+  <61AEE"=>&+JsO~(.28ns+/3H~,'*1#tXF,S$A$++%(%)'](0$)II.D$E*/)) <+> 09b/@+>-  *Q.)!} $7G /N	 Y__./5 !'!B!D #DEM
 #$ !%L!
 !.E9##E*D+D1
 tT* ;!CD'(; !=>:;	 # <B5)L  (""'->? @-- ""' +""&((+M"N!Q R,,0HH5G,H+K1N  M6 %C#<<,2D#.??3#;#ArL*)--l;ArHHJ
 1 #$B/17;(K49." 9x  +0
3 99X.$6826x.N3/(//),)+05,4(F.21@3D$B1  .2-"aKF 
 . L)--l;ArHHJ;O'K+-373L16*		<8x +0
3 99X.$6826x.N3/(//),)+,4(L.21@3D/S	1 	 .2-"aKF &*&E&E!%1*;$ 'F 'JsO aKFo %p %d+* AaeeGnc2quuW~ g  
 !+%||C(.B*sB7=2"&"A"A!-&71# 9005y: #B 	#
3 ! !" *6)9)9%)@)HDK&(Ghhw'!#s+3n,
 ..
 ||C(.B*sB7=2)--lB?
 !%:L M $:: $)= > D"I"0"4"4Y"?K"*${2C2J2J2L !% ? ? #!%)5.?"@#,-/E!G $: !@ 
! -1j)1Go.6?235>12>Bhh(?:; 9=8H45*/
3! &)+&6O $)= > D"I,' $,'"D,' ()?,' -i	,'
 ,Y,' &txx"'=,' (.")E,' #O,' %j,' &|'7'7r'J'Pb,' #DHH-?$D$J,' !",' $Y,' #N,'  *1!,'" '#,'$ (-)D%,'& ,12C2G2G3 %)HHV$4-C2;-6]] /.	/ 7;hh|6L040@+/ HH%67=2, >&+(,04_0E/F)7	K,'JsO` +/*?N3'#2GCL ''!$!&$3 $ 0&*hh|&<*3+<'>	) 	 &*%#H$H$HI   /'1B(CTJL/'1C(DdKM2'1F(GNP(	&(ea "$  ( # 	& &*.*I*I #!%)5.?!..1W4G#1"2 3+!, +J +
3 ! 3!#(3 '
 8D3C(23(> H: @D" 3"&#&+[%918	C 14IS^,D  *--E)F2)FAQ)F # 2,*,a3q6	 , ' * 7?6N6N$O6NT!W6NM$O(5$(51QXXZA ! $ $*.*I*I #!%)5.?"N#/.!2 +3*:*:*< +J 
+
3 ! ++"/"2)+"&)6$#d|3$$&223EF& 66C ! %T*.2%"(.K"G'7zz&)V3 '-(/$ 't,f0 C+/?#C
O4H , 'ENEHEG	 26(%.v%6N(+DD % . ' %N %H %#%& /3%"(.K'7! C'E($ ?(+EE % %'B4'HH ! -"( 8+%##1
 %-)4+9$/(,(A(A(C ?sww}/E ]+,!+0 (H57=~488J32!%*k!B7f7 7 $%7	7
 "488Hb#97 $TXXnb%A7 7 !*7 "<#3#3M2#F#L"7 );R @ FB7 b7  $((?";"CtQ!G7 7 &txx
A'>7 #DHH-A$B$Hb7  $TXXmR%@!7" &t+@0@%7( -.?.C.CC.L)7, +3*:*:*< ::/?'+H,D,D'E2:2E2E,4MM (,H,D,D'E
 3T# ''5!/(+	rw'C)1/5|.@.@".M-8%OSS"-=-;'-|&8&8R&H$/3M7l -T2m7p %$((3H*I #)"2$*:$6+E,' :>E56?txx0F'G "%W*-''2BB*G$'GGJ$;'*ww}b'A	0E+, %$((3M*N )/w$*:$64E/0 (TXX4.6 )2'(:"+H"54E/0 &12DE./"'
3T>h*.x.N3'#+GCL-c4B(dH= ''!$!&$, (&.&9&9)-h.D.D)E+<'8	) 	 &*%aKFY a !.B "$>6<??U.  ('(+- &("	(d #G, LL:;?A 	N 3 N 5:'$ ! 	NN9:@#G "&h(=(*!$S$3	"J		R)"  ; %"LL!347> /3.M.M$'%)-92C(9#&? /N /JsO #aKF$%B '0 !%&)+ +/*I*I #!%)5.?">#2 +J +
3 ! !X
 / S3 %C#<<,2D#.??3#;#ArL&*&E&E!%1*; 1#7 'F 'JsO aKF % !$r	&R 3 LL$S
 '+&E&E!%1*; 1#7 'F 'JsO aKFH2* %P$8 #G, LLN '+&E&E!%1*;:.&.&6&6&8 'F 'JsO aKFsi  *B2Av4 )Aw#4Ax$Ax6Ax ;Ax%=/Ax*Ay4=4Ay?1Ay9Ay?3A{
PA|P AA~`A~
aA~bA(b.A-cA2c$A7c:A7eA<v4	Aw v=AwwAw w#%AxxAxxAxxAxx*	Ay1x33Ay,y,Ay1y9Ay?y?A{z8A{{A{{
AA||A||A~|A*A~
~
A~~A%~"8A  A%<ABAABAc                   ddl m} ddlm}m} | j
                  j                  |      j                  |j                  | j                  k(  |j                  dk(        j                         }|D ci c]&  }|j                  s|j                  |j                  ( }	}|	st        j                  d       yi }
i }t        t!        |dd            }i }g }|D ]u  }|j#                  |      xs i }|j#                  d	      d
k7  s|j#                  d      s>|j#                  dd      xs d}|sW|
j#                  |d      }|||<   |dz   |
|<   w t%        j&                  t(        j*                        j-                         }t/        |j0                        j2                  }d}i }t5        |xs i j7                               D ]  }|xs i j#                  |      xs i }|j#                  d	      d
k7  s|j#                  d      sC|j#                  d      xs g D cg c]  }|st9        |       }}d}t9        |j#                  d      xs d      g|z   D ]  }|s|	j#                  |      s|	|   } n |st        j                  d|       	 t9        t/        t9        |d               j;                  |            }d| }| j
                  j                  |      j?                  | j                  | j@                  d||      jC                         }|du } |r=||_"        t9        |j#                  d      xs d      }!|!r|!|_#        d|_$        d|_%        n| |t9        tM        jN                               | j                  | j@                  d|dd||t9        |j#                  d      xs d      ddd|      }| j
                  jQ                  |       t9        |j#                  d      xs d      }"t        |j#                  d            }#tS        |d|#r| sdn|j#                  d      r|"r|"gng ||t9        |j#                  d      xs d      |#t        |j#                  d            t9        |j#                  d      xs d      t9        |j#                  d      xs d      d        |D ]  }$|j                  ||$<    |dz  } i }%| j
                  j                  |      j                  |j                  | j                  k(  |jT                  d!k(        jW                  |jX                  j[                         |j\                  j[                               j                         D ]7  }&|&j^                  s|&j^                  |%vs|&j                  |%|&j^                  <   9 |D ]  }'|j#                  |'      xs i }|j#                  d	      d
k7  r.|j#                  dd      xs d}(|(sG|j#                  dd      xs d}|	j#                  |      })|)st        j                  d"|'|       	 t9        t/        |(      j;                  |            }*|j#                  |'d      }+|j#                  d#d      xs d$|+d%},|j#                  d&g       xs g }-g }.|-D ]  }/ta        |/tb              s|/j#                  d'd      xs d}0|/j#                  d(      xs |/j#                  d)      xs d}1|1sU|0r|.je                  d*|0 d+|1        o|.je                  |1        |.rd,jg                  |.      nd}2| j
                  j                  |      j?                  | j                  | j@                  d-|)|'      jC                         }3|j#                  d.      xs |j#                  d/d      xs d}4|3r;|*|3_"        |4|3_#        |+|3_4        |,|3_5        |2|3_6        d|3_,        d|3_$        d|3_%        |3}5na |t9        tM        jN                               | j                  | j@                  d-|)|+|,|'|2|*|4ddd|0      }5| j
                  jQ                  |5       |%j#                  |)      }6t9        |j#                  d1      xs i j#                  d2      xs d      }7g }8|7r(|j#                  |7      }9|9s|8je                  d3|7z          n|6}9t9        |j#                  d4      xs i j#                  d      xs d      }:to        tb        jq                  d5 |9|:fD                    };|;rtS        |5d6|;|8rd7|8ind        n!tS        |5d6d7|8xs d8t9        |)      z   gi9       |5j                  ||'<   |r|j#                  d:      xs i }<g }=|<j#                  d;      xs g D ],  }>t9        |>      }?|?s|?|'k7  s|?|=vs|=je                  |?       . |<j#                  d<      d=k(  }@g }At9        |j#                  d>      xs i j#                  d?      xs d      }B|BrAje                  d@Bf       t9        |j#                  dA      xs i j#                  d?      xs d      }C|CrAje                  dBCf       |=sAr|je                  |5|9|=@|:A|8f       |dz  } |r|D DEch c]  }D|DdC   D ]  }E|E  }F}D}E|F|D DGHch c]  }D|DdD   D ]  \  }G}H|H	  c}H}G}Dz  }Ftc        |      }I|FD Jcg c]	  }J|JIvsJ }K}J|Kr| j
                  j                  |jr                  |j                        j                  |j                  | j                  k(  |j@                  | j@                  k(  |jT                  d-k(  |jr                  ju                  K            j                         D ]  \  }}L|s	t9        L      It9        |      <   ! |D ]  \  }5}M}=}@}N}A}Otw        |=|MI|@E      \  }P}Q|OD ]#  }RQjy                  d7g       je                  |R       % AD ]M  \  }S}TIj#                  |T      }U|UrUPvrg PU}P$Ur'Qjy                  d7g       je                  SdFz   Tz          O Nr
NPvrg PN}PtS        |5d6Pxs dQ         |rM| j
                  j{                          t        j}                  dG|t        |      |rdHt        |       dInd       yyc c}w c c}w # t<        $ r t9        |d         }Y 
w xY w# t<        $ r |(}*Y w xY wc c}E}Dw c c}H}G}Dw c c}Jw )Ju  Phase 7 — bg PNG를 ImageAsset(asset_type='chain_bg') UPSERT.

        Phase 5 ``background_chain_render_step._register_chain_bg_image_assets``
        패턴 미러. variant_index는 loc_id 단위 1+ counter (v00은 floor_plan).
        deterministic을 위해 ``order`` (master_plan gen_order에서 파생) 순서
        대로 counter 증분.

        match key (application-level): (project_id, episode_id, asset_type,
        entity_id, variant_type=bg_id).

        W-L: ``location_aerials`` (loc별 aerial 진단, status=='ok' 만 대상)가
        주어지면 aerial PNG 를 ImageAsset(asset_type='location_aerial',
        variant_type='aerial_<loc>') 로 먼저 UPSERT 하고, ``aerial_ref``
        구조 필드를 가진 bg row 의 input_image_ids **1순위** 를 loc 의
        floor_plan UUID 대신 aerial UUID 로 교체한다(실제 첨부 SOT 정합 —
        야외 bg 는 fp ref 가 의도적으로 제외됨). None(default) = 기존 경로
        byte-identical.
        r   r   )EntityCanonr  locationuF   background_render: no location EntityCanon — skip ImageAsset DB syncN1background_render_record_prior_bg_lineage_enabledFr}   r7  r8  r~   r"   r   r4  r8  u@   background_render: aerial group %s has no canon — skip DB syncr6  location_aerial)r   r   r  	entity_idr  r?  	generatedra  rC  )r  r   r   r  r"  variant_indexr]  r  	file_pathr?  generation_modelr}   
is_primary
created_atr  r;  r<  r   r:  )r  r4  r8  r;  r<  r   r:  )pipeline_roleinput_image_idspipeline_metadatar  u=   background_render: bg %s loc %s has no canon — skip DB syncr]  r  02drR  shot_id
guide_textguide[z] 
chain_bgrT  rQ  )r  r   r   r  r"  r$  r]  r  	t2i_guider%  r?  r&  r}   r'  r(  rY  r<   zlocation_aerial:r]  c              3  &   K   | ]	  }|s|  y wr  r
  )r  rk   s     r   r  z>BackgroundRenderStep._register_image_assets.<locals>.<genexpr>^  s      ,:3aq3s   ry  r^   zfloor_plan:)r)  r+  r_  r/   r1   r  rc  rC   same_loc_anchorr`  building_anchorr=      )rd   :zNbackground_render: registered %d ImageAssets (chain_bg + %d location_aerial)%sz (star anchor lineage: r  )@r   r   r  r  r  r  r  r  r   entity_typer  short_idr  r  r  r   r   r   r   nowr   utc	isoformatr   r   parentrL   r  rG   rj  rk  	filter_byr   firstr%  r?  r}   r&  uuiduuid4r`   r   r  order_byr'  descr(  r"  r  r  r4   joinr$  r]  r3  ra   fromkeysr  r  rm   rI   commitr    rK   )Vr   rt   rN   rz  r   r  r  canonsr  canon_id_by_shortlocation_countervariant_idx_by_bg_star_enabled_star_uuid_by_bgid_star_pendingrQ   r  	loc_shortnext_idxr;  projects_root
registered_aerial_uuid_by_locr  _aerk   _ae_locs_canon_cand_rel_vt_row_is_new_row_pu_ae_fp
_ae_cachedr  _fp_id_by_canon_fpr9   png_path_strcanon_idrel_png_pathr$  r]  rR  guide_linessgsidr/  t2i_guide_textr'  prompt_used_value_bg_row_fp_id_for_bg_aerial_loc_p1_unresolved_first_uuid	_bfp_uuid
_base_iids_lin
_prior_idsr  _bs_reuse_row_anchors_sp_bgid_anchor_bgid_tupr8   _needed_a	_resolverr  _missing_aid_fp_uuid_row_bfp_pre_unresolved_iids_meta_u_kind_abgid_anchor_uuidsV                                                                                         r   r  z+BackgroundRenderStep._register_image_assets&  s   0 	-> GGMM+&V&&$//9'':5 SU 	 '--
&,

AJJf 	 -
 !NNX  ,.,.
 WI5R S79  	 C**S/'RCwwx D(
0Cr28bI'++Iq9H%-c"*2Q,Y'  ll8<<(224X223::
 /1,288:;D#)r..t4:Cwwx D(
0C),)>B)>E)>11A)>HEFsww|4:;<xG.2259.u5F H #$(* ,4C
O 45AA!# $ D6"Cj)##0$!$     $,K!%#''-06B7'*D$)(@%!4::<(##0$"#"*!$" #CGGM$:$@b A%=& "  D!
 /526Fcggh/0J$$5'DGG$67F   !%$"%cggl&;&Ar"B((,SWW5G-H(I '*#''2B*C*Ir&J$'(?(E2$F
#. *.''#B' !OJu <~ +-GGMM*%V%%8%%5 Xj++002J4I4I4N4N4PQSU  }}o!E14. E**U#)rCwwx D(77:r28bLr28bI(,,Y7HS9 ,"4#5#A#A-#PQ .11%;MGGOR8Sac?R<SM ''-4:K%'K!!"d+ffY+1r |,EwE2#**Qse2eW+=>#**51 " 8CTYY{3N j)##)&!&    $ 12 77<, 
 %1"'8$)6&)6&%3"&'#"-,D)"$4::<(##)&"/"/!&,* 1%=& "" G$ ,//9M
 &,"11(;ArCK(*N155kB""))*<{*JK+ *+1r66}EKMIdmm ,:'3,: : ;J(+>$. * -n=/3 )+>':& ;)CM9:'= )0

u%ww;<B )+
88N39r9Bb'Cse|:0E"))#. : ((:..@ 79WW239r>>~N   ''):H(EF"WW239r>>~N     ''):L(IJ "(( +z6"L.BC !OJO Z ++dT!WWm   mHmdQ1mHHG267I2JI#*A7aay.@7HAGGMM*"9"9:==IV"--@"--@"--;"//33H=	 SU C .1$i	#c(+ 4A0(J:)6 Cu *B$$%8"=DDRH * &2ME6#,==#8L#E(A 6% 6 6)(()<bAHH!CK&02 &2  5.e.X.E(+>%*]d&+- 4A8 GGNNKK4'(DQ*3}+=*>a@WY E-
v F  ,3z?+,Z  ,+,v IAsT   0r)r)r. r./r3*#s>s#s)
	s0s03sss s c                   t        |      }|xs i j                  di       xs i j                  di       xs i }|xs i j                  di       xs i j                  di       xs i }t               }g }|j                         D ]  }t	        |t
              r|j                  d      dk7  r(|j                  d      xs i }	|	j                  d      xs g D ]s  }
|
j                  d      }|r|j                  |      s(||v r-|j                  |i       j                  d      dk7  rR|j                  |       |j                  |       u  |S )u  ``_execute`` 와 동일한 필터로 렌더 대상 bg_id 리스트 산출 (helper).

        Codex I2 fix: verify_completion 의 expected 가 _execute 와 비대칭이면
        prompt 실패 / duplicate / unsafe bg_id 를 expected에 포함해 false partial
        이 발생한다. 이 helper로 양 sites 산출 로직을 통일한다.

        필터: `_select_bg_id_filter(plans_cp)` (D6 marker → BG_ID_RE / legacy →
        `_LEGACY_SAFE_BG_RE`) + first-wins(중복 bg_id) + prompt status=='ok'.
        r   r4  r5  r}   r7  r@  r9   )	r   r   r_   r  r  r  r  r`   r4   )r   r   r  r  r  ru  seenexpectedr  r@  r  rQ   s               r   _compute_expected_bg_idsz-BackgroundRenderStep._compute_expected_bg_ids  s?    ,H5n"))&"5;@@"MSQS	"(b--fb9?RDD]TVW][] %%'EeT*eii.AT.I99V$*Dhh}-33ffWo,"4"4S"9$;??3+//9TA$ 4	 ( r   c                d   | j                  d      }t        |      }|xs i j                  di       xs i j                  di       xs i }g }|j                         D ]P  \  }}t	        |t
              s|r|j                  |      s+|j                  d      dk7  r@|j                  |       R |S )u  upstream cp 부재 시 자기 cp(background_render.data.groups)에서 expected 복구.

        Codex I1 fix: master_plan cp 가 손상/누락된 채 step_run.status='completed'면
        자기 cp의 그룹 정보가 마지막 ground truth. 자기 cp도 없으면 noop이라
        호출자가 빈 리스트를 보고 clean 반환하면 된다.

        D6: 자기 cp 의 bg_id 들도 marker-gated 검증. own_cp 가 D6 marker
        (bg_catalog_hash) 가지면 BG_ID_RE strict.
        ry  r   rt   r}   r7  )r   r   r   rJ   r  r  r  r4   )r   own_cpr  rt   r  rQ   gress          r   _expected_bg_ids_from_self_cpz2BackgroundRenderStep._expected_bg_ids_from_self_cp  s     ++,?@ ,F3<R$$VR06B;;HbIOR ICdD)l005xx!T)OOC  ( r   c                	   ddl m} ddlm} ddlm} ddlm} |j                  dvr| j                  d      S | j                  d	      }| j                  d
      }d}|r|r| j                  ||      }n;t        j                  dt        |      t        |             | j                         }d}t!        |      }	|	dk(  r| j                  |dz         S t#        |      }
| j$                  j'                  |      j)                  |j*                  | j*                  k(  |j,                  | j,                  k(  |j.                  dk(        j1                         }t#               }t#               }t#               }|D ]  }|j2                  xs d} ||j4                        }t        |xr |j7                               }||
v r|sI|j9                  |       [|s^|j9                  |       |sr|j9                  |        ||
z  }t!        |      }t;        |
|z
        }t=        |j>                        | j*                  z  dz  | j,                  z  dz  dz  }g }|j7                         r@t;        |jA                  d      D ch c]  }|jB                  |
vr|jB                   c}      }||	k(  rd}n
|dk(  rd}nd}g }|r(|jE                  t!        |       d|	 d| d|dd         |dk7  rt        j                  d||	|||dd        t;        |      }|}t!        |      dkD  xs t!        |      dkD  }| j                  d       }|xs i jG                  d!i       xs i jG                  d"i       xs i }g }g } i }!|
D ]  }"|jG                  |"      xs i }#t        |#jG                  d#            xs |#jG                  d$      d%k(  }$|$r=| jE                  |"       |#jG                  d&      xs |#jG                  d'      xs d|!|"<   |jE                  |"        g }%d}&| D ]8  }"|!jG                  |"      xs d}'|"|v r|'r
|'|v r|&d(z  }&(|%jE                  |"       : t;        |%      }( ||dk(  xr |% |||	||t!        |      t!        |       |&|(dd t;        |       dd t;        | D )ch c]  })|!jG                  |)      r|!|)    c})      dd t!        |      |dd t!        |      t!        |      |dd |d)*      S c c}w c c})w )+u9  chain_bg 산출물 무결성 검증 (Phase 7 background_render).

        expected 산출 우선순위:
          1. master_plan + background_prompt cp 가 모두 있으면 ``_execute`` 와 동일
             필터(`_select_bg_id_filter(plans_cp)` + first-wins + prompt ok)로 expected 빌드.
          2. 둘 중 하나라도 부재하면 자기 cp(`background_render.data.groups`)의
             ``status=='ok'`` bg_id 로 fallback (Codex I1).
          3. 자기 cp 마저 없으면 noop 으로 인정해 clean 반환.

        actual = ``ImageAsset(asset_type='chain_bg', variant_type IN expected)``
        + 파일 stat(cwd 독립 ``resolve_image_path``).

        background_mode off면 step 자체가 noop → 항상 clean.

        cleanup_artifacts override 안 함 → default noop (사용자 caveat).
        r   r   r  CompletionReportr  >   r&  r'  off)r#  r0  r1  phase7_master_planu^   [VERIFY] background_render: upstream cp 부재 (master_plan=%s prompt=%s) → self_cp fallbackself_cp_fallback_emptyr2  r"   r   rG  rH  z*.pngcleanmissingpartialz# chain_bg images missing (expected=z, found=z): N   zO[VERIFY] background_render: path=%s expected=%d found=%d severity=%s missing=%s
   2   ry  r   rt   r  rz  r  r  r  r   )chain_bg_expectedchain_bg_foundr#  expected_new_render_countexpected_reuse_countvalid_reuse_countmissing_reuse_targetsreuse_alias_bg_idsreuse_target_bg_idschain_bg_extra_asset_rowschain_bg_extra_asset_bg_ids$chain_bg_extra_asset_rows_with_fileschain_bg_extra_file_countchain_bg_extra_file_bg_idschain_bg_extra_overflowis_completer  severitymetadata)$r   r   r  r	  app.core.integrity_reportr  r  r  r   _verify_clean_reportr   r  r  r  r   r  rK   r_   r  r  r  r   r   r  r  r  r%  r3   r`   rL   r   r   globr5   r4   r   )*r   r   r	  r  r  r   r  
path_labelexpected_bg_idsr  expected_setrowsbgs_with_fileextra_asset_bg_idsextra_asset_bg_ids_with_filesrr9   r8   has_file	found_setfoundmissing_bgsrs  extra_file_bg_idsr  missing_msgsextra_asset_bg_ids_sortedextra_file_bg_ids_sortedr  r  
own_groupsexpected_new_renderexpected_reusereuse_target_by_bgrQ   ru   r  r  valid_reusetgtmissing_reuse_targets_sortedr  s*                                             r   verify_completionz&BackgroundRenderStep.verify_completion  s   " 	-:>1 ##+HH,,%,88--.FG//0CD
)

";;HjQO NN'XZ 0
 #@@BO+J'q=,,*x2G,HH?+GGMM*%V%%8%%8%%3
 SU 	 #&%'*u25%%ANN(bE"1;;/AA,!((*-H$!%%e,"&&u-155e<  "L0	I\I56 &&'oo oo 	
 !! 	 (* & )w 7( 7166-  7( !
 HHaZ H H"${#$ %%JhugSSb9I8JL
 wNN)HeX{3B7G %++=$>!#4 )*R/ 2+,r1 	  ++,?@l+1r66xDJ 	 *,$&-/Cs#)rAQUU:&' D55)-CC  %%c*EE-. uu12 #3' $**3/   ,.!C$((-3CiCC9,<q %,,S1 " (..C'D$!W,J5J1J %-"'"-01D-E(+N(;%0)Ecr)J&,^&<Sb&A'- "0!/A-11!4 +1-!/( 2( .11C-D/H"/M8;19 .11B-C.Fs.K+B7	!
 !	
M(js   9!S-S2"c          	     .    ddl m}  |dg ddd|d      S )uM   expected=0 / mode=off 등 정당한 noop 케이스의 clean 리포트 helper.r   r  Tr  )r  r  r#  r  )r  r  )r   r#  r  s      r   r  z)BackgroundRenderStep._verify_clean_report  s%    >+,4P	
 	
r   )r  rG   )r  rG   r  r  )r  Dict[str, str]r  r  )r  r  )r!  )r  rG   r  r  )rQ   rG   rV   r  rn  r  rq  Dict[str, Dict[str, str]]r/  rG   r}   rG   r  r  r  r  )r   r  r  r  )r  Dict[str, Dict[str, Any]])&rM   r  ru  r  r  r  rq  r  r{  r  rO   r_   rN   	List[str]rs  r   rt  r   rr  r	   r|  z#Optional[Dict[str, Dict[str, str]]]r}  #Optional[Dict[str, Dict[str, Any]]]r~  r  r  r  r  r  r  z)Optional[Dict[str, List[Dict[str, Any]]]]r  zOptional[Dict[str, List[Any]]]r  rG   r  zLTuple[Dict[str, Dict[str, Any]], Dict[str, Path], int, List[Dict[str, Any]]]r  )rt   r  rN   r  rz  r  r  r  )r   r  r  r  r  r  )r  r  )r#  rG   )__name__
__module____qualname__r   r   r  r$  r  r  r  r  r  r  r  r  r  r  r  r
  r   r   r   r   2  s*   GR*:*:	:x
"T	
P 26& & 	&
 %& 5& & & 0& 
&T^0^	"^@$P*v CGGKBF48;?DH:>)F@ ,F@ /	F@
 %F@ 5F@ 0F@ F@ F@ F@ !F@ F@ @F@ "EF@ @F@  2!F@" !9#F@$ B%F@& 8'F@( )F@*
+F@X: AE	n)n n >	n
 
n`"*" -" 
	"H:|
|	
r   r   )r   r  )r    r  r  r  )r.   rG   r6   Optional[Path]r7   z
List[Path]r1   rG   r#   rG   r$   r  r%   rG   r&   r  r'   rG   r(   r  r)   rG   r*   r  r  r  )
rM   r  rJ   r  rN   r  rO   r_   r  r  )
r/   r  rb   zOptional[str]rc   zDict[str, Optional[str]]rd   r   r  z Tuple[List[str], Dict[str, Any]])rr   r  r  r_   )rO   r_   rM   r  r   r_   r  z%Tuple[set, Dict[str, Dict[str, Any]]])-__doc__
__future__r   r   loggingr  r  rA  concurrent.futuresr   r   r   r   pathlibr   typingr	   r
   r   r   r   app.core.bg_state_vocabr   app.core.image_call_budgetr   app.core.step_runnerr   #app.services.image_capture.annotater   	getLoggerr  r  r   r   compiler   r   r!   r:   rW   rm   rx   r   r   r   r
  r   r   <module>r     s  . #   	   ? '  3 3 , : + H			8	$
  "
  RZZ 78 $ '+!#+/!#+/"&CC C 	C
 C C %C C )C C )C C  C CL.'.$. . 	.
 .b))) +)
 ) &)X)(..'. . +	., l:
: l:
r   