
    j<                        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 dZdZdZdZdZdZd	Zd
ZdZdZdZdZdZdZeeeeeee	ee
eeeiZ eeeeeh      Z eeeeeeh      ZddZd Z d Z!d Z"d Z#d Z$d Z%d Z&dddZ'd Z(y)u  Merge-ready DRY-RUN executor (Track B · read-only · evidence-only · merge 실행 0).

merge_ready_classifier 의 output dict 와 PR identity 를 입력받아 verdict 별 routing
artifact 를 결정적으로 생성한다. **본 task = dry-run 까지만** — 실 merge/push/PR/cron
발사 0 · GitHub write 0 · branch protection 우회 0 · admin override 자동화 0.

doctrines (spec system_merge_ready_executor_dryrun_spec_260522.md):
- evidence-only decoupled: anu_v3/런타임 import 0 · classifier 수정 0(입력 소비만)
- pure function · read-only · 파일/네트워크/subprocess/live-git/merge I/O 0 · no daemon
- 모든 artifact 에 actually_executed=false 강제 · 모든 executor_action 에 WOULD_* 접두사 강제
- verdict → routing (spec §1):
    PASS            → merge_ready.auto_merge_candidate.v1 (executor_action=WOULD_MERGE)
    HOLD            → merge_ready.remediation_required.v1 (executor_action=WOULD_AUTO_REMEDIATE)
    CHAIR_REQUIRED  → merge_ready.hold_for_chair.v1       (executor_action=WOULD_ESCALATE_CHAIR)
    UNKNOWN         → merge_ready.hold_for_chair.v1       (executor_action=WOULD_REGATHER,
                                                            reason=INSUFFICIENT_EVIDENCE)
- 보수적 추정 금지: classifier 가 UNKNOWN 이면 routing 도 REGATHER (재수집).
- 결정적 idempotency: 동일 입력 2회 호출 → byte-identical 출력 (ts_kst 도 caller 가 공급).

본 모듈은 데이터-only 다. merge/push/PR/cron/branch-protection/admin-override 호출 경로
자체가 부재하다 (코드 경로 0 = 안전 불변식의 가장 강한 보증).

단일소스 스펙: memory/specs/system_merge_ready_executor_dryrun_spec_260522.md
    )PASSHOLDCHAIR_REQUIREDUNKNOWN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_ORDERz#merge_ready.auto_merge_candidate.v1z#merge_ready.remediation_required.v1zmerge_ready.hold_for_chair.v1WOULD_MERGEWOULD_AUTO_REMEDIATEWOULD_ESCALATE_CHAIRWOULD_REGATHERWOULD_WAIT_RECHECKWOULD_OWNER_GEMINI_REVIEW_NUDGE+WOULD_AUTO_FIX_REGRESS_PUSH_RESOLVE_RECHECKWOULD_RESOLVE_THREAD_RECHECKINSUFFICIENT_EVIDENCEuG   같은 함수 HIGH 반복/scope 확장 조짐 → CHAIR_REQUIRED 승격"WOULD_RECLASSIFY_AFTER_REMEDIATIONc                 H    	 t        |       S # t        t        f$ r |cY S w xY w)u`   안전 int 변환 (classifier 입력 견고성 doctrine 동형). pr 번호 등 비숫자 폴백.)int	TypeError
ValueError)valuedefaults     8/home/jay/workspace/utils/merge_ready_dryrun_executor.py_as_intr   _   s*    5zz" s   
 !!c                     | xs i }t        |j                  d      d      t        |j                  d      xs d      t        |j                  d      xs d      t        |j                  d      xs d      dS )u[   pr_identity dict → 정규화된 dict({pr, head_sha, task_id, branch}). None-guard 포함.prr   head_sha task_idbranch)r!   r"   r$   r%   )r   getstrpr_identitypis     r   	_identityr+   g   sj    		BbffTlA&z*0b1rvvi(.B/bffX&,"-	     c                 J    | xs i }t        |j                  d      xs d      S )u   ts_kst 는 caller(=collector/wiring) 가 공급 — 결정적 idempotency 보장.
    None/누락 → 빈 문자열(스키마 형식 유지).ts_kstr#   )r'   r&   r(   s     r   _ts_kstr/   r   s'     
	Brvvh%2&&r,   c                     | xs i }|j                  d      xs i }t        |j                  dd            t        |j                  dd            t        |j                  d      xs d      dS )u  post_merge_smoke_plan 은 collector 가 사전 수집해 pr_identity 로 전달.
    기본값(defined=True/runnable=True/cmd_ref="") — auto_merge_candidate 생성 시점에
    smoke 가 정의/실행가능하다는 가정은 회장 executor 활성화 단계에서 재검증된다.post_merge_smoke_plandefinedTrunnablecmd_refr#   )r2   r3   r4   )r&   boolr'   )r)   r*   sps      r   _smoke_planr7   y   sh     
	B	'	(	.BBy$/0
