+
    F,i/                    X  a  0 t $ R t^ RIHt ^ RIt^ RIt^ RIt^ RIHt ^ RIH	t	 ]P                  P                  ^ ]! ]	! ]4      P                  4       P                  4      4       ^ RIHtHtHtHtHtHtHtHtHt ]! 4       t]R,          t]R,          tRtR]R	&   R
P?                  R ] 4       4      t ]PB                  ! R] ,           R,           ]PD                  4      t#]PB                  ! R4      t$^2t%R R lt&R R lt'R R lt(R R lt)]*R8X  d   ]PV                  ! ](! 4       4       R# R# )uY  G4.4 canary — STRICT view-mixing detection (Task 4.4).

Detects same-character-ID full-body / partial-body verbs (`stands` /
`seated` / `leaning` / `walking` / `running` / `kneeling` / `lying` —
G4.4 ground-truth) **+** body-part close-up co-occurrence (`focus on` /
`close on` / `tight on` / `detail on` + `<id>'s <body-part>` —
`_ID_BODY_PART_TRIGGERS` cross-import from G4.3) within a single
t2i_prompt = view-mixing 시점 혼합 violation.

Override O-7 — paired-string substring carry: same composite-ID body-part
focus rule cross-references `_CONTINUITY_ID_POLICY_CROSS_REF_LITERAL`
(`id_policy.body_part_focus_rule`). Cross-card paired drift is enforced
by unit + integration tests; this canary inherits the same import boundary.

Override O-17 — regex brittleness: this regex/substring detector is a
1차 detector only. False-positive examples: "C01O02 stands in profile, hand
resting on the table" (full-body + body-part are natural partial
description, not close-up). If baseline >0, escalate to LLM-validator
(gpt-5.4-mini judge) as P1 follow-up.
`feedback_no_regex_postprocessing.md` carry.

Scope: ALL pinned (si, shi) shots — view-mixing pattern detection itself
is intent-agnostic (R2-B4 carry).

Exit criteria (analyzer, OUT-OF-BAND):
  candidate.metrics.view_mixing_count == 0  (STRICT, Override O-1)

Usage (config mode):
    python scripts/canary/g4_4_view_mixing.py \
        --config canary_config.json \
        --cp-root data/projects/<pid>/checkpoints/scene_detail \
        --prompt-version 19.<timestamp> \
        --role candidate \
        --output results/view_mixing_candidate.json
)annotationsN)datetime)Path)	_load_scenes_or_fail_validate_scene_preflightbuild_pinning_scene_setemit_outputload_cp_manifestload_pinning_from_argsrender_prompt_card_importsresolve_cp_rootvalidate_pinning_ID_BODY_PART_TRIGGERS'_CONTINUITY_ID_POLICY_CROSS_REF_LITERALztuple[str, ...]_VIEW_MIXING_FULL_BODY_VERBS|c              #  N   "   T F  p\         P                  ! V4      x  K  	  R # 5iN)reescape).0ts   & "scripts/canary/g4_4_view_mixing.py	<genexpr>r   M   s     E.D		!.Ds   #%z\b(?:z)\s+C\d{2}(?:O\d{2})?'s\s+\w+z\bC\d{2}(?:O\d{2})?\bc                   V ^8  d   QhRR/# )   returnstr )formats   "r   __annotate__r    V   s     / /S /    c                 V    \         P                  ! 4       P                  4       R ,           # )Z)r   utcnow	isoformatr   r!   r   iso8601_nowr&   V   s    ??&&(3..r!   c                    V ^8  d   QhRRRR/# )r   promptr   r   z
list[dict]r   )r   s   "r   r    r    Z   s     ; ;s ;z ;r!   c                f  a . pV P                  4       p/ p\        P                  V 4       FR  pVP                  4       pVP	                  V. 4      P                  VP                  4       VP                  4       34       KT  	  . p\        P                  V 4       Fq  p\        P                  VP                  4       4      pV'       g   K0  VP                  RVP                  4       RVP                  4       RVP                  4       /4       Ks  	  VP                  4        EF  w  rXV EF  w  r\        ^ V	\        ,
          4      p\        \        V 4      V
