
    h;jB<              	       F   d Z ddl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 G d d	ee      Zd
eeef   deeeef      defdZd
eeef   deeeef   ee   f   fdZd
eeef   deeeef      deeeef   ee   f   ddfdZy)uF   T2I 검수 StepRunner — entity_t2i + scene_detail 검증 후 치환.    N)AnyDictListOptionalTupleAppError)
StepRunner)refresh_t2i_prompt_hash)_DetailStepMixinc                   D    e Zd ZdZdefdZd	deeef   fdZdedefdZ	y)
T2iReviewStepuM   entity_t2i와 scene_detail의 T2I 프롬프트를 검수하고 치환 적용.returnc                 0   ddl }ddl}ddlm} ddlm}  || j                        }t        |dd      }t        t        |dd            }|d	k7  s|s|S |j                  |j                  |d
dd      j                  d            j                         dd S )u  검수 **범위**를 지문에 접는다 (2026-08-27, Codex BLOCK-3).

        v1 에서 씬 갈래를 건너뛰면 산출 모양이 달라진다(`scene_fixes` 가
        0 이고 `scene_review_status` 가 붙는다). 그것을 안 접으면 **옛
        CP 가 새 계약인 것처럼** current 로 읽혀 조용히 skip 되고, 나중에
        「검사했는데 깨끗하다」로 오독된다.

        ★OFF/legacy 에서는 종전과 같은 값이 나오게 둔다 — 그 경로는
         범위가 안 바뀌었다.
        r   Nsettings)compute_config_hashstill_recipe_modeofft2i_review_skip_scene_on_v1Tv1entity_only_v1)basereview_scope)	sort_keyszutf-8   )hashlibjsonapp.core.configr   app.core.step_runnerr   project_configgetattrboolsha256dumpsencode	hexdigest)selfr   _jsonr   r   r   modeskips           T/Users/manta/Documents/Projects/TheRoad-I1/backend/app/core/steps/t2i_review_step.py_config_hashzT2iReviewStep._config_hash   s     	,<"4#6#67x!4e<GH&CTJK4<tK~~KK7GH"&  ((.w
 )+cr 	    c                    | j                  d      }| j                  d      }| j                  d      }| j                  d      }| j                  d      }| j                  d      }| j                  d      }|r|sdd	lm}	  |	d
dd      |j                  di       }
|j                  di       }|r|j                  di       ni }|r|j                  di       ni }|r|j                  di       ni }|r|j                  di       ni }|r|j                  di       ni }ddlm} t        |      } ||
||||||| j                  dg            }|d   dkD  r+| j                  d|
       t        j                  d|d          |d   dkD  rK|d   }	 t        ||      }t        |||       | j                  d|       t        j                  d|d   |       |d   dkD  s|d   dkD  rt        j!                  d|d   |d          |d   |d   |d   |d   |d   |d   d|d   d |d!   |d   | j#                         d"S # 	t        t        f$ r }t        ||	      r  |	dd|       |d }~ww xY w)#N
entity_t2iscene_detailentity_mergeentity_detailshot_validatorshot_stagingvisual_world_rulesr   r   zstep.no_inputu,   entity_t2i 또는 scene_detail 결과 없음i  )codemessagestatus_codedata)run_t2i_review
t2i_review)
extra_tags)entity_t2i_datascene_detail_dataentity_merge_dataentity_detail_datashot_extract_datashot_staging_datavwr_dataopik_metadataentity_appliedz4t2i_review: entity_t2i checkpoint updated (%d fixes)scene_appliedscene_applied_indicesz"t2i_review.sentinel_refresh_failedu   sentinel refresh 실패: r7   r8   zNt2i_review: scene_detail checkpoint updated (%d fixes, %d sentinels refreshed)u   t2i_review: %d fixes applied to entity_t2i + %d to scene_detail. downstream(shot_dependency_t2i / scene_image_pipeline)이 이미 완료 상태면 수정 결과 반영을 위해 force 재실행이 필요합니다 (cascade=1-pass policy).entity_fixesscene_fixes)entityscenescene_review_status)entity_detectedscene_detectedrF   rG   regeneration_requiredrN   diagnostics)review_summaryrR   rH   config_hash)_load_prev_checkpointapp.core.errorsr	   getapp.modules.pipeline.t2i_reviewr;   _capture_card_hash_statebuild_opik_metadata_save_checkpoint_dataloggerinfo_refresh_scene_detail_sentinels_assert_card_hash_unchangedKeyError
IndexError
isinstancewarningr-   )r(   r*   entity_t2i_cpscene_detail_cpentity_merge_cpentity_detail_cpshot_extract_cpshot_staging_cpvwr_cpr	   r>   r?   r@   rA   rB   rC   rD   r;   pre_card_statereview_resultapplied_indices	refreshedexcs                          r,   _executezT2iReviewStep._execute+   s   22<@44^D44^D55oF445EF 44^D++,@AO0$F  (++FB7+//;?NO//;TVAQ-11&"=WY?NO//;TV?NO//;TV-36::fb)B 22CD&+//1//22|n2M	
$ )*Q.&&|_EKKNP]^nPop)A-+,CDO;%	 ,% &&~7HIKK`o. )*Q.-2PST2TNNm ./1O	 $1#@"/">"/0@"A"/"@+N;*=9* (55J'K )7%23J%K  ,,.1
 	
; h
3  c8,=7u= s   H> >I.I))I.step_idr:   c           
      v   ddl }ddlm}m} ddlm} ddlm}m} ddlm	}	  ||	j                        | j                  z  dz  dz  | j                  z  |z  }
|
d	z  }|j                         st        d
d| d|       d|j                  |j                         j#                  d       d}	 |j%                  t'        |      t'        |
|z                ||      }|t        d
d| d|       ||d<    |||       y# t(        $ r/}t        d
d| dt+        |      j,                   d|       |d}~ww xY w)u  다른 step의 체크포인트 데이터를 덮어쓰기 (아카이브 + 원자적 쓰기).

        B1 patch (Block A closure stabilization, Codex BLOCKING #1): manifest
        missing / unreadable 시 모두 fail-fast. 옛 동작 (logger.warning + return)
        은 mutator 가 성공처럼 끝나지만 cp 미저장 — silent fallback 정책 위반
        (feedback_no_silent_fallback.md). caller (StepRunner) 가 step 실패로
        surface — silent corruption 차단.
        r   N)datetimetimezone)Path)atomic_write_jsonread_json_safer   checkpointsepisodeszmanifest.jsonz!t2i_review.checkpoint_save_failedzt2i_review: target uY    checkpoint manifest missing — silent skip 금지 (mutator 성공 오판 차단). path=rI   	manifest_z%Y%m%d_%H%M%Sz_pre_review.jsonu-    archive copy failed — silent skip 금지. z: u=    manifest unreadable — silent skip 금지. archive 보존: r:   )shutilrs   rt   pathlibru   app.core.checkpoint_iorv   rw   r   r   projects_dir
project_id
episode_idexistsr	   nowutcstrftimecopy2strOSErrortype__name__)r(   rq   r:   r{   rs   rt   ru   rv   rw   r   cp_dirmanifestarchive_namero   cps                  r,   r[   z#T2iReviewStep._save_checkpoint_data   sl    	/ L,h++,t>NQ[[^b^m^mmpwwO+ 8)' 3OOWjZ  #8<<#=#F#F#W"XXhi		LLXF\,A(BC H%:8)' 3;;G.J  6
(B'+  	8)' 3++/9+=+=*>bG 	s   -'D   	D8	*D33D8N)resume)
r   
__module____qualname____doc__r   r-   r   r   rp   r[    r.   r,   r   r      s;    Wc 6{
c3h {
z7(S 7( 7(r.   r   r?   rm   r   c           	          d}| d   }|D ]V  \  }}||   }|d   |   }|j                  d      }|st        dd| d| d	      t        ||d
   d| d|       sR|dz  }X |S )u+  t2i_review 가 수정한 (scene_list_idx, variation_idx) 항목의
    owned_validation sentinel 의 t2i_prompt_hash 만 갱신.

    AC-A1, A2 (spec §3.4): applied_indices 외 항목은 건드리지 않음.
    sentinel 누락 / shape 위반 시 raise → caller 가 t2i_review failed 처리.
    r   scenest2i_variationsowned_validationz#t2i_review.owned_validation_missingzscenes[].t2i_variations[u+   ].owned_validation 없음 — schema 위반rI   
t2i_promptzt2i_review_refresh@s_v)where   )rW   r	   r   )	r?   rm   rn   r   
s_list_idxv_idxrM   	variationsentinels	            r,   r^   r^      s     Ix(F,
Ez"*+E2	==!34:j\):5' B@ @  #l#(Bug>

 NI# -$ r.   c                     i }t        | j                  dg             D ]>  \  }}t        |j                  dg             D ]  \  }}|j                  d      |||f<    @ |S )u  mutation 직전 모든 (scene_idx, var_idx) 의 render_prompt_card_hash
    전체 capture.

    V2 patch P2 (Codex BLOCKING #2 + spec §3.5 V5 patch S1):
      run_t2i_review() 호출 **전** capture 의무 — 호출 후엔 이미 mutation
      끝남. applied_indices 는 mutation 후에야 알 수 있으므로 **전체**
      scenes/variations 매핑. under-coverage 위험 0 — applied_indices 는
      항상 전체의 부분집합.
    r   r   render_prompt_card_hash)	enumeraterW   )r?   states_idxrM   r   vs         r,   rY   rY   
  sj     35E!"3"7"7""EFu!%)),<b"ABHE1$%EE*C$DE5%.! C G Lr.   	pre_statec           	          |D ]N  \  }}| d   |   d   |   }|j                  d      }|j                  ||f      |k7  s<t        dd| d| d       y	)
u  t2i_review 는 card payload 변경 금지 — pre/post hash 일치 검증
    (AC-A3).

    V2 patch P2: pre_state 는 caller 가 _capture_card_hash_state(
    scene_detail_data) 로 mutation 전 만든 dict — 전체 매핑. 본 helper 는
    applied_indices 만 비교.
    r   r   r   z&t2i_review.card_hash_unexpected_changeuF   t2i_review 가 card hash 를 변경함 — scope 외 mutation: scenes[r   ]rI   N)rW   r	   )r?   rm   r   r   r   r   	post_hashs          r,   r_   r_     sy     (uh'./?@GEE34	==%(I5=((-w.?waI 	 (r.   )r   loggingtypingr   r   r   r   r   rV   r	   r    r
   app.core.steps._owned_helpersr   app.core.steps.detail_stepsr   	getLoggerr   r\   r   r   intr^   rY   r_   r   r.   r,   <module>r      s    L  3 3 $ + A 8			8	$R($j R(xCH~%S/* 	BCH~	%S/8C=
()&CH~%S/* E#s(OXc]23 
	r.   