
     jS                    
   U 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m	Z	 ddl
mZ ddlmZmZmZ ddlmZmZmZ ddlmZ g d	Z eh d
      Zded<   dZded<   ed   Z ed       G d d             Z G d dee      Z ed       G d d             Z ed       G d d             Z dOdZ!dPdZ"dd	 	 	 	 	 	 	 	 	 dQd!Z#dRd"Z$ ed       G d# d$             Z%dd%	 	 	 	 	 dSd&Z&dd	 	 	 	 	 dTd'Z'dUd)Z(	 dVdd	 	 	 	 	 	 	 	 	 dWd*Z)	 	 	 	 	 	 dXd+Z*	 	 	 	 	 	 dYd,Z+	 	 	 	 	 	 	 	 dZd-Z,d[d.Z-	 	 	 	 	 	 	 	 d\d/Z.dd	 	 	 d]d0Z/dd	 	 	 	 	 d^d1Z0d_d2Z1d`d3Z2dad4Z3e4d5k(  r e1       Z5e5jm                         Z7ded<   ded <   e7jp                  r&e7jr                  re7jp                  e7jr                  cZ8Z9n: e/       \  Z8Z9e7jp                  re7jp                  Z8e7jr                  re7jr                  Z9e7jR                  r	  e)e8e9e7jt                        Z;e7j                  r e2e;      ZB	 ddlCZDd9ZE	  e&g d:d%      ZFeFj                  dk(  reFj                  j                         ZE eDj                  d;eE      ZKeKreKj                  d      nd<ZM eeMd=>      ZNeNj                  eNj                  d?eBd@<    e> ej                  eBdAB             n+ e2e;      j                         D ]  \  ZSZT e>eS dCeT          ej                  d       e7j                  	  e)e8e9e7jt                        Z; e0e7j                        ZV e+eVe;      ZW e,eVe;eW      ZXe7j                  r~e7j                  eWeWj                  nddDZ[e7j                  r e> ej                  e[dAB             n(eWeWj                  ndEZ\ e>dFe7j                   dGe\         ej                  d       e7j                   e2e;      eWeWj                  nd e3eX      dHZ]e7j                  r e> ej                  e]dAB             n e>dIe7j                           e>dJeWreWj                  nd(         e>dKeXj                           e>dLeXj                           e>dMeXj                           e>dNeXj                           ej                  d       e5j                           ej                  d       yy# e<$ r4Z= e>d6e= ej~                  7        ej                  d8       Y dZ=[=dZ=[=ww xY w# e<$ r Y w xY w# e<$ r	 deBd@<   Y w xY w# e<$ r4Z= e>d6e= ej~                  7        ej                  d8       Y dZ=[=!dZ=[=ww xY w)buv  utils/repository_policy_adapter.py — GitHub repository policy → runtime capability layer.

회장 §명시: GitHub repository ruleset / branch protection / merge capability를
runtime capability layer로 표준화. admin override 없이 deterministic merge path 선택.
"회장 직접 머지 fallback" 완전 제거.

회장 §명시 11개 금지 행위:
  1.  admin override 호출 (--admin flag 정적 차단)
  2.  branch protection 우회 코드
  3.  canonical_workspace_resolver 수정
  4.  automation_contracts 수정
  5.  merge_queue_executor 본체 수정
  6.  replacement_pr_runner 본체 수정
  7.  auto_gemini_triage 본체 수정
  8.  post_merge_smoke_runner 본체 수정
  9.  critical_escalation_reporter 본체 수정
  10. expected_files 외 파일 수정
  11. AUTOMATION_CAPABILITY_GAP을 CriticalEscalationType에 추가 (Critical 7종 외 보고 금지)
    )annotationsN)	dataclassreplace)Enum)AnyCallableOptional)CriticalEscalationTypeEscalationPacket	RiskLevel)resolve_canonical_workspace)RepositoryCapabilityBlockedReasonMergePathPlanBotMergeIdentityMergeIdentityRecordprobe_capabilityclassify_blocked_reasonselect_merge_pathassert_no_admin_overrideinvoke_triage_hookprobe_bot_merge_identityclassify_capability_gapinfer_token_source_from_actor*reevaluate_bot_can_merge_with_token_sourcer
   r   r   r   build_capability_gap_packet>   jeon-jonghyukJonghyukJeonjonghyukjeonJeon-Jonghyukzfrozenset[str]_OWNER_LOGINS)z[bot]ztuple[str, ...]_BOT_LOGIN_SUFFIXES).z subprocess.CompletedProcess[str]T)frozenc                  N    e Zd ZU dZded<   ded<   ded<   ded<   ded<   ded<   y	)
