
    jU                     $   d Z ddlmZmZmZmZmZmZmZm	Z	m
Z
mZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZm Z m!Z!m"Z"m#Z#m$Z$m%Z%m&Z&m'Z'm(Z(m)Z)m*Z*m+Z+m,Z,m-Z-m.Z.m/Z/m0Z0m1Z1m2Z2m3Z3m4Z4m5Z5m6Z6m7Z7m8Z8m9Z9 d Z:d Z;d Z<d Z=ddZ>e6dd	d
Z?d Z@y)u  Merge-ready classifier (evidence-only, pure function, decoupled).

PR/Gemini/CI/phase3/scope/credential/lifecycle evidence snapshot(dict) 를 종합해
merge 가능 여부(verdict)와 회장 보고 필요 여부(chair_triggers)를 결정적으로 판정한다.
callback lifecycle classifier 와 동형 — evidence-only · I/O 0 · merge 실행 0.

doctrines (spec §1~§6):
- evidence-only decoupled: anu_v3/런타임 import 0
- pure function · read-only · 파일/네트워크/subprocess/live-git/merge I/O 0 · no daemon
- 추정 금지 → 핵심 gate evidence 결핍 시 UNKNOWN(재수집)
- verdict precedence (상태기계): UNKNOWN > CHAIR_REQUIRED > HOLD > PASS
- credential 3계층: BLOCKING_SECRET/NET_NEW → CHAIR · EXISTING/NONE → fail 아님
- Critical7 1:1 → 전부 CHAIR_REQUIRED
- Gemini auto-remediation: medium/style/non-critical HIGH(+expected_files 내부) → HOLD(auto_remediable)
- callback lifecycle classification==INCIDENT → CHAIR_REQUIRED 승격

evidence collector(gh/git 조회)는 별도 read-only collector 가 담당한다.
classifier 는 dict 만 입력받는 순수함수다 (git grep/gh/merge 직접 호출 X).

단일소스 스펙: memory/specs/system_merge_ready_executor_spec_260522.md
    )8PASSHOLDCHAIR_REQUIREDUNKNOWN	CRED_NONECRED_EXISTING_SYSTEM_IDENTIFIERCRED_NET_NEWCRED_BLOCKING_SECRETCREDENTIAL_CHAIR_TIERSCOMPLETEPARTIALMISSINGC7_FORBIDDEN_PATH C7_OUT_OF_SCOPE_REPLACEMENT_FAILC7_SCOPE_EXPANSIONC7_OVERRIDEC7_DEPENDENCY_CYCLE_OR_SERIALC7_REPLACEMENT_FAILC7_POST_MERGE_SMOKE_FAIL	CRITICAL7CRITICAL7_ORDERCHAIR_CRITICAL7%CHAIR_CREDENTIAL_PERMISSION_EXPANSIONCHAIR_OUT_OF_EXPECTED_FILESCHAIR_ADMIN_OVERRIDECHAIR_REPLACEMENT_PR_FAILURECHAIR_POST_MERGE_SMOKE_FAILURECHAIR_DEPENDENCY_OR_SERIALCHAIR_MERGE_POLICY_CHANGECHAIR_LIFECYCLE_INCIDENT$CHAIR_AUTO_REMEDIATION_LOOP_BOUNDARYCHAIR_TRIGGER_ORDERAR_CI_PENDINGAR_GEMINI_EVIDENCE_STALE AR_GEMINI_MEDIUM_WITHIN_EXPECTED*AR_GEMINI_NONCRITICAL_HIGH_WITHIN_EXPECTEDAR_UNRESOLVED_MEDIUM_THREAD AR_MERGE_STATE_TRANSIENT_BLOCKEDAUTO_REMEDIABLE_ORDER!GEMINI_AUTO_REMEDIABLE_SEVERITIESAUTO_MERGE_10_CONDITION_KEYSLIFECYCLE_NORMALLIFECYCLE_INCIDENTLIFECYCLE_INCIDENT_MISS_CAUSESCI_PENDING_STATESCI_PASS_STATESCI_FAIL_STATESMERGE_STATE_CLEANMERGE_STATE_BLOCKEDMERGEABLE_OKCANONICAL_EVIDENCE_SOURCESCORE_EVIDENCE_SOURCESDEFAULT_ANU_KEYSis_anu_owner_keyCLASSIFIED_BYNEXT_ACTIONc                     | yt        | t              r| S t        | t        t        t        t
        t        f      rt        |       dkD  S t        | t        t        f      r| dkD  S t        |       S )uR   리스트/집합은 비어있지 않으면 True, 수치는 >0, bool 은 그대로.Fr   )

isinstanceboollisttupleset	frozensetdictlenintfloatvalues    M/home/jay/workspace/.worktrees/task-2723-dev2/utils/merge_ready_classifier.py_truthy_signalrI   >   s^    }%%$sIt<=5zA~%#u&qy;    c                 4    || v xr | j                  |      d uS Nget)evidencekeys     rH   _src_presentrQ   K   s    (?<x||C0<<rJ   c                     t         D cg c]  }t        | |      s| c}t         D cg c]	  }|vs| }}t        fdt        D              rt        |fS |st
        |fS t        |fS c c}w c c}w )Nc              3   8   K   | ]  }|t              v  y wrL   )r@   ).0spresents     rH   	<genexpr>z)_evidence_completeness.<locals>.<genexpr>T   s     
@Q1CL 
@s   )r5   rQ   anyr6   r   r   r   )rO   rU   missingrV   s      @rH   _evidence_completenessrZ   O   st    4RQXq8QqRG4IQ8HqIGI 
@*?
@@  G SIs   A-A-	A2A2c                 X    | 't        |       j                         j                         S dS )N )strstriplowerrF   s    rH   _lowerr`   [   s(    ).):3u:##%BBrJ   c                 H    	 t        |       S # t        t        f$ r |cY S w xY w)u   안전 int 변환 (Gemini medium): evidence 값이 비숫자('N/A' 등)여도 ValueError 없이
    default 로 폴백. 입력 정합성이 완벽히 보장되지 않는 frozen evidence 방어.)rD   	TypeError
ValueError)rG   defaults     rH   _as_intre   _   s*    5zz" s   
 !!N)anu_keysexpected_filesc                  TUV | xs i } | j                  d      xs i }| j                  d      xs i }| j                  d      xs i }| j                  d      xs i }| j                  d      xs i }| j                  d      xs i }| j                  d      xs i }	t        |       \  }
}t        |j                  d            }t        |j                  d	            }t        |j                  d
            }|rt        }n|rt
        }n|rt        }nt        }|
t        k(  r0t        D ci c]  }|d }}t        t        dgg g |g ||
|ddi
      S |t        |      n|j                  d      xs g }t        |      V|j                  d      }t        |j                  d            }|j                  d      }|t        Vfd|D              nd}t        |      xs t        |      }|j                  d      }|t        |      Vk(  xr | }nt        |      xr | xr | }t        |j                  d            }t        |j                  d            }t        |j                  d            }t        |j                  d            }t        |j                  d            }t        |j                  d            }t        |j                  d            } |j                  d      xs g }!t        |j                  d            }"t        |j                  d             }#|"d!k(  xs |#d!k(  }$|"d"k(  }%t        |j                  d#            }&t        |j                  d$            }'t        |j                  d%            xs t        |j                  d%            }(d& Ud' Tt        Ufd(|!D              })|j                  d)      }*t        TUfd*|!D              }+t        TUfd+|!D              xs |&d"k(  },t        TUfd,|!D              }-t               }.|r|.j!                  t"               |r|r|.j!                  t$               |)s|(r|.j!                  t&               |s|r|.j!                  t(               |s|r|.j!                  t*               |r|.j!                  t,               | r|.j!                  t.               |j                  d-      xs g D ]  }/|/t0        v s|.j!                  |/        t2        D 0cg c]	  }0|0|.v s|0 }1}0t        |	j                  d.            xs t4        }2|	j                  d/      }3|	j                  d0      xs |	j                  d1      }4t        |	j                  d2            }5|5xr |4duxr t7        |4|       }6|2t8        k(  xs |3t:        v xs |6}7|j                  d3      xs i }8t=        |8t>              r'|8jA                         D 9cg c]  }9t        |9       c}9ng }:t        |j                  d4            xs t        d5 |:D              };t        d6 |:D              }<|j                  d7      }=|= t        |:      xr tC        d8 |:D              }>nt        |=      xr |; xr |< }>tE        |j                  d9      xs d:      jG                         }?tE        |j                  d;      xs d:      jG                         }@|j                  d<      }At=        |At>              r:tI        Aj                  d=            }BtI        |Aj                  d>            }C|B|Cz   }Dn,t=        AtJ        tL        f      rtI        A      }D|D}Bd?}Cnd?x}Bx}C}D|j                  d@      }E|EdAu xs t        E      dBk(  }F|"dBk(  xr2 |$ xr- |% xr( |*dCv xr" |+ xr |&d"k7  xr t        TUfdD|!D               }G||>xr |; xr |< t        G      t        F      |?tN        k(  @tP        k(  Bd?k(  xr Cd?k(  |t        t        fv tS        |1      d?k(  |7 dE
}t               }Hg }I|1r8Hj!                  tT               IjW                  dFdGjY                  |1      z          |tZ        v r*Hj!                  t\               IjW                  dH| dI       |r&Hj!                  t^               IjW                  dJ       |s|r&Hj!                  t`               IjW                  dK       |r&Hj!                  tb               IjW                  dL       | r&Hj!                  td               IjW                  dM       |s|r&Hj!                  tf               IjW                  dN       |r&Hj!                  th               IjW                  dO       |7r&Hj!                  tj               IjW                  dP       |-r(|'r&Hj!                  tl               IjW                  dQ       tn        D Jcg c]	  }J|JHv sJ }K}Jt               }L|;rLj!                  tp               |$rLj!                  tr               |t        t        fv }M|,rMr|1sLj!                  tt               |-r|'s|(sMr|1sLj!                  tv               Cd?kD  rBd?k(  rLj!                  tx               |?tz        k(  rKsLj!                  t|               t~        D Ncg c]	  }N|NLv sN }O}NKrt        }PntC        |jA                               r	Ost        }Pnwt        }PIso|j                         D Qcg c]
  \  }}Q|Qr	| }R}}Q|Rr#IjW                  dRdGjY                  R      z          Or#IjW                  dSdGjY                  O      z          ||||;|<|>|$|%|7rt8        nt4        BCDdT|?@t        |j                  dU            t        |j                  dV            |dW}St        PIKO||1||
||S
      S c c}w c c}0w c c}9w c c}Jw c c}Nw c c}Q}w )Xu  evidence snapshot(dict) → merge-ready 분류 결과(dict). 순수함수.

    Args:
        evidence: scope/credential/gates/gemini/critical7/merge_mechanics/lifecycle
                  섹션을 가진 frozen evidence dict (collector 가 사전 수집).
        anu_keys: ANU authoritative owner key 집합 (라우팅 식별자, 비밀 아님).
        expected_files: 선언된 expected_files (없으면 evidence['scope']['expected_files'] 사용).

    Returns:
        dict: verdict · blocking_reasons · chair_triggers · auto_remediable
              · auto_merge_10_conditions · critical7_hits · credential_tier
              · evidence_completeness · next_action · classified_by (+부가 진단 필드)
    scope
credentialgatesgemini	critical7merge_mechanics	lifecycleblocking_secret_hitsnet_new_identifier_exposure existing_system_identifier_reuseFuF   core gate evidence(scope/gates) 결핍 → 재수집 필요 (추정 0)reasoncore_gate_evidence_missing
verdictblocking_reasonschair_triggersauto_remediable
conditionscritical7_hitscredential_tiercompletenessrY   diagNrg   effective_diff_filesforbidden_path_hits"out_of_expected_files_modificationc              3   &   K   | ]  }|v 
 y wrL    )rT   fexpected_sets     rH   rW   z'classify_merge_ready.<locals>.<genexpr>   s     5aA\!5s   exact_matchreplacement_pr_failureadmin_override_required!branch_protection_bypass_requireddependency_cycleserial_only_collisionmerge_policy_change_requiredpost_merge_smoke_failuregemini_findingsgemini_review_gateevidence_freshnessstalependingmedium_auto_remediation_statusrepeated_high_same_functionscope_expansion_requiredc                 8    t        | j                  d             S )Nresolved)r=   rN   r   s    rH   _unresolvedz)classify_merge_ready.<locals>._unresolved   s    j)***rJ   c                 6    t        | j                  d            S )Nseverity)r`   rN   r   s    rH   _sevz"classify_merge_ready.<locals>._sev   s    aeeJ'((rJ   c              3   X   K   | ]!  } |      xr |j                  d       du  # yw)within_expected_filesFNrM   )rT   r   r   s     rH   rW   z'classify_merge_ready.<locals>.<genexpr>   s4       	ADAEE"9:eCDs   '*high_or_critical_unresolvedc              3   F   K   | ]  } |      xr
  |      d v   yw))highcriticalNr   rT   r   r   r   s     rH   rW   z'classify_merge_ready.<locals>.<genexpr>   s/      . 	A:47&:::.   !c              3   v   K   | ]0  } |      xr"  |      t         v xr |j                  d d       2 yw)r   TN)r*   rN   r   s     rH   rW   z'classify_merge_ready.<locals>.<genexpr>   sI      #  	A 	147&GG 	1EE)40	1#s   69c              3   p   K   | ]-  } |      xr  |      d k(  xr |j                  dd       / yw)r   r   TNrM   r   s     rH   rW   z'classify_merge_ready.<locals>.<genexpr>   s@      ! 	AU47f,U7NPT1UU!s   36r{   classificationnormal_callback_miss_cause	owner_keynormal_callback_owner_keyfired	ci_checks
ci_pendingc              3   ,   K   | ]  }|t         v   y wrL   )r/   rT   rU   s     rH   rW   z'classify_merge_ready.<locals>.<genexpr>  s     5`QRa;L6L5`   c              3   ,   K   | ]  }|t         v   y wrL   )r1   r   s     rH   rW   z'classify_merge_ready.<locals>.<genexpr>  s     ;AA';r   ci_all_passc              3   ,   K   | ]  }|t         v   y wrL   )r0   r   s     rH   rW   z'classify_merge_ready.<locals>.<genexpr>  s     -Uaa>.A-Ur   mergeStateStatusr\   	mergeableunresolved_threadsr   mediumr   phase3_merge_gateTpass)Nr   c              3   F   K   | ]  } |      xr
  |      d v   yw))r   r   Nr   r   s     rH   rW   z'classify_merge_ready.<locals>.<genexpr>7  s'     WKNDtAw2D'DDWr   )
exact_scope_matchci_all_greengemini_review_passphase3_merge_gate_passmerge_state_cleanr   threads_resolvedcredential_cleanno_critical7lifecycle_normalu   Critical7 적중: z, u'   credential·permission expansion (tier=)u    expected_files 밖 수정 필요u0   admin override / branch protection 우회 필요zreplacement PR failurezpost-merge smoke failurez(dependency cycle / serial_only collisionu   merge policy 변경 필요uH   callback lifecycle classification=INCIDENT (production 신뢰성 훼손)u9   auto-remediation loop boundary: 같은 함수 HIGH 반복u   auto-merge 10조건 미충족: u   자동수렴 후보: )r   r   total
queue_headserial_conflict)r   r   forbidden_path_presentr   	ci_failedr   gemini_stalegemini_pendinglifecycle_classificationr   merge_stater   r   r   declared_expected_files)DrN   rZ   rI   r=   r
   r	   r   r   r   r+   _resultr   r>   r@   rX   r`   addr   r   r   r   r   r   r   r   r   r,   r8   r-   r.   r<   rB   valuesallr]   upperre   rD   rE   r2   r4   rC   r   appendjoinr   r   r   r   r   r   r   r   r    r!   r"   r#   r$   r%   r&   r'   r3   r(   r)   r   r   r   items)WrO   rf   rg   ri   credrk   gemc7mechlifer}   rY   blocking_presentnet_newexistingr|   krz   declared_expected	effectiveforbidden_presentoof_providedout_of_expected_observedout_of_expectedem_providedr   r   r   bp_bypass_requiredr   r   merge_policy_changer   findingsgemini_gate	freshnessr   r   medium_statusrepeated_highr   gemini_requires_oofr   #unresolved_high_or_critical_findingmedium_within_unresolvedhigh_within_unresolvedrm   hcr{   life_classificationlife_miss_causelife_owner_key
life_fired self_key_fired_non_authoritativelifecycle_incidentr   rU   	ci_statesr   r   ci_all_pass_providedr   r   mergeable_statethreadsut_high	ut_mediumut_totalphase3phase3_passr   chairrw   trx   autocred_clean_for_remediationary   rv   vfailedr~   r   r   r   sW                                                                                       @@@rH   classify_merge_readyr
  l   s    ~2HLL!'RE<<%+DLL!'RE
,,x
 
&BC	k	"	(bB<<)*0bD<<$*D28<L' &dhh/E&FG4889:;GDHH?@AH.	&	9# w(DE1ahE
Efg!+%89
 	
 1?0J^,QVQZQZ[kQlQrpr()L		01I&uyy1F'GH99ABL :C9N5955TY  34J\8JO))M*K 9~5P?P;P;'Y0A,AY/FY ""&&)A"BC"266*C#DEbff%HIJBFF#567 (?!@Arvv&DEF#BFF+E$FG ww()/RH#789Ksww345I')AY'-AL I-N377#CDEM!>?@M#CGG,F$GHtDQSQWQWXrQsLt+)    #&''*G"H*- .. +'  # # #    $ 
)	#	 
 ! !! 
 I'(1676()"4k"034)*./ff%&," 	>MM! "1CAANaCNC !*:!;<P@Phh;<O XXk*Sdhh7R.SNdhhw'(J 	;~T1 	; :: %
 	11 	,==	,+  		+&,"I;EiQU;VI$4$4$67q7\^Ieii-.`#5`V_5`2`J;;;I 99]3#9oU#-U9-U*U/0U^UIeii 239r:@@BK%))K06B7==?Oii,-G'4 '++f-.GKK12	 Y&	Gc5\	*7#	)***)hYY*+FT>@vf~'?K 	v 	X	X%3!3	X(I5	X 43	X Y&		X WhWWW  )#HJHy="#56"&{"3(,==$4 %\<i1n+	;Z/[[N+q0 22J& EE		/" 4tyy7P PQ00		78"I/IZZ[ \]		-. BC"4		&' RS		./ 89		01 :;0		,- JK		+, <=		*+V	
 -		67 [\!4CAU
aCNC 5D)*!0Y@_4`!`$>~12}=U&~;<1}A,-)).12"7EQ19qEOE  	Z 	!/$.$4$4$6@DAqaa@F@ ''(IDIIV\L](]^ ''(?$))OB\(\] #.="3 "$(:L$6Rb'.)hW"$488L12): ;<#4D$ )%'%'! c FP D* 8| D( F As<   +
o	oo(o$	o#.o#;	o(o(
o-o-c        
         6    | ||||||||t         |    |	t        dS )u*   반환 dict 조립 (필드 순서 고정).)rv   rw   rx   ry   auto_merge_10_conditionsr{   r|   evidence_completenessmissing_evidence_sourcesnext_actionmerge_ready_evidenceclassified_by)r:   r9   ru   s
             rH   r   r     s7     ,(*$.(*!-$+"7+ $& rJ   )r   )A__doc__utils.merge_ready_statesr   r   r   r   r   r   r	   r
   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r    r!   r"   r#   r$   r%   r&   r'   r(   r)   r*   r+   r,   r-   r.   r/   r0   r1   r2   r3   r4   r5   r6   r7   r8   r9   r:   rI   rQ   rZ   r`   re   r
  r   r   rJ   rH   <module>r     s   *! ! ! ! ! ! ! ! ! ! ! ! ! ! !P
=	C 0@PT DN
rJ   