
    ej#                        d Z ddlmZ ddlmZmZmZ ddlmZmZm	Z	m
Z
mZ dZdZdZdZd	Zd
ZdZ e ed            ZddZddZddZded	 	 	 	 	 	 	 ddZded	 	 	 	 	 	 	 ddZy)u  utils.gate_snapshot_validator — pre_merge_gate_snapshot.json validator.

task-2637 — real merge executor wiring 코드화 (activation false default · 실제 merge 실행 0).

Spec: memory/specs/system_real_merge_executor_wiring_spec_260523.md §4 + §7.2
sha256: bcaf654e981a43083af50879164021c918eeac9753cad3b3ad146209a1a62765

회장 verbatim (회장 10결정 #3):
    gate_snapshot TTL = 5분 확정.

11종 gate (spec §4 Table):
    1. ci_checks (11/11 success)
    2. gemini_review_gate (PASS, fresh head)
    3. phase3_merge_gate (PASS)
    4. unresolved_threads (value=0)
    5. mergeStateStatus (CLEAN/MERGEABLE)
    6. critical7_hits (value=0)
    7. blocking_secret (value=0; net_new_identifier_exposure=0)
    8. expected_files_exact (value=True)
    9. forbidden_path (value=0)
    10. admin_override_required (value=False)
    11. callback_lifecycle_artifact (value="normal" delivery_outcome 정상)

TTL 검증:
    snapshot.ts_kst + snapshot_ttl_seconds < now → STALE_SNAPSHOT
    )annotations)datetime	timedeltatimezone)AnyDictListOptionalTuplezreal_merge.pre_gate_snapshot.v1i,  )	ci_checksgemini_review_gatephase3_merge_gateunresolved_threadsmergeStateStatuscritical7_hitsblocking_secretexpected_files_exactforbidden_pathadmin_override_requiredcallback_lifecycle_artifactGATE_OKGATE_INVALID_SCHEMA
GATE_STALE	GATE_FAIL	   )hoursc                    d}|D ]>  }	 t        j                  | |      }|j                  |j                  t              }|c S  y # t
        $ r Y Mw xY w)N)z%Y-%m-%dT%H:%M:%S%zz%Y-%m-%d %H:%M:%S%zz%Y-%m-%dT%H:%M:%Sz%Y-%m-%d %H:%M:%Sz%Y-%m-%d %H:%Mtzinfo)r   strptimer   replace_KST
ValueError)text
candidatesfmtdts       N/home/jay/workspace/.worktrees/task-2658-dev6/utils/gate_snapshot_validator.py
_parse_kstr)   <   si    J  	""4-Byy ZZtZ,I   		s   9A	AAc                4   | 6t        j                  t        j                        j	                  t
              S  |        }t        |t               r$|j                  r|S |j                  t
              S t        t        |            }|t        d|      |S )Nr   z#clock() returned unparsable value: )r   nowr   utc
astimezoner"   
isinstancer   r!   r)   strr#   )clockvalparseds      r(   _now_kstr3   O   s}    }||HLL)44T::
'C#x jjs>ckkk&>>C!F~>sgFGGM    c                   | j                  d      }|dk(  rU| j                  d      dk7  rdd| j                  d      fS | j                  d      dvrdd	| j                  d      d
fS y|dk(  r(| j                  d      dk(  d| j                  d      fS |dk(  r(| j                  d      dk(  d| j                  d      fS |dk(  r(| j                  d      dk(  d| j                  d      fS |dk(  r| j                  d      }|dvrdd|fS y|dk(  r(| j                  d      dk(  d| j                  d      fS |dk(  rT| j                  d      dk7  rdd| j                  d      fS | j                  d      dvrdd| j                  d      fS y|dk(  r0t        | j                  d            d u d!| j                  d      fS |d"k(  r(| j                  d      dk(  d#| j                  d      fS |d$k(  r0t        | j                  d            du d%| j                  d      fS |d&k(  r(| j                  d      d'k(  d(| j                  d      fS dd)|fS )*zPer-gate pass evaluator.

    Returns (passed, reason_if_fail). Each gate has a deterministic interpretation
    so the snapshot can be authored by any collector with the same semantics.
    namer   
conclusionsuccessFzci_checks.conclusion=count)N z11/11zci_checks.count=z (expected '11/11'))Tr:   r   PASSzgemini_review_gate.conclusion=r   zphase3_merge_gate.conclusion=r   valuer   zunresolved_threads.value=r   )CLEAN	MERGEABLEzmergeStateStatus.value=r   zcritical7_hits.value=r   zblocking_secret.value=net_new_identifier_exposure)r   Nz,blocking_secret.net_new_identifier_exposure=r   Tzexpected_files_exact.value=r   zforbidden_path.value=r   zadmin_override_required.value=r   normalz"callback_lifecycle_artifact.value=zunknown gate name )getbool)gater6   r1   s      r(   _gate_passesrD   [   s    88FD{88L!Y.1$((<2H1KLLL88G$77,TXXg->,AATUUU##HH\"f,,TXXl-C,FG
 	
 ""HH\"f,+DHH\,B+EF
 	
 ##HHW"'(9'<=
 	
 !!hhw,,3C7;;;HHW"#DHHW$5#89
 	
   88G!2488G3D2GHHH8812)C>889:=?  %%'"#t+)$((7*;)>?
 	
 HHW"#DHHW$5#89
 	
 (('"#u,,TXXg->,AB
 	
 ,,HHW)0'1B0EF
 	
 &th///r4   N)r0   ttl_secondsc                  g }t        | t              s dt        dt        |       j                   gfS | j                  d      t        k7  r*|j                  dt        d| j                  d             | j                  d      }t        |t              r|s|j                  d       |r	dt        |fS t        |t              rt        |      nd}|dt        d	|gfS | j                  d
|      }	 t        |      }t        t        |      |      }t        |      }	|	|z
  j                         }
|
|kD  r4dt         d|
dd| d|j#                          d|	j#                          d	gfS | j                  d      }t        |t$              s dt        dt        |      j                   gfS |D ch c]$  }t        |t              s|j                  d      & }}t&        D cg c]	  }||vs| }}|rdt        d| gfS t)        d |D              }|rdt        d| gfS g }|D ]I  }t        |t              s|j                  d|       (t+        |      \  }}|r9|j                  |       K |r	dt,        |fS | j                  d      }|du r
dt,        dgfS dt.        g fS # t        t        f$ r dt        d|gfcY S w xY wc c}w c c}w )uB  Validate a pre_merge_gate_snapshot.json payload.

    Returns:
        (all_pass, code, reasons) — ``code`` is one of GATE_* enums.

    Order of checks:
      1. dict + schema
      2. ts_kst parsable + within TTL
      3. 11 gate names present, no extras
      4. Each gate passes its deterministic interpretation
    Fzsnapshot must be dict, got schemazschema must be z, got ts_kstz%ts_kst must be a non-empty ISO stringNzts_kst unparsable: snapshot_ttl_secondsz&snapshot_ttl_seconds must be int, got zsnapshot age z.0fzs > ttl z
s (ts_kst=z, now=)gateszgates must be a list, got r6   zmissing required gate names: c              3  F   K   | ]  }||t         vrt        |        y w)N)REQUIRED_GATE_NAMESr/   ).0ns     r(   	<genexpr>z)validate_gate_snapshot.<locals>.<genexpr>   s)      =Q&99 	As   !zunexpected gate names: zgate entry not a dict: all_passue   snapshot.all_pass is False despite every gate passing — trust authored all_pass=False (fail-closed)T)r.   dictr   type__name__rA   GATE_SNAPSHOT_SCHEMAappendr/   r)   int	TypeErrorr#   minr3   total_secondsr   	isoformatlistrM   sortedrD   r   r   )snapshotr0   rE   reasonsts_rawrH   declared_ttldeclared_ttl_inteffective_ttlr+   age_secondsrK   gobserved_namesrO   missingextrasfail_reasonsrC   okreasondeclared_all_passs                         r(   validate_gate_snapshotrm      sW   " Gh%))$x.*A*A)BC,
 
 	
 ||H!5525VHLL<R;UV	
 \\(#Ffc"&>?)722#-fc#:ZF~).A&,L+MMM<< 6DL
|,
 K(*:;M
5/C<..0K]"jK,H]O D'')*&0AD#
 
 	

 LL!EeT")(e)=)=(>?,
 
 	
 .3JjD6IaeeFmJNJ-IQ.1HqIGI)+G95,
 
 	
  & F )%fX.,
 
 	
 !L ($%"9$ BC!$'
F'( i-- Z0E!i:"
 
 	
 "g z" 
)4\4DE,
 
 	

$ KIs*   3J% /KK"	K,K%KKc                   t        | t              sy| j                  d      }t        |t              rt	        |      nd}|yt        |      }||z
  j                         |k  S )z8Single-purpose freshness predicate (no gate evaluation).FrH   N)r.   rR   rA   r/   r)   r3   rZ   )r^   r0   rE   r`   tsr+   s         r(   is_snapshot_freshrp      s]     h%\\(#F)&#6F	DB	z
5/C"H##%44r4   )r$   r/   returnzOptional[datetime])r0   Optional[Any]rq   r   )rC   zDict[str, Any]rq   zTuple[bool, str])r^   r   r0   rr   rE   rW   rq   zTuple[bool, str, List[str]])r^   r   r0   rr   rE   rW   rq   rB   )__doc__
__future__r   r   r   r   typingr   r   r	   r
   r   rU   GATE_SNAPSHOT_TTL_SECONDSrM   r   r   r   r   r"   r)   r3   rD   rm   rp    r4   r(   <module>rx      s   4 # 2 2 3 38    + 
		"#&	C0R  0	[[ [ 	[
 ![B  0	55 5 	5
 
5r4   