D12rvvi(.B/ r,   c                 r    | xs i }|j                  d      xs i }dt        |j                  dd            iS )u   callback_lifecycle_artifact_plan — collector 가 lifecycle artifact 생성 가능성을
    사전 통지. 기본 would_generate=True (정상 closeout 경로 가정). callback_lifecycle_artifact_planwould_generateT)r&   r5   )r)   r*   cps      r   _callback_planr<      s>     
	B	2	3	9rBd266*:D#ABCCr,   c                 N   | j                  d      durt        d| j                  d      d      | j                  d      }t        |t              r|j	                  d      st        d|d      | j                  d      }|t
        t        t        fvrt        d	|      | S )
u3  artifact 가 안전 불변식을 만족하는지 자체검증.
    위반 시 ValueError(설계 버그 신호) — 정상 입력에서는 절대 발생하지 않아야 한다.

    불변식:
    - actually_executed === False
    - executor_action 은 WOULD_* 접두사
    - schema 는 3종 중 하나
    actually_executedFz@safety invariant violated: actually_executed must be False (got )executor_actionWOULD_zIsafety invariant violated: executor_action must start with 'WOULD_' (got schemaz*safety invariant violated: unknown schema )r&   r   
isinstancer'   
startswithSCHEMA_AUTO_MERGE_CANDIDATESCHEMA_REMEDIATION_REQUIREDSCHEMA_HOLD_FOR_CHAIR)artifactactionrB   s      r   _assert_safety_invariantsrJ      s     ||'(5LL!458;
 	
 \\+,Ffc"&*;*;H*EWX^Waabc
 	
 \\(#F13NPeffEfZPQQOr,   c                     t        | j                  d      xs i       }t        |d   |d   |d   |d   t        |t	        |      t
        ddt        |      |d}t        |      S )	u:   PASS → merge_ready.auto_merge_candidate.v1 (spec §2.1).auto_merge_10_conditionsr!   r"   r$   r%   FT)rB   r!   r"   r$   r%   verdictrL   r1   r@   r>   requires_chair_activationr9   r.   )dictr&   rE   r   r7   ACTION_WOULD_MERGEr<   rJ   )resultidentr)   r.   
conditionsrH   s         r   _build_auto_merge_candidaterT      sr    fjj!;<BCJ-Dk*%#/$.!,[!9-"%),:;,GH %X..r,   c                    t        | j                  d      xs g       }t        D cg c]	  }||v s| }}t        d |D              }|j	                  |       |D cg c]  }|t
        j                  |t              d! }}t        |d   |d   |d   |d   t        ||t        t        t        d|d	}	t        |	      S c c}w c c}w )
