
    u+i4                    P   d Z ddlmZ ddlZddlZddlmZ ddlmZ  ee	      j                         j                  d   dz  Z ee      ej                  vr"ej                  j                  d ee             ddZdd	Z	 	 	 	 	 	 	 	 	 	 dd
ZddZddZddZddZddZddZy)uY  Shared preflight helpers for G4.4 canary scripts (Wave 3 carry).

All 4 metric scripts (`g4_4_double_description.py`,
`g4_4_zoom_in_detail_no_new_entity.py`, `g4_4_atmosphere_no_layout_import.py`,
`g4_4_view_mixing.py`) import the helpers from this module and apply them
identically. The token-count script (`g4_4_token_count.py`) does NOT use
these helpers — it reads prompt files, not CP, and per R3-M2 must remain
CP-free (no `compute_continuity_snapshot_hash` import).

Trap #1 silent-absorb ban (Wave 3 carry — G4.3 R3R4-B2 carry):
- `or [] / or {}` 패턴 금지.
- `data.scenes` / `t2i_variations` / `t2i_prompt` /
  `render_prompt_card` / `continuity_elements_used` 누락은
  measurement_failures 로 적재 후 caller 가 exit 1.
- `compute_continuity_snapshot_hash()` 호출 실패도 measurement_failures 로
  적재 (silent skip 금지).
    )annotationsN)Path)Any   backendc                 :    ddl m} m}m}m}m}m}m} | ||||||dS )u  Return the G4.4 + G4.3-cross module symbols Wave 1-A exposes.

    Centralised to give every canary script a single import boundary; if
    Wave 1-A renames a constant, only this module needs adjustment.

    Trap #8 carry — module-level constants direct import; NO inline list
    duplication of the 7-entry generic person nouns / 7-entry furniture
    layout tokens / 4-entry body-part triggers / etc.
    r   !_CONTINUITY_FRAMING_SCOPE_OPTIONS#_CONTINUITY_FURNITURE_LAYOUT_TOKENS _CONTINUITY_GENERIC_PERSON_NOUNS'_CONTINUITY_ID_POLICY_CROSS_REF_LITERAL_CONTINUITY_REF_USAGE_VALUES_ID_BODY_PART_TRIGGERS compute_continuity_snapshot_hash)!app.core.steps.render_prompt_cardr
   r   r   r   r   r   r   r	   s          I/Users/manta/Documents/Projects/TheRoad-I1/scripts/canary/_g4_4_common.pyrender_prompt_card_importsr   "   s3       .O/R,L3Z(D"8,L     c                    d| vr|j                  d       y| d   }t        |t              s|j                  d       yd|vr|j                  d       y|d   }t        |t              s|j                  d       y|S )u   Validate CP envelope shape and return scenes list (or None on failure).

    Caller must check None and fail-fast (sys.exit(1)) — measurement_failures
    is appended in-place. Trap #1 — silent-absorb ban.
    datazcp.data key missingNzcp.data not dictsceneszcp.data.scenes key missingzcp.data.scenes not list)append
isinstancedictlist)cpmeasurement_failuresr   r   s       r   _load_scenes_or_failr   A   s     R##$9:f:DdD!##$67t##$@A(^Ffd###$=>Mr   c           	     |   d| vr|j                  d| d| d       y| d   }t        |t              s|j                  d| d| d       yd|vr|j                  d| d| d       y|d   }t        |t              s|j                  d| d| d	       y	 d
dlm}  ||       d| vr|j                  d| d| d       y| d   }t        |t              s|j                  d| d| d       y|s|j                  d| d| d       y|S # t
        $ r$}|j                  d| d| d|        Y d}~yd}~ww xY w)u  Validate per-scene shape — render_prompt_card / continuity_elements_used /
    variations.

    Returns variations list when valid; None otherwise (caller continues
    loop). Per spec §5.3 + Trap #1 silent-absorb ban + Trap #3 CP shape:

      - render_prompt_card must be dict.
      - render_prompt_card.continuity_elements_used must be dict.
      - compute_continuity_snapshot_hash(rpc) must succeed (no silent skip).
      - t2i_variations must be present, list, AND non-empty (R3-B1 carry —
        empty must fail).
    render_prompt_cards_shz : render_prompt_card key missingNz: render_prompt_card not dictcontinuity_elements_usedz9: render_prompt_card.continuity_elements_used key missingz6: render_prompt_card.continuity_elements_used not dictr   )r   z: continuity hash failed: t2i_variationsz: t2i_variations key missingz: t2i_variations not listz: t2i_variations empty)r   r   r   r   r   	Exceptionr   )	scenesishir   rpccer   exc