\        ,           4      pW+V o\        ;QJ d#    V3R l\          4       F  '       g   K   RM	  RM! V3R l\          4       4      pV'       g   K  V Fo  pVR,          V8w  d   K  VR,          V	\        ,
          8  d   VR,          V
\        ,           8:  d   KG  VP                  RVRW.RVR,          VR,          ./4       Kq  	  EK  	  EK  	  V# )	u  Return list of view-mixing violations.

Each violation = {id_token, full_body_position, body_part_position}.
Same composite-ID + full-body verb (within ±50 chars window) + body-part
trigger close-up of same id elsewhere (outside that window) →
view-mixing violation.

`feedback_no_regex_postprocessing.md` carry — char-level proximity
(NOT sentence regex). Override O-17 — 1차 detector only.
id_tokenstartendc              3  ,   <"   T F	  qS9   x  K  	  R # 5ir   r   )r   vwindows   & r   r   %detect_view_mixing.<locals>.<genexpr>   s       %AV%As   TFfull_body_positionbody_part_position)lower	_ID_REGEXfinditergroup
setdefaultappendr+   r,   _BODY_PART_FOCUS_PATTERNsearchitemsmax_WINDOW_CHARSminlenanyr   )r(   
violationsprompt_lowerid_positionsmatchr*   bp_focus_matchesid_match	positionsid_startid_end	win_startwin_endhas_full_bodybpr/   s   &              @r   detect_view_mixingrN   Z   s     J<<>L 68L##F+;;="-44[[]EIIK(	
 , $&)226:##EKKM28##HNN,uyy{%  ;  ,113 )HAx-78I#f+v'=>G!G4FC  %A CCC  %A  M !&j>X-wK8m#;;5	Vm%;; !!(8*<(2g;5	*B#  ' !*  40 r!   c                   V ^8  d   QhRR/# )r   r   intr   )r   s   "r   r    r       s     c cc cr!   c                 h	   \         P                  ! R R7      p V P                  R\        RR7       V P                  R\        RR7       V P                  R\        RR7       V P                  R\        RR	7       V P                  R
\        RRR.R7       V P                  R\        RR7       V P                  R\        RR7       V P                  R\        RR7       V P                  R\        R. R@OR7       V P                  R\        RR7       V P                  R\        RR7       V P                  R\        RR	7       V P	                  4       p\        V4      p\        V4       \        V4      p\        V4      p. p\        WE4      pVf   \        WV4      p\        Wq4       ^# \        V4      p\        4       p	^ p
^ p/ p. p. pV EF  p\        V\        4      '       g   VP!                  R4       K-  VP#                  R4      pVP#                  R4      pVe   Vf   KY  \%        V4      p\%        V4      pVV3V9  d   Kz  V	P'                  VV34       \)        VVVV4      pVf   K  VP!                  RVRV/4       V
^,          p
^ p\+        V4       F  w  pp\        V\        4      '       g   VP!                  RV RV RV R24       K9  VP#                  R4      p\        V\        4      '       d   VP-                  4       '       g   VP!                  RV RV RV R24       K  \/        V4      pV\1        V4      ,          pV F5  pVP!                  RVRVRVR VR ,          R!VR!,          R"VR",          /4       K7  	  K  	  VV,          pVVV R#V 2&   EK  	  V F)  w  ppVV3V	9  g   K  VP!                  R$V RV R%24       K+  	  R&\3        4       R'VP4                  R(VP6                  R)TR*TR+R,V
R-VR.VR/VR0\9        \:        4      R1\9        \<        4      /R2TR3^ R4V'       * ;'       d    V^ 8H  R5R6R7\>         R82//
p\        Wq4       \A        R9VP6                   R:VP4                   R;V
 R<V R=\1        V4       R>2\B        PD                  R?7       V'       d   ^# VP6                  R8X  d
   V^ 8  d   ^# ^ # )Au{   G4.4 canary: view-mixing detection (all shots, cross-import G4.3 _ID_BODY_PART_TRIGGERS — Override O-17 regex 1차 only).)descriptionz--configN)typedefaultz--pidz	--cp-rootz--prompt-versionT)rS   requiredz--role	candidatebaseline)rS   rT   choicesz--scene-index-listz--shot-index-list-per-scenez--model-routingz--prompt-source-modez--card-commit-hashz--continuity-card-snapshot-hashz--outputzscene entry is not dictscene_index_shot_index
shot_indexs_sh_vz: variation not a dict
t2i_promptz': t2i_prompt missing, empty, or not strvariation_indexr*   r1   r2   _z
pinning (sz ): not present in CP data.scenes	timestampprompt_versionrolepinning	scene_setmetricstotal_shotsview_mixing_countview_mixing_per_shotviolations_detailtrigger_phrases_usedfull_body_verbs_usedmeasurement_failuresexit_criteria_thresholdexit_criteria_passmeasurement_scriptsview_mixingu   scripts/canary/g4_4_view_mixing.py (all shots — cross-import G4.3 _ID_BODY_PART_TRIGGERS, Override O-17 regex 1차 only — paired ref literal: )z[g4_4_view_mixing] role=z prompt_version=z
  total_shots=z  view_mixing_count=z
  measurement_failures: zA
Exit criteria (STRICT): candidate.metrics.view_mixing_count == 0)file)Nrt   db)#argparseArgumentParseradd_argumentr   
parse_argsr
   r   r   r	   r   _empty_outputr   r   set
isinstancedictr8   getrP   addr   	enumeratestriprN   r?   r&   rc   rd   listr   r   r   printsysstderr)parserargsre   cp_rootcprn   scenesoutpinning_set
seen_in_cprh   ri   rj   rk   scene_set_outscenesishisi_intshi_int
variations
shot_countvivarr(   shot_violationsr.   s                              r   mainr      s7   $$NF 
d;
c48
#t<
*tD
[)	   ,3E
5CN
)TB
$	   ,3E
)T   
t<D$T*GWd#G	'	"B&(!";F~D+?@C)'2K'*uJK+-$& "M%&& ''(ABYY}%ii&:Rc(GK/() /67$8

 6'
 	
 	q
 ,GBc4(($++xs7)2bT1GH WW\*Ffc**&,,..$++xs7)2bT 2( ) 08O#o..J$!((!6 '%r*(!,@*A(!,@*A*  % -2 	Z'6@xq	23m r !	S9J& ''RDC5(HI ! 	[]$--		7];!2"$8!2"D)?$@"D)E$F
 	 4!1$$??):a)?I ;;1> 
'C: 	
"499+ .--. /$ &./ 0##&';#<"= >3		4 ZZ	 yyK$5$9r!   c               (    V ^8  d   QhRRRRRRRR/# )r   r   zargparse.Namespacere   r}   rn   r   r   r   )r   s   "r   r    r    >  s0      
  
	r!   c                    R \        4       RV P                  RV P                  RVR. RR^ R^ R/ R	. R
\        \        4      R\        \
        4      /RVR^ RRRRR//
# )rb   rc   rd   re   rf   rg   rh   ri   rj   rk   rl   rm   rn   ro   rp   Frq   rr   z.scripts/canary/g4_4_view_mixing.py (all shots))r&   rc   rd   r   r   r   )r   re   rn   s   &&&r   rz   rz   >  s     	[]$--		7R1"B"D)?$@"D)E$F
 	 4!1e@ 
# r!   __main__)standsseatedleaningwalkingrunningkneelinglying),__conditional_annotations____doc__
__future__r   rv   r   r   r   pathlibr   pathinsertr   __file__resolveparent_g4_4_commonr   r   r   r   r	   r
   r   r   r   _CONSTSr   r   r   __annotations__join_TRIGGER_ALTcompile
IGNORECASEr9   r4   r=   r&   rN   r   rz   __name__exit)r   s   @r   <module>r      s  "F #  	 
   3tH~--/667 8
 
 
 %
& !9: *1-+ '
1 o  xxE.DEE::|>>MM  JJ/0	/;|cL< zHHTV r!   