u:   HOLD → merge_ready.remediation_required.v1 (spec §2.2).auto_remediablec              3   2   K   | ]  }|t         vs|  y w)N)r   ).0as     r   	<genexpr>z._build_remediation_required.<locals>.<genexpr>   s     TAQ>S5SaTs   )itemrI   r!   r"   r$   r%   F)rB   r!   r"   r$   r%   rM   rV   remediation_planloop_boundary_guardnext_recheckr@   r>   r.   )setr&   r   sortedextendAUTO_REMEDIABLE_ACTION_MAPACTION_WOULD_WAIT_RECHECKrF   r   LOOP_BOUNDARY_GUARD_TEXTNEXT_RECHECK_ACTIONACTION_WOULD_AUTO_REMEDIATErJ   )
rQ   rR   r.   auto_rem_src_setrY   auto_remleftoverr[   r\   rH   s
             r   _build_remediation_requiredrj      s     6::&78>B?0JaA9I4IJHJT!1TTHOOH  !;!?!?F_!`a  .Dk*%#/#,7+6"H %X..3 K
s   	B?B?$CN)reasonc                P   t        | j                  d      xs g       }t        | j                  d      xs g       }t        | j                  d      xs g       }|r|d   }	n|t        k(  rd}	nd}	|	|g d}
t        |d   |d	   |d
   |d   |||
||d|d}|r||d<   t	        |      S )uT  CHAIR_REQUIRED/UNKNOWN → merge_ready.hold_for_chair.v1 (spec §2.3).

    Args:
        verdict: CHAIR_REQUIRED 또는 UNKNOWN — classifier 값 그대로 보존(추정 0).
        executor_action: WOULD_ESCALATE_CHAIR (CHAIR_REQUIRED) | WOULD_REGATHER (UNKNOWN).
        reason: UNKNOWN 시 INSUFFICIENT_EVIDENCE 표식 (spec §1).
    chair_triggersblocking_reasonscritical7_hitsr   uF   core gate evidence(scope/gates) 결핍 → 재수집 필요 (추정 0)r#   )one_lineevidence_refsrecommended_optionsr!   r"   r$   r%   F)rB   r!   r"   r$   r%   rM   rm   report_envelopern   r@   r>   r.   rk   )listr&   REASON_INSUFFICIENT_EVIDENCErG   rJ   )rQ   rR   r.   rM   r@   rk   rm   rn   ro   rp   rs   rH   s               r   _build_hold_for_chairrv      s     &**%56<"=NFJJ'9:@bA&**%56<"=N#A&	/	/[ '!O (Dk*%#/(*,*"H #$X..r,   c                 ~   | xs i }|j                  d      }t        |      }t        |      }|t        k(  rt	        ||||      S |t
        k(  rt        |||      S |t        k(  rt        |||t        t              S |t        k(  rt        |||t        t        t              S t        |||t        t        t              S )u  classifier 결과 → verdict 별 routing artifact dict (spec §1).

    Args:
        merge_ready_result: utils.merge_ready_classifier.classify_merge_ready(...) 반환 dict.
                            verdict/chair_triggers/auto_remediable/critical7_hits/
                            auto_merge_10_conditions/blocking_reasons/credential_tier 사용.
        pr_identity: {pr, head_sha, task_id, branch, ts_kst,
                      post_merge_smoke_plan?, callback_lifecycle_artifact_plan?}
                     ts_kst 는 caller 가 결정적으로 공급(idempotency).

    Returns:
        dict: 3종 routing artifact 중 verdict 에 맞는 1종.
              모든 artifact 는 actually_executed=False · executor_action ∈ {WOULD_*}.

    Safety invariants (코드 경로 부재로 자동 보장):
        - merge/push/PR/cron/branch-protection/admin-override 호출 0
        - GitHub write 0 · 파일 쓰기 0 · subprocess 0 · network 0
        - classifier 수정 0 (입력 dict 만 read-only 소비)
    rM   )rM   r@   )rM   r@   rk   )r&   r+   r/   r   rT   r   rj   r   rv   ACTION_WOULD_ESCALATE_CHAIRr   ACTION_WOULD_REGATHERru   )merge_ready_resultr)   rQ   rM   rR   tss         r   dryrun_router|     s    (  %2Fjj#Gk"E		B$*65+rJJ$*65"==. $E2"7
 	

 '$E21/	
 	
 !r-+	 r,   )r   ))__doc__utils.merge_ready_statesr   r   r   r   r   r   r	   r
   r   r   r   rE   rF   rG   rP   rf   rx   ry   rc   &ACTION_WOULD_OWNER_GEMINI_REVIEW_NUDGE2ACTION_WOULD_AUTO_FIX_REGRESS_PUSH_RESOLVE_RECHECK#ACTION_WOULD_RESOLVE_THREAD_RECHECKru   rd   re   rb   	frozensetALL_EXECUTOR_ACTIONSALL_SUB_ACTIONSr   r+   r/   r7   r<   rJ   rT   rj   rv   r|    r,   r   <module>r      s(  0    D C 7 
 # 4 4 (  1 )J &5b 2&D #  7  e  ;  ,D$&X.0b!D$&?  !	"   *6' '
D:/*/D VZ )/`1r,   