variationss	            r   _validate_scene_preflightr-   X   s   $ 5(##t3se;<	
 
$
%Cc4 ##t3se89	
 !,##t3se  	
 	'	(Bb$##t3se  	
 	
 	)- u$##t3se78	
 '(Jj$'##t3se45	
 ##t3se12	
 -  ##t3se5cU;	
 	s   D 	D;D66D;c                   t        | dd      rt        | j                        }|j                         s3t	        d| t
        j                         t        j                  d       	 |j                  dd      5 }t        j                  |      }ddd       j                  d
      |j                  d      |j                  d      |j                  d      |j                  d      |j                  d      |j                  d      dS 	 t        | dd      rt        j                  | j                        nd}t        | dd      rt        j                  | j                        nd}t        | d
d      t        | dd      t        | dd      t        | dd      t        | dd      dS # 1 sw Y   xY w# t        $ r>}t	        d	| t
        j                         t        j                  d       Y d}~`d}~ww xY w# t        $ r=}t	        d| t
        j                         t        j                  d       Y d}~d}~ww xY w)ux  Construct pinning dict from --config JSON OR individual CLI flags.

    Returns dict with 7 keys (G4.4 pinning block — Override O-12):
      pid / scene_index_list / shot_index_list_per_scene / model_routing /
      prompt_source_mode / card_commit_hash / continuity_card_snapshot_hash

    Trap #1 — NO silent defaults; caller must run validate_pinning() afterwards.
    configNz.[g4_4_common] ERROR: --config file not found: file   rutf-8encodingz+[g4_4_common] ERROR: --config parse error: pidscene_index_listshot_index_list_per_scenemodel_routingprompt_source_modecard_commit_hashcontinuity_card_snapshot_hashr7   r8   r9   r:   r;   r<   r=   z:[g4_4_common] ERROR: failed to parse list/dict JSON args: )getattrr   r/   existsprintsysstderrexitopenjsonloadr%   getloadsr8   r9   )argscfg_pathfpcfgr+   r8   r9   s          r   load_pinning_from_argsrN      s    tXt$$ @
KZZ HHQK	sW5iim 6 775> #(: ;),1L)M WW_5"%''*>"? #(: ;-0WW/.

 
	
 t/6 JJt,,- 	 t8$? JJt556 	" tUD),%> =%d,@$G#D*<dC)014*

 
I 65 	=cUCZZ HHQKK	8  HN	
 	sI   'F6 :F)F6 AH  )F3.F6 6	G=?3G88G= 	I	3IIc                   d}|D cg c]  }| j                  |      dv s| }}|r4t        d| dt        j                         t        j                  d       t        | d   t              s0t        dt        j                         t        j                  d       t        | d	   t              s1t        d
t        j                         t        j                  d       yyc c}w )uD   Fail-fast on missing pinning fields. Trap #1 — NO silent defaults.r>   )N z8[g4_4_common] ERROR: pinning missing required field(s): zF. Provide via --config <json> or individual flags. NO silent defaults.r0   r2   r8   z?[g4_4_common] ERROR: pinning.scene_index_list must be list[int]r9   zC[g4_4_common] ERROR: pinning.shot_index_list_per_scene must be dictN)rH   rA   rB   rC   rD   r   r   r   )pinningrequiredkmissings       r   validate_pinningrU      s    H #C(Qgkk!n
&Bq(GCFi "# 		
 	g0148M	
 	g9:DA	

 	 B Ds
   C$C$c           	     ~   t               }| d   }| d   D ]$  }t        |      }|j                  t        |            }||j                  |      }|4t	        d| dt
        j                         t        j                  d       t        |t              sJt	        d| dt        |      j                   d	t
        j                         t        j                  d       |s4t	        d| d
t
        j                         t        j                  d       |D ]  }|j                  |t        |      f         ' |S )u  Cartesian (scene_index, shot_index) tuples from pinning block.

    Trap #4 — pinning enumerates EXACT (si, shi) tuples. A scene_index without
    a corresponding shot_index_list entry (or with non-list / empty list) is a
    contract violation, not a silent default.
    r9   r8   z=[g4_4_common] ERROR: pinning.scene_index_list contains scene z? but shot_index_list_per_scene has no entry. NO silent default.r0   r2   z7[g4_4_common] ERROR: pinning.shot_index_list_per_scene[z] must be list[int], got .u4   ] is empty — pinned scene must enumerate >=1 shot.)setintrH   strrA   rB   rC   rD   r   r   type__name__add)rQ   outshot_mapr'   si_int	raw_shotsr(   s          r   build_pinning_scene_setrb     s4    !$C23H()RLLV-	 V,I !%& ZZ	 HHQK)T*84	?++,A/ ZZ	 HHQK8  ZZ	 HHQKCGGVSX&' ; *> Jr   c                   | dz  }|j                         s3t        d| t        j                         t        j                  d       	 |j                  dd      5 }t        j                  |      cddd       S # 1 sw Y   yxY w# t        $ r=}t        d	| t        j                         t        j                  d       Y d}~yd}~ww xY w)
zELoad `manifest.json` under cp_root. fail-fast on missing/parse error.zmanifest.jsonz0[g4_4_common] ERROR: manifest.json not found at r0   r2   r3   r4   r5   Nz0[g4_4_common] ERROR: manifest.json parse error: )	r@   rA   rB   rC   rD   rE   rF   rG   r%   )cp_rootmanifest_pathrL   r+   s       r   load_cp_manifestrf   3  s    o-M!>o	

 	g6"99R= 766 >seD	
 	s6   
B A<2	B <BB B 	C3C		Cc                   d}t        | dd      rUt        | j                        j                  dd      5 }t	        j
                  |      }ddd       j                  d      }|st        | dd      }|s0t        dt        j                         t        j                  d	       t        |      }|j                         s3t        d
| t        j                         t        j                  d	       |S # 1 sw Y   xY w)up   Resolve cp_root from --config or --cp-root flag. Fail-fast on missing.

    Trap #1 — NO silent defaults.
    Nr/   r3   r4   r5   rd   z;[g4_4_common] ERROR: --cp-root (or config.cp_root) requiredr0   r2   z*[g4_4_common] ERROR: --cp-root not found: )r?   r   r/   rE   rF   rG   rH   rA   rB   rC   rD   r@   )rJ   cp_root_strrL   rM   rd   s        r   resolve_cp_rootri   H  s    
 #KtXt$$++##C'#:b))B-C ;ggi(dIt4I	
 	;G>>8	B	
 	N% ;:s   C66C?c                   |j                   dk(  rHt        j                  | t        j                  ddd       t        j                  j                  d       yt        |j                         }|j                  j                  dd       |j                  dd	
      5 }t        j                  | |ddd       ddd       y# 1 sw Y   yxY w)z2Write JSON output to args.output ('-' for stdout).-Fr   T)ensure_asciiindent	sort_keys
)parentsexist_okwr4   r5   N)
outputrF   dumprB   stdoutwriter   parentmkdirrE   )r^   rJ   out_pathrL   s       r   emit_outputrz   d  s    {{c		#szza4P

$dT:]]3]1RIIc2E!tL 211s   CC
)returnr   )r   r   r   r   r{   list | None)
r&   r   r'   
int | Noner(   r}   r   r   r{   r|   )rJ   r   r{   r   )rQ   r   r{   None)rQ   r   r{   zset[tuple[int, int]])rd   r   r{   r   )rJ   r   r{   r   )r^   r   rJ   r   r{   r~   )__doc__
__future__r   rF   rB   pathlibr   typingr   __file__resolverp   _BACKEND_PATHrZ   pathinsertr   r   r-   rN   rU   rb   rf   ri   rz    r   r   <module>r      s   " #  
   X&&(003i?}SXX%HHOOAs=)*>.GGG 
G 	G
 GT@F F(V*8	Mr   