r   u   GitHub repository의 머지 관련 capability snapshot.

    모든 필드는 probe 시점에 고정(frozen). admin override 없이 deterministic.
    boolcan_squash_mergerequires_approvalrequires_thread_resolutionauto_merge_enabledbot_can_mergeadmin_override_requiredN__name__
__module____qualname____doc____annotations__     6/home/jay/workspace/utils/repository_policy_adapter.pyr   r   Y   s-    
  $$!!r3   r   c                  0    e Zd ZdZdZdZdZdZdZdZ	dZ
d	Zy
)r   u]   PR 머지 차단 이유. 기존 7종 + task-2521 §1 신규 1종 (AUTOMATION_CAPABILITY_GAP).UNRESOLVED_REVIEW_THREADREQUIRED_APPROVAL
STALE_BASEMISSING_CI_CHECKBRANCH_PROTECTIONPERMISSION_ISSUEAUTO_MERGE_UNSUPPORTEDAUTOMATION_CAPABILITY_GAPN)r-   r.   r/   r0   r6   r7   r8   r9   r:   r;   r<   r=   r2   r3   r4   r   r   l   s6    g9+J)+)5 !<r3   r   c                  N    e Zd ZU dZded<   ded<   ded<   ded<   ded	<   ded
<   y)r   um   Single PR mergedBy/mergeCommit 분석 record.

    task-2521 §1 fixture replay 대상 (PR #69/#70/#71).
    int	pr_numberstrmerged_by_loginmerged_by_typer%   is_botinferred_token_sourcefallback_to_owner_tokenNr,   r2   r3   r4   r   r      s+    
 NL!!r3   r   c                  R    e Zd ZU dZded<   ded<   ded<   ded<   ded<   d	Zd
ed<   y)r   u   6 field probe 결과 (회장 §1 명시).

    bot/app identity로 merge가 가능한지 + owner token fallback이 발생했는지를
    deterministic 박제. CriticalEscalationType에 새 enum 추가 금지 (회장 §금지).
    r%   bot_can_merge_as_apprA   merge_actor_loginmerge_actor_is_bottoken_source fallback_to_owner_token_detectedr2   ztuple[MergeIdentityRecord, ...]merge_identity_auditN)r-   r.   r/   r0   r1   rM   r2   r3   r4   r   r      s3     &**<>9>r3   r   rA   c                    | sy| j                         t        fdt        D              ry| t        v s$t        D ch c]  }|j                          c}v rydv r|xs dj                         dk(  ryyc c}w )	u  merge actor login + type → token_source 추론 (deterministic).

    Returns:
      "installation_app" — login.endswith("[bot]") AND actor_type == "Bot"
      "owner_pat"        — login ∈ _OWNER_LOGINS (회장 토큰 fallback 신호)
      "bot_pat"          — actor_type == "User" 인데 login에 "bot" 포함 (휴리스틱)
      "unknown"          — 그 외 (데이터 없음 / 신원 미상)
    unknownc              3  @   K   | ]  }j                  |        y wN)endswith).0suffixlowers     r4   	<genexpr>z0infer_token_source_from_actor.<locals>.<genexpr>   s     
Df5>>&!
Ds   installation_app	owner_patbot userbot_pat)rU   anyr"   r!   )login
actor_typexrU   s      @r4   r   r      ss     KKME

D0C
DD!m*L1779*L!L~:+224>	 +Ms   A8c                   t        | j                  dd      xs d      }| j                  d      xs i }t        |t              si }t	        |j                  d      xs d      }t	        |j                  d      xs |j                  d      xs d      }t        |j                  d      xs d	      }t        ||      }|xs |d
v xs |xs dj                         dk(  }|dk(  }t        ||||||      S )uD   단일 PR JSON에서 mergedBy 필드 추출 → MergeIdentityRecord.numberr   mergedByr^   rZ   type
__typenameisBotF>   r\   rW   rY   rX   )r@   rB   rC   rD   rE   rF   )	r?   get
isinstancedictrA   r%   r   rU   r   )	prr@   	merged_byr^   r_   is_bot_fieldinferredrD   fallbacks	            r4   _analyze_merge_recordro      s    BFF8Q',1-Iz"(bIi&		g&,"-EY]]6*OimmL.IORPJ	g.7%8L,UJ?H 	/66	/"##%. 
 ;&H!& ( r3   runnerownerrepoc          
     \   ||nt         }g }d}| r	|r|  d| nd}|D ]  }	 dddt        |      ddg}	|r|	j                  d	|g        ||	d
      }
|
j                  dk7  s|
j                  j                         s^	 t        j                  |
j                        }t        |t               st#        |      }|j%                  |       |j&                  s|} t)        d |D              }t)        d |D              }|r|j&                  nd}|r|j*                  nd}|r|j,                  nd}t/        |||||t1        |            S # t        $ r@}t	        d| dt        |      j                   dt        j                         Y d}~nd}~ww xY w# t        j                  $ r Y w xY w)u  task-2521 §1 — last N PRs의 mergedBy를 조회해 BotMergeIdentity 박제.

    각 PR에 대해 ``gh pr view <N> --json number,mergedBy`` 호출. 조회 실패 시
    해당 PR은 빈 record로 남기고 다음 PR 진행. silent fallback이지만 stderr trace.

    bot_can_merge_as_app 판정 규칙:
      - samples 중 1건 이상이 inferred_token_source == "installation_app" → True
      - 그 외 False (deterministic; "회장 직접 머지 fallback = 자동화 성공 X" 박제)
    N/rZ   ghrj   view--jsonznumber,mergedBy--repocwdz([repository_policy_adapter] gh pr view #z	 failed (u
   ) — skipfiler   c              3  :   K   | ]  }|j                   d k(    yw)rW   N)rE   rS   rs     r4   rV   z+probe_bot_merge_identity.<locals>.<genexpr>   s!      :;#55s   c              3  4   K   | ]  }|j                     y wrQ   )rF   r   s     r4   rV   z+probe_bot_merge_identity.<locals>.<genexpr>  s     G!A55Gs   FrO   )rH   rI   rJ   rK   rL   rM   )_default_runnerrA   extend	Exceptionprintrd   r-   sysstderr
returncodestdoutstripjsonloadsJSONDecodeErrorrh   ri   ro   appendrB   r]   rD   rE   r   tuple)rr   rs   
pr_numbersrq   fnrecordslast_recordrepo_argnargsresultexc
pr_payloadrecrH   fallback_detectedactor_loginactor_is_botrK   s                      r4   r   r      s     %?B)+G15K$)d%$ H 	$A:KLDXx01$'F !)<)<)>	FMM2J *d+#J/sK14  ?F  GwGG1<+--"K)4;%%%L8C;44L1%'!):"7^ ;  	:1# >I&&'z3ZZ
 	 ## 		s)   0E=F	F5FFF+*F+c                t    | j                   rt        j                  S | j                  st        j                  S y)u  BotMergeIdentity → AUTOMATION_CAPABILITY_GAP 분류.

    회장 §1 정책:
      - bot/app identity로 merge 가능 → None (정상)
      - 회장 토큰(owner_pat) 사용이 1건이라도 탐지 → AUTOMATION_CAPABILITY_GAP
      - bot_can_merge_as_app=False & fallback도 없음 → AUTOMATION_CAPABILITY_GAP
        (samples 부재 시 보수적으로 GAP 분류; "자동화 성공 = bot/app driven only")
    N)rL   r   r=   rH   )identitys    r4   r   r     s1     00666((666r3   c                  X    e Zd ZU dZded<   ded<   ded<   ded<   d	ed
<   d	ed<   ded<   y)r   u  Deterministic merge path 선택 결과.

    회장 §명시: admin override 없이 선택된 경로만 허용.
    capability_gap=True 시 CriticalEscalationType에 추가하지 않고
    ops 채널 보고 마커로만 사용 (Critical 7종 외 회장 보고 0건).
    rA   actionOptional[BlockedReason]reasonr%   requires_chaircapability_gapOptional[str]triage_hookbase_sync_commanddescriptionNr,   r2   r3   r4   r   r   #  s4     K $#$$r3   r   rz   c               6    t        j                  | |ddd      S )NT   )r{   capture_outputtexttimeout)
subprocessrun)r   r{   s     r4   r   r   <  s$    
 >> r3   c                  t        |        ||nt        }	  || d      }|j                  d	k7  ry|j                  j                         sy	 t        j                  |j                        }t        |t        t         f      r|S dS # t        $ rQ}t        dt	        |      j
                   ddj                  | dd        dt        j                         Y d}~yd}~ww xY w# t        j"                  $ rG}t        d
dj                  | dd        d|j$                   t        j                         Y d}~yd}~ww xY w)u   gh api 호출 후 JSON dict 반환. 실패 시 None (safe fallback).

    예외 발생 시 stderr에 짧은 trace 기록 후 None 반환 — silent fallback이지만
    디버깅 가능하도록 원인을 남긴다 (Gemini high 권고 수용).
    Nrz   z,[repository_policy_adapter] gh call failed (z):     u   ... → fallback Noner|   r   z2[repository_policy_adapter] JSON parse failed for : )r   r   r   r   rd   r-   joinr   r   r   r   r   r   r   rh   ri   listr   msg)r   rq   r   r   r   parseds         r4   _run_ghr   J  s'    T"%?B	Dd# A== 	FMM*#FT4L9vCtC#  :49;M;M:NcxxRa!""79	

 $  @xxRa!""SWWI/	

 s6   
B 6C# C# 	C ACC #D=6=D88D=Nonec                >    t        d | D              rt        d      y)u   gh 호출 args에 --admin 포함 시 RuntimeError. 어디서든 gh 호출 전에 호출.

    회장 §명시: admin override는 항상 금지.
    c              3  &   K   | ]	  }|d k(    yw)z--adminNr2   rS   as     r4   rV   z+assert_no_admin_override.<locals>.<genexpr>|  s     
(a1	>
(s   uh   admin override is forbidden by repository_policy_adapter (회장 §명시: admin override 항상 금지)N)r]   RuntimeError)r   s    r4   r   r   w  s)    
 
(4
((>
 	
 )r3   c                  d}d}d}t        ddd|  d| d| g|      }|g }t        |t              r|}n"t        |t              r|j	                  d	g       }|D ]  }	|	j	                  d
d      }
|	j	                  di       xs i }|
dk(  r]|j	                  dd      xs d}|dkD  rd}|j	                  dd      rd}|	j	                  dg       xs g }|rt        d |D              rd}|
dk(  sd} t        ddd|  d| d| dg|      }|t        |t              r|j	                  di       xs i }|rU|j	                  dd      xs d}|dkD  rd}|j	                  dd      rd}|j	                  di       j	                  dd      rd}|j	                  dd      }|d}d}d}t        ddd|  d| g|      }|Ft        |t              r6t        |j	                  dd            }t        |j	                  dd            }d}t        ddd|  d| dg|      }|,t        |t              r|j	                  dd      xs d}|dv rd}t        ||||||       S )!u   GitHub API 4회 호출로 RepositoryCapability 6 field를 probe.

    각 호출은 실패 허용 — fallback False 처리.
    runner: subprocess.run 주입 가능 (테스트 stubbing).
    Frv   apizrepos/ru   z/rules/branches/rp   Nrulesrd   rZ   
parameterspull_requestrequired_approving_review_countr   T!required_review_thread_resolutionbypass_actorsc              3     K   | ]@  }t        |t              r.|j                  d d      dk(  xr |j                  dd      dk(   B yw)r_   rZ   RepositoryRole	role_nameadminNrh   ri   rg   r   s     r4   rV   z#probe_capability.<locals>.<genexpr>  sR      ) !!T* UU<,0@@ ;{B/7:;)s   AArestrictionsz
/branches/z/protectionrequired_pull_request_reviewsrequire_code_owner_reviews required_conversation_resolutionenabledallow_squash_mergeallow_auto_mergez-/collaborators/github-actions[bot]/permission
permission)writer   r&   r'   r(   r)   r*   r+   )r   rh   r   ri   rg   allr%   r   )rr   rs   branchrq   r(   r'   r+   ruleset_datar   rulertypeparamscountr   protection_dataprcr   r&   r)   	repo_datar*   	perm_dataperms                          r4   r   r     s     "'#	uugQtf,<VHEFL lD) Ed+ $$Wb1E 	/DHHVR(EXXlB/52F&

#DaHMA19(,%::A5I15. $" = C S ) +) & /3+&*.'+	/4 	uugQtfJvhkJKO "z/4'H!!"A2FL"GG=qAFQEqy$(!ww3U;$(!""#ErJNNyZ_`-1*&**>4@#&*#
 	uugQtf-.I It!<	.BE JK!)--0BE"JK
 M	u%$L	M	OI
 It!<}}\2.4"%% M)+#=-# 7 r3   c                   |xs dj                         j                         }|dv r| j                  s| S t        | d      S | S )u  probe_capability()의 결과를 실제 사용된 token source 기준으로 재평가.

    task-2522 §본질:
      현재 probe_capability()는 ``gh api`` 호출을 통해 capability를 추출하지만,
      이 호출에 사용된 token이 owner_pat이면 결과는 "owner_pat이 본 capability"
      에 가깝다. 실제 자동화 머지에 사용될 GitHub App installation token이 보유한
      capability를 박제하려면, token source가 OWNER_PAT/UNKNOWN인 경우
      ``bot_can_merge=False``로 strict 재평가해야 한다 (자동화 fallback 차단).

    재평가 규칙 (deterministic, 좁은 보강):
      - token_source == "GITHUB_APP_INSTALLATION_TOKEN" → 그대로 유지 (정상 자동화).
      - token_source == "GITHUB_ACTIONS_TOKEN" → 그대로 유지 (Actions runner 자동화).
      - token_source == "OWNER_PAT" → bot_can_merge=False로 강제 (회장 §본질).
      - token_source == "UNKNOWN" → bot_can_merge=False로 강제 (fail-closed).
      - 기타 (분류 외 값) → 그대로 유지 (보수적; 알 수 없는 enum value는 변경 안 함).

    회장 §금지: 새 abstraction 생성 X. RepositoryCapability dataclass 그대로 사용,
    좁은 함수 1개만 추가. 기존 6 field 변경 X.
    rZ   >   UNKNOWN	OWNER_PATF)r*   )r   upperr*   r   )
capabilityrK   srcs      r4   r   r     sK    0 2
$
$
&
,
,
.C
&&''z77r3   c                   d}| j                  dd      }t        |t              rt        d |D              }n]t        |t              r)|j                  dg       xs g }t        d |D              }n$| j                  dd      }t        |t
              r|}| j                  dd	      xs d	}| j                  d
d	      xs d	}| j                  dd      }d	}	t        |t              r|j                  dd	      xs d	}	nt        |t              r|}	|j                  r|dkD  rt        j                  S |dk(  rt        j                  S |j                  r|dk7  rt        j                  S |	dv rt        j                  S |j                  st        j                  S |j                   st        j"                  S |dk(  rt        j$                  S y)u>  PR dict + RepositoryCapability → BlockedReason | None.

    우선순위 순차 체크 (회장 §명시 순서 고정):
      1. UNRESOLVED_REVIEW_THREAD
      2. STALE_BASE
      3. REQUIRED_APPROVAL
      4. MISSING_CI_CHECK
      5. PERMISSION_ISSUE
      6. AUTO_MERGE_UNSUPPORTED
      7. BRANCH_PROTECTION
    r   reviewThreadsNc              3  d   K   | ](  }t        |t              r|j                  d d      sd * yw
isResolvedT   Nr   rS   ts     r4   rV   z*classify_blocked_reason.<locals>.<genexpr>8  /      &
!T"155t+D &
   .0nodesc              3  d   K   | ](  }t        |t              r|j                  d d      sd * ywr   r   r   s     r4   rV   z*classify_blocked_reason.<locals>.<genexpr>?  r   r   unresolved_thread_countmergeStateStatusrZ   reviewDecisionstatusCheckRollupstateBEHINDAPPROVED)PENDINGEXPECTEDFAILUREBLOCKED)rg   rh   r   sumri   r?   rA   r(   r   r6   r8   r'   r7   r9   r*   r;   r)   r<   r:   )
rj   r   r   raw_threadsr   direct_countmerge_statereview_decisionrollupci_states
             r4   r   r   "  s   $ $%&&$/K+t$"% &
"&
 #
 
K	&,2"% &
&
 #
 vv7;lC(&2#vv0"5;K66"2B7=2O VV'.FH&$::gr*0b	FC	 
 ,,1H11L555
 h'''
 ##:(E...
 55---
 ##---
 ((333
 i... r3   c                   | j                  dd      }|j                  }|j                  }|t        ddddddd| d| d	      S |t        j
                  k(  rt        d
|ddddd| d	      S |t        j                  k(  rt        d|ddddd| d	      S |t        j                  t        j                  t        j                  t        j                  fv r)t        d|ddddd| d|j                   d| d| d		      S |t        j                  k(  rt        d|ddddd| d	      S t        d|ddddd| d	      S )u   BlockedReason → deterministic MergePathPlan 선택.

    회장 §명시: admin override 없이 deterministic. "회장 직접 머지 fallback" 없음.
    AUTOMATION_CAPABILITY_GAP은 ops 채널만 (requires_chair=False).
    rb   ?Nsquash_mergeFzPR #uE   : 정상 squash merge path. 모든 capability 충족. (bot_can_merge=)r   r   r   r   r   r   r   auto_gemini_triageauto_gemini_triage.triage_pruW   : Unresolved review thread 존재. auto_gemini_triage hook으로 자동 분류/resolve.	base_synczgit merge origin/mainuR   : Base branch가 stale. git merge origin/main으로 동기화. (force push 금지)escalate_capability_gapTu   : Capability gap 감지: z. requires_approval=z, bot_can_merge=uS   . 자동화 불가 — ops 채널로 보고. (회장 직접 머지 fallback 없음)wait_ciu/   : CI 체크 미완료/실패. CI 통과 대기.manual_merge_requireduG   : Repo auto_merge 비활성화. manual merge 필요. ops 채널 보고.)rg   r*   r'   r   r   r6   r8   r7   r:   r;   r=   valuer9   )rj   r   blocked_reasonpr_numbot_mergeableneeds_approvals         r4   r   r     s    x-F$22M%77N!  "vh ""/3
 	
 ???'!  6"vh G G
 	
 111!  5vh M M
 	
 ''''&&//	  ,! "vh78L8L7M N%%3$44D]O Tdd
 	
 777!  "vh&UV
 	
 *! "vh : :
 	
r3   c                    ddl m} d| |dS )u  auto_gemini_triage 연동 hook. 실제 wiring은 후속 task.

    본 task에서는 인터페이스만 정의. 호출 시 lazy import로 circular 방지.
    실제로 triage_pr을 호출하지 않고 callable만 반환 (테스트에서 인터페이스 검증).
    r   )	triage_prr  )hookr@   callable)utils.auto_gemini_triager  )r@   r  s     r4   r   r     s     3. r3   c                `   | j                   sy| j                  rt        j                  nt        j                  }t        ||t        j                  | j                  d| j                   d| j                  r| j                  j                  nd ddgd|j                  | j                  d      S )	u  capability_gap=True인 MergePathPlan을 EscalationPacket으로 변환.

    회장 §명시: AUTOMATION_CAPABILITY_GAP은 CriticalEscalationType 7종 외이므로
    Critical 보고 대상이 아님. 가장 가까운 기존 타입 사용 (ops 채널 marker만).
    RiskLevel은 plan.requires_chair 기반으로 결정 (HIGH vs MEDIUM).

    Returns:
        EscalationPacket (ops 채널용) or None (capability_gap=False인 경우)
    Nzcapability_gap=True: action=z, blocked_reason=r   ops_channel_reportmanual_merge_review)
risk_levelr   )task_idr@   escalation_typer   why_auto_cannot_continuesafe_optionsrecommended_optionevidence)r   r   r   HIGHMEDIUMr   r
   .BLOCK_OVERRIDE_REQUIRED_OR_REASON_INSUFFICIENTr   r   r   r  )planr@   r   risks       r4   r   r     s     !009>>i6F6FD.]]*4;;- 837;;dkk//FKM +,AB/ $

dkkB r3   c                   | | nt         }	  |g dd      }|j                  dk(  rT|j                  j                         }ddl}|j                  d|      }|r"|j                  d      |j                  d      fS y# t        $ r Y yw xY w)	uO   git remote get-url origin에서 owner/repo 추출. 실패 시 기본값 반환.N)gitremotezget-urloriginrz   r   z[:/]([^/]+)/([^/]+?)(?:\.git)?$r      )r    dev_workspace)r   r   r   r   researchgroupr   )rq   r   r   urlr1  ms         r4   _extract_owner_repo_from_remoter6  (  s    
 %?B:E!--%%'C 		<cBAwwqz1771:-- ,  +s   A.A< <	BBc                   ||nt         }	  |dddt        |       ddgd      }|j                  dk(  r9|j                  j	                         rt        j                  |j                        S i S # t        $ r Y i S w xY w)	u   gh pr view로 PR 정보 조회.Nrv   rj   rw   rx   z?mergeStateStatus,reviewThreads,reviewDecision,statusCheckRolluprz   r   )r   rA   r   r   r   r   r   r   )r@   rq   r   r   s       r4   _fetch_pr_infor8  =  s     %?BdFC	NQ
 
 !fmm&9&9&;::fmm,, I  Is   A A/ /	A<;A<c                 x   t        j                  dt         j                  d      } | j                  ddd       | j                  dd d	
       | j                  dd d
       | j                  ddd
       | j                  dt        dd d       | j                  ddd       | j                  dddd       | S )Nu   repository_policy_adapter — GitHub repository capability probe & deterministic merge path selector. (회장 §명시: admin override 항상 금지)u  
Examples:
  # capability probe (JSON 출력)
  python3 utils/repository_policy_adapter.py --probe-capability --owner Jeon-Jonghyuk --repo dev_workspace --branch main --json

  # PR 분석 (probe + classify + select_merge_path)
  python3 utils/repository_policy_adapter.py --pr 42 --json

  # PR 차단 이유만 분류
  python3 utils/repository_policy_adapter.py --pr 42 --classify-blocked

금지 사항 (회장 §명시):
  - admin override (--admin flag 정적 차단)
  - branch protection 우회 코드
  - canonical_workspace_resolver / automation_contracts 수정
  - 5 모듈 본체 수정
  - expected_files 외 파일 수정
  - AUTOMATION_CAPABILITY_GAP을 CriticalEscalationType에 추가
        )r   formatter_classepilogz--probe-capability
store_trueu+   Repository capability를 probe하여 출력)r   helpz--owneru0   GitHub owner (미지정 시 remote에서 추출))defaultr=  ry   u/   GitHub repo (미지정 시 remote에서 추출)z--branchmainu   대상 branch (기본: main)z--prNu6   PR 번호. probe + classify + select_merge_path 실행)rd   metavarr>  r=  z--classify-blockedu0   --pr N과 함께 사용: 차단 이유만 출력rx   output_jsonu   JSON 출력)r   destr=  )argparseArgumentParserRawDescriptionHelpFormatteradd_argumentr?   )ps    r4   _build_parserrI  T  s    a !<<	A4 NN:  
 NN9d1cNdNN8T0aNbNN:v4RNSNNE   NN?  
 NN8L}=NYHr3   c                    | j                   | j                  | j                  | j                  | j                  | j
                  dS )Nr   r   )caps    r4   _capability_to_dictrL    sB    00 22&)&D&D!44**#&#>#> r3   c                    | j                   | j                  | j                  j                  nd | j                  | j                  | j
                  | j                  | j                  dS )Nr  )r   r   r  r   r   r   r   r   )r)  s    r4   _plan_to_dictrN    sX    ++'+{{'>$++##D----''!33'' r3   __main__zERROR: r|   r   rZ   )r,  z	rev-parsez--abbrev-refHEADztask-\d+(?:[+\-]\w+)?probeF)fetch)r   branch_nameworkspace_metar/  )indentr   )r@   r  u   None (merge 가능)zpr #z blocked_reason: )r@   r   r  merge_path_planzpr              : #zblocked_reason  : zaction          : zcapability_gap  : zrequires_chair  : zdescription     : )r^   rA   r_   rA   returnrA   )rj   ri   rW  r   )
rr   rA   rs   rA   r   z	list[int]rq   Optional[RunnerType]rW  r   )r   r   rW  r   )r   	list[str]r{   r   rW  z"'subprocess.CompletedProcess[str]')r   rY  rq   rX  rW  zOptional[Any])r   rY  rW  r   )r?  )
rr   rA   rs   rA   r   rA   rq   rX  rW  r   )r   r   rK   rA   rW  r   )rj   ri   r   r   rW  r   )rj   ri   r   r   r  r   rW  r   )r@   r?   rW  ri   )r)  r   r@   r?   r   rA   rW  z'EscalationPacket | None')rq   rX  rW  ztuple[str, str])r@   r?   rq   rX  rW  ri   )rW  zargparse.ArgumentParser)rK  r   rW  ri   )r)  r   rW  ri   )cr0   
__future__r   rD  r   r   r   dataclassesr   r   enumr   typingr   r   r	   utils.automation_contractsr
   r   r   "utils.canonical_workspace_resolverr   __all__	frozensetr!   r1   r"   
RunnerTyper   rA   r   r   r   r   ro   r   r   r   r   r   r   r   r   r   r   r   r   r6  r8  rI  rL  rN  r-   parser
parse_argsr   rr   rs   r   rK  r   r   r   r   exitrB  cap_dictr1  _re_branch_guess_brr   r   r   r2  _task_matchr3  _inferred_task_id	workspacer   rS  dumpsitemskvrj   pr_infoblockedr)  classify_blockedr  r   valcombinedr   r   r   r   
print_helpr2   r3   r4   <module>rw     s  & #    
 *  * * 
< !* + !~  (2 _ 1
 =>
 $" " "$<C <. $" " " $? ? ?*> $(??
? ?
 !? ?D  $  6 
 
 (	" $(&
& !& 	&Z	
& p
 $(pp
p p
 !p pn$  	H]]$] ]Hd
d
$d
 ,d
 	d
V$
  	N $(, , ,0 $( ! 
	.0f	  z_FD J
Izzdiijj$))t57t::JJE9999D
 	"5$<C
 *3/H2  ")D C ~~*(+

(8(8(: )cjj)A=Q<GK$5$5a$8W!7%	
  )00#,#8#8.)* *$**Xa01+C0668 #12aSk"#
 ww	"5$<C$TWW-G-gs;G$Wc7;D
    "WW3:3F'--DF jdjj23'.':gmm@UTWWI%6se<=CHHQK -c2/6/Bgmm,T2	
 *$**Xa01'y12&w}}V&LMN&t{{m45&t':':&;<=&t':':&;<=&t'7'7&89: CHHQKY ,  	GC5/

3CHHQKK	& !   2-1)*2"  	GC5/

3CHHQKK	sg   S( +T0 25T$ 'AT0 9U (T!-)TT!$T-)T0 ,T--T0 0
T>=T>U:)U55U: