
    +i!/                       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mZ ddlm	Z	 ej                  j                  d e e	e      j                         j                               ddlmZmZmZmZmZmZmZmZmZ  e       Zed   Z ej8                  d      Zd	Zdd
ZddZ 	 	 	 	 	 	 	 	 ddZ!e"dk(  r ejF                   e               yy)u  G4.4 canary — STRICT double-description detection (Task 4.1).

Detects co-occurrence of a mapped character ID (`C##` / `C##O##`) and a
generic person noun (`an Asian man` / `a young woman` / `a figure` etc. —
imported from `_CONTINUITY_GENERIC_PERSON_NOUNS`) within a ±50 chars
window. Generic noun list is imported from
`render_prompt_card._CONTINUITY_GENERIC_PERSON_NOUNS` (Trap #8 — module-level
constant single source).

Scope: id-mapping shots only (R2-B4 carry — `fixed_elements[i].character_name`
maps to a `C##` / `C##O##` listed in `id_policy.allowed_outlook_pairs`).

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

Override O-7 — paired-string substring carry: any double-description with the
same character ID treated as cross-card / cross-shot violation; canary
intentionally does NOT inspect cross_shot_id_substitution_rule wording.

Usage (config mode):
    python scripts/canary/g4_4_double_description.py \
        --config canary_config.json \
        --cp-root data/projects/<pid>/checkpoints/scene_detail \
        --prompt-version 19.<timestamp> \
        --role candidate \
        --output results/double_description_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 _CONTINUITY_GENERIC_PERSON_NOUNSz\bC\d{2}(?:O\d{2})?\b2   c                 L    t        j                         j                         dz   S )NZ)r   utcnow	isoformat     )scripts/canary/g4_4_double_description.pyiso8601_nowr   >   s    ??&&(3..r   c                 z   t        j                  d      } | j                  dt        d        | j                  dt        d        | j                  dt        d d       | j                  d	t        d
       | j                  dt        dddg       | j                  dt        d        | j                  dt        d        | j                  dt        d        | j                  dt        d g d       | j                  dt        d        | j                  dt        d        | j                  dt        d
       | j	                         }t        |      }t        |       t        |      }t        |      }g }t        ||      }|t        |||      }t        ||       yt        |      }t               }	d}
d}i }g }|D ]  }t        |t              s|j!                  d       &|j#                  d      }|j#                  d      }||Mt%        |      }t%        |      }||f|vrj|	j'                  ||f       t)        ||||      }||d   }|d   }d|vr|j!                  d | d!| d"       |d   }t        |t*              s|j!                  d | d!| d#       d$|vr|j!                  d | d!| d%       |d$   }t        |t              s|j!                  d | d!| d&       0d'|vr|j!                  d | d!| d(       N|d'   }t        |t*              s|j!                  d | d!| d)       }d*}|D ]  }t        |t              s|j#                  d+      }t        |t              r|s8|D ]y  }t        |t              s|j#                  d,      }|j#                  d-      }t        |t              r||k(  s,t        |t              s\t        |t              sm|| | k(  swd
} n |s n |j!                  |||d.       |sV|
dz  }
d}t-        |      D ]!  \  } }!t        |!t              s|j!                  d | d!| d/|  d0       3|!j#                  d1      }"t        |"t              r|"j/                         s|j!                  d | d!| d/|  d2       |"j1                         }#t2        j5                  |"      D ]z  }$|$j7                         }%|$j9                         }&t;        d|%t<        z
        }'t?        tA        |"      |&t<        z         }(|#|'|( })tB        D ]  }*|*j1                         |)v s|dz  } z | $ ||z  }||| d3| <    |D ]$  \  }}||f|	vs|j!                  d4| d!| d5       & tE               |jF                  |jH                  |||
||t+        tB              d6|d| xr |dk(  d7d8id9
}t        ||       tK        d:|jH                   d;|jF                   d<|
 d=| d>tA        |       d?tL        jN                  @       |ry|jH                  dk(  r|dkD  ryy)ANue   G4.4 canary: double-description detection (id-mapping shots only — Trap #8 module-level constants).)descriptionz--config)typedefaultz--pidz	--cp-rootz/Directory containing scene_detail manifest.json)r   r   helpz--prompt-versionT)r   requiredz--role	candidatebaseline)r   r   choicesz--scene-index-listz--shot-index-list-per-scenez--model-routingz--prompt-source-mode)Nfiledbz--card-commit-hashz--continuity-card-snapshot-hashz--output   r   zscene entry is not dictscene_index_shot_indexrender_prompt_cardcontinuity_elements_usedfixed_elementss_shz5: continuity_elements_used.fixed_elements key missingz2: continuity_elements_used.fixed_elements not list	id_policyz*: render_prompt_card.id_policy key missingz': render_prompt_card.id_policy not dictallowed_outlook_pairsz-: id_policy.allowed_outlook_pairs key missingz*: id_policy.allowed_outlook_pairs not listFcharacter_namecharacter_id
outlook_id)r%   
shot_indexhas_fixed_element_id_mapping_vz: variation not a dict
t2i_promptz': t2i_prompt missing, empty, or not str_z
pinning (sz ): not present in CP data.scenestotal_shots_with_id_mappingdouble_description_countdouble_description_per_shotgeneric_person_nouns_useddouble_description\   scripts/canary/g4_4_double_description.py (id-mapping shots only — Override O-7 / Trap #8)
	timestampprompt_versionrolepinning	scene_setmetricsmeasurement_failuresexit_criteria_thresholdexit_criteria_passmeasurement_scriptsz[g4_4_double_description] role=z prompt_version=z
  total_shots_with_id_mapping=z
  double_description_count=z
  measurement_failures: zH
Exit criteria (STRICT): candidate.metrics.double_description_count == 0)r"   )(argparseArgumentParseradd_argumentstr
parse_argsr   r   r   r
   r   _empty_outputr	   r   set
isinstancedictappendgetintaddr   list	enumeratestriplower	_ID_REGEXfinditerstartendmax_WINDOW_CHARSminlenr   r   r?   r@   printsysstderr)+parserargsrA   cp_rootcprD   scenesoutpinning_set
seen_in_cpr7   r8   r9   scene_set_outscenesishisi_intshi_int
variationsrpccer)   r,   allowed_pairshas_id_mappingfer.   opcidoid
shot_countvivarpromptprompt_lowermatchid_startid_end	win_startwin_endwindownouns+                                              r   mainr   B   sJ   $$JF 
d;
c48
>	   *tD
[)	   ,3E
5CN
)TB
$	   ,3E
)T   
t<D$T*GWd#G	'	"B&(!"&:;F~D'+?@C)'2K'*uJ"# 24 "M%& ''(ABYY}%ii&:Rc(GK/().67$8

 ()+,2% ''F83wi (- . ,-.$/ ''F83wi (* + c! ''F83wi (  $	)T* ''F83wi (  ")3 ''F83wi (  !"9:-. ''F83wi (  
  Bb$'VV$45Nnc2.#!"d+ff^,ff\*sC(^s-BsC("3,&SE#-7%)N $ + !. 	!!,:
 	 #q(#
 ,GBc4($++xs7)2bT1GH WW\*Ffc*&,,.$++xs7)2bT 2( )  "<<>L"++F3 ;;=8m#;<	c&k6M+AB%i8<Dzz|v-"a
 = 4! -8 	!J. =G#vhay$9:E J !	S9J& ''RDC5(HI ! !]--		"+F(@+F)-0*	
 !5#$$$F)AQ)F !E 
'C6 T	
)$)) 5--. /))D(E F&&>%? @##&';#<"= >:		; ZZ	 yyK$<q$@r   c                |    t               | j                  | j                  |g ddi t        t              d|ddddid
S )Nr   r6   Fr;   r<   r=   )r   r?   r@   rU   r   )re   rA   rD   s      r   rM   rM   6  s[     !]--		+,()+-)-0*	
 !5#$# E 
# r   __main__)returnrK   )r   rS   )re   zargparse.NamespacerA   rP   rD   rU   r   rP   )$__doc__
__future__r   rH   jsonrerb   r   pathlibr   pathinsertrK   __file__resolveparent_g4_4_commonr   r   r   r	   r
   r   r   r   r   _CONSTSr   compilerY   r^   r   r   rM   __name__exitr   r   r   <module>r      s   6 #   	 
   3tH~--/667 8
 
 
 %
&#*+M#N   BJJ/0	/qh
  
	> zCHHTV r   