
     j]                    T   U d Z ddlmZ ddlZddlmc mZ ddl	Z	ddl
Z
ddlZddlmZ ddlmZmZmZ  ee      j'                         j(                  j(                  j(                  Z ee      ej.                  v r!ej.                  j1                   ee             ej.                  j3                  d ee             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) ddl*m+Z+m,Z, ddl-m.Z.m/Z/m0Z0m1Z1m2Z2m3Z3 dAdBd	Z4dCd
Z5dDdZ6ddddddddZ7de8d<   ddddddddZ9de8d<   ddddddddZ:de8d<   dddddd ddZ;de8d!<   d"dddd#d$ddZ<de8d%<   d&Z=d'Z>d(Z?d) Z@d* ZAd+ ZBd, ZCdEd-ZDd. ZEd/ ZFd0 ZGd1 ZHd2 ZId3 ZJd4 ZKd5 ZLd6 ZMd7 ZNd8 ZOd9 ZPd: ZQd; ZRd< ZSd= ZTd> ZUd? ZVd@ ZWy)Fu  tests/regression/test_bot_merge_identity_2522.py

회귀 테스트 — task-2522 GitHub App bot merge identity hardening.

회장 §본질:
  task-2522의 목표는 "머지가 되게 하는 것"이 **아니다.** 이미 머지는 된다.
  목표는 **"누가 머지했는가"**를 자동화 기준에 맞게 고치는 것.
  owner_pat로 머지되면 functional success여도 autonomy success로 인정 X.

5 연속 mergedBy=JonghyukJeon (PR #68/#69/#70/#71/#72) 종결 박제 + token source 4 enum 분류.

영역 A — Token source 분류 (4건)
영역 B — owner_pat fallback fixture replay (PR #68~#72, 5건)
영역 C — capability probe + autonomy_score 변화 (5건)

총 14건. 회장 §6 단일 파일.

회장 §보안: raw token value를 어떤 형태로도 출력/기록 X. fixture token도 prefix만 사용.
gh api 실호출 금지 — 모두 runner mock / dataclass 직접 주입.
    )annotationsN)Path)AnyDictList)DEFAULT_AUDIT_JSONL_PATHMergeIdentityAuditRecordTokenSourceTOKEN_SOURCE_GITHUB_APPTOKEN_SOURCE_GITHUB_ACTIONSTOKEN_SOURCE_OWNER_PATTOKEN_SOURCE_UNKNOWNappend_audit_jsonlbuild_audit_recordclassify_token_sourcecompute_autonomy_score_deltadecide_autonomy_capability_gapexpected_bot_identity_for_actorfingerprint_token_for_auditprobe_token_source_from_env)OWNER_PAT_FALLBACK_BLOCKEDselect_merge_token_decision)BlockedReasonRepositoryCapabilityclassify_capability_gapprobe_bot_merge_identity*reevaluate_bot_can_merge_with_token_sourceselect_merge_pathc                4    t        j                  g | ||      S )N)args
returncodestdoutstderr)
subprocessCompletedProcess)r!   r"   r#   s      D/home/jay/workspace/tests/regression/test_bot_merge_identity_2522.pycpr'   H   s    &&B:f]cdd    c                     dd fd}|S )uL   gh pr view <N> --json number,mergedBy 호출에 응답하는 runner factory.c                &   ~t        |       dk  s
| dd g dk7  rt        ddd      S 	 t        | d         }j	                  |      }|t        ddd	      S t        dt        j                  |      d      S # t        $ r t        ddd      cY S w xY w)
N   r      )ghprview    zunexpected callzbad pr numberz	Not Found)lenr'   int
ValueErrorgetjsondumps)r    cwdnpayloadpr_payloadss       r&   runnerz#make_pr_view_runner.<locals>.runnerO   s    t9q=D1I)==a.//	.DGA //!$?a[))!TZZ("--  	.a_--	.s   A7 7BBN)r    z	List[str]r8   r   returnsubprocess.CompletedProcess )r;   r<   s   ` r&   make_pr_view_runnerrA   L   s    . Mr(   c                 \    t        dddddd      }|j                  |        t        di |S )NTF)can_squash_mergerequires_approvalrequires_thread_resolutionauto_merge_enabledbot_can_mergeadmin_override_requiredr@   )dictupdater   )	overridesbases     r&   make_capabilityrM   _   s:    #( %D 	KK	'$''r(   D   JonghyukJeonUser)logintypez	task-2517z2026-05-09T00:53:24Z)task_idmergedAt)numbermergedBy_metaDict[str, Any]PR_68_FIXTUREE   z	task-2519z2026-05-09T02:04:50ZPR_69_FIXTUREF   z	task-2518z2026-05-09T04:50:46ZPR_70_FIXTUREG   z	task-2520z2026-05-09T06:31:34ZPR_71_FIXTUREH   	task-2521z2026-05-09T13:30:00ZPR_72_FIXTUREghs_aaaaghp_zzzzgithub_pat_yyyc                    t        t        dt        i      } | j                  }|t        k(  }|st	        j
                  d|fd|t        f      dt        j                         v st	        j                  |       rt	        j                  |       ndt	        j                  |      dt        j                         v st	        j                  t              rt	        j                  t              nddz  }dd	|iz  }t        t	        j                  |            d
x}}| j                  }d}||u }|st	        j
                  d|fd||f      dt        j                         v st	        j                  |       rt	        j                  |       ndt	        j                  |      t	        j                  |      dz  }dd|iz  }t        t	        j                  |            d
x}x}}| j                  }d}||u }|st	        j
                  d|fd||f      dt        j                         v st	        j                  |       rt	        j                  |       ndt	        j                  |      t	        j                  |      dz  }dd|iz  }t        t	        j                  |            d
x}x}}| j                  }t        d
d }||k(  }|st	        j
                  d|fd||f      dt        j                         v st	        j                  |       rt	        j                  |       ndt	        j                  |      t	        j                  |      dz  }dd|iz  }t        t	        j                  |            d
x}x}}| j                  }d
}||u}|st	        j
                  d|fd||f      dt        j                         v st	        j                  |       rt	        j                  |       ndt	        j                  |      t	        j                  |      dz  }dd|iz  }t        t	        j                  |            d
x}x}}| j                  }t!        |      }d}	||	k(  }
|
s
t	        j
                  d|
fd||	f      dt        j                         v st	        j                  t               rt	        j                  t               nddt        j                         v st	        j                  |       rt	        j                  |       ndt	        j                  |      t	        j                  |      t	        j                  |	      dz  }dd|iz  }t        t	        j                  |            d
x}x}x}
}	t#        j$                  | j'                               }t        dd
 }||v}|st	        j
                  d|fd||f      t	        j                  |      dt        j                         v st	        j                  |      rt	        j                  |      ndd z  }t	        j(                  d!      d"z   d#|iz  }t        t	        j                  |            d
x}}y
)$u[   (1) ``ghs_`` prefix token + actions runner 신호 없음 → GITHUB_APP_INSTALLATION_TOKEN.GITHUB_APP_INSTALLATION_TOKENtoken_valueenv==z4%(py2)s
{%(py2)s = %(py0)s.token_source
} == %(py4)sprober   py0py2py4assert %(py6)spy6NTisz;%(py2)s
{%(py2)s = %(py0)s.installation_signal
} is %(py5)srp   rq   py5assert %(py7)spy7Fz=%(py2)s
{%(py2)s = %(py0)s.actions_runner_signal
} is %(py5)s   )z=%(py2)s
{%(py2)s = %(py0)s.token_prefix_observed
} == %(py5)sis not)zF%(py2)s
{%(py2)s = %(py0)s.token_fingerprint_sha256_8
} is not %(py5)s   )z`%(py5)s
{%(py5)s = %(py0)s(%(py3)s
{%(py3)s = %(py1)s.token_fingerprint_sha256_8
})
} == %(py8)sr2   rp   py1py3ry   py8assert %(py10)spy10not inz%(py1)s not in %(py3)s
serialisedr   r   z-raw token suffix leaked into serialised probe
>assert %(py5)sry   )r   "_FIXTURE_INSTALLATION_TOKEN_PREFIXtoken_sourcer   
@pytest_ar_call_reprcompare@py_builtinslocals_should_repr_global_name	_safereprAssertionError_format_explanationinstallation_signalactions_runner_signaltoken_prefix_observedtoken_fingerprint_sha256_8r2   r6   r7   to_dict_format_assertmsg)rn   @py_assert1@py_assert3@py_format5@py_format7@py_assert4@py_format6@py_format8@py_assert2@py_assert7@py_assert6@py_format9@py_format11r   @py_assert0@py_format4s                   r&   >test_a1_ghs_prefix_classified_as_github_app_installation_tokenr      s   !6,.PQE 8!88888!888888858885888888888!8888!88888888$$,,$,,,,$,,,,,,5,,,5,,,$,,,,,,,,,,&&/%/&%////&%//////5///5///&///%///////&&P*LRa*PP&*PPPPP&*PPPPPPP5PPP5PPP&PPP*PPPPPPPP++747+47777+477777757775777+77747777777//53/05A50A55550A55555535553555555u555u555/5550555A5555555EMMO,J-ab1 1C  1    2      :D    :D    	8    r(   c                    t        t        dt        i      } | j                  }|t        k(  }|st	        j
                  d|fd|t        f      dt        j                         v st	        j                  |       rt	        j                  |       ndt	        j                  |      dt        j                         v st	        j                  t              rt	        j                  t              nddz  }dd	|iz  }t        t	        j                  |            d
x}}| j                  }d}||u }|st	        j
                  d|fd||f      dt        j                         v st	        j                  |       rt	        j                  |       ndt	        j                  |      t	        j                  |      dz  }dd|iz  }t        t	        j                  |            d
x}x}}t        t        dt        i      }|j                  }|t        k(  }|st	        j
                  d|fd|t        f      dt        j                         v st	        j                  |      rt	        j                  |      ndt	        j                  |      dt        j                         v st	        j                  t              rt	        j                  t              nddz  }dd	|iz  }t        t	        j                  |            d
x}}|j                  }d}||u }|st	        j
                  d|fd||f      dt        j                         v st	        j                  |      rt	        j                  |      ndt	        j                  |      t	        j                  |      dz  }dd|iz  }t        t	        j                  |            d
x}x}}y
)u9   (2) ``ghp_`` 또는 ``github_pat_`` prefix → OWNER_PAT.
GITHUB_PATrh   rk   rm   probe_ar   ro   rs   rt   NTru   z8%(py2)s
{%(py2)s = %(py0)s.owner_pat_signal
} is %(py5)srx   rz   r{   GH_PATprobe_b)r   !_FIXTURE_OWNER_PAT_CLASSIC_PREFIXr   r   r   r   r   r   r   r   r   r   owner_pat_signal%_FIXTURE_OWNER_PAT_FINEGRAINED_PREFIX	r   r   r   r   r   r   r   r   r   s	            r&   9test_a2_ghp_and_github_pat_prefix_classified_as_owner_patr      s$    $5<=G 9#99999#999999979997999999999#9999#99999999##+t+#t++++#t++++++7+++7+++#+++t+++++++ $9<=G 9#99999#999999979997999999999#9999#99999999##+t+#t++++#t++++++7+++7+++#+++t+++++++r(   c                 t   t        dddd      } | j                  }|t        k(  }|st        j                  d|fd|t        f      dt        j                         v st        j                  |       rt        j                  |       ndt        j                  |      d	t        j                         v st        j                  t              rt        j                  t              nd	d
z  }dd|iz  }t        t        j                  |            dx}}| j                  }d}||u }|st        j                  d|fd||f      dt        j                         v st        j                  |       rt        j                  |       ndt        j                  |      t        j                  |      dz  }dd|iz  }t        t        j                  |            dx}x}}t        t        dt        d      }|j                  }|t        k(  }|st        j                  d|fd|t        f      dt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      d	t        j                         v st        j                  t              rt        j                  t              nd	d
z  }dd|iz  }t        t        j                  |            dx}}|j                  }d}||u }|st        j                  d|fd||f      dt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      t        j                  |      dz  }dd|iz  }t        t        j                  |            dx}x}}y)u   (3) GITHUB_ACTIONS=true env (token 값 없음) → GITHUB_ACTIONS_TOKEN.

    runner GITHUB_TOKEN(ghs_)가 있어도 actions runner 환경에서는
    ACTIONS_TOKEN으로 분류된다 (출처가 명확).
    Ntruezubuntu-runner-1)GITHUB_ACTIONSRUNNER_NAMErh   rk   rm   r   r   ro   rs   rt   Tru   r|   rx   rz   r{   )r   GITHUB_TOKENr   )r   r   r   r   r   r   r   r   r   r   r   r   r   r   s	            r&   6test_a3_github_actions_env_classified_as_actions_tokenr      s$    $%6GHG >#>>>>>#>>>>>>>7>>>7>>>>>>>>>#>>>>#>>>>>>>>((0D0(D0000(D00000070007000(000D0000000 $6%7YZG >#>>>>>#>>>>>>>7>>>7>>>>>>>>>#>>>>#>>>>>>>>((0D0(D0000(D00000070007000(000D0000000r(   c            	        t        di       } | j                  }|t        k(  }|st        j                  d|fd|t        f      dt        j                         v st        j                  |       rt        j                  |       ndt        j                  |      dt        j                         v st        j                  t              rt        j                  t              nddz  }dd	|iz  }t        t        j                  |            dx}}| j                  }d
}||u }|st        j                  d|fd||f      dt        j                         v st        j                  |       rt        j                  |       ndt        j                  |      t        j                  |      dz  }dd|iz  }t        t        j                  |            dx}x}}| j                  }d
}||u }|st        j                  d|fd||f      dt        j                         v st        j                  |       rt        j                  |       ndt        j                  |      t        j                  |      dz  }dd|iz  }t        t        j                  |            dx}x}}| j                  }d
}||u }|st        j                  d|fd||f      dt        j                         v st        j                  |       rt        j                  |       ndt        j                  |      t        j                  |      dz  }dd|iz  }t        t        j                  |            dx}x}}| j                  }d}||u }|st        j                  d|fd||f      dt        j                         v st        j                  |       rt        j                  |       ndt        j                  |      t        j                  |      dz  }dd|iz  }t        t        j                  |            dx}x}}| j                  }d}||u }|st        j                  d|fd||f      dt        j                         v st        j                  |       rt        j                  |       ndt        j                  |      t        j                  |      dz  }dd|iz  }t        t        j                  |            dx}x}}| j                  }t!        |      }t         j"                  }	||	u }
|
sSt        j                  d|
fd||	f      dt        j                         v st        j                  t               rt        j                  t               nddt        j                         v st        j                  |       rt        j                  |       ndt        j                  |      t        j                  |      dt        j                         v st        j                  t               rt        j                  t               ndt        j                  |	      dz  }dd|iz  }t        t        j                  |            dx}x}x}
}	y)u0   (4) env 미설정, token 값 없음 → UNKNOWN.Nrh   rk   rm   rn   r   ro   rs   rt   Fru   r|   rx   rz   r{   rw   r   )z=%(py2)s
{%(py2)s = %(py0)s.token_prefix_observed
} is %(py5)s)zB%(py2)s
{%(py2)s = %(py0)s.token_fingerprint_sha256_8
} is %(py5)s)zo%(py5)s
{%(py5)s = %(py0)s(%(py3)s
{%(py3)s = %(py1)s.token_source
})
} is %(py9)s
{%(py9)s = %(py7)s.UNKNOWN
}r
   )rp   r   r   ry   r{   py9assert %(py11)spy11)r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r
   UNKNOWN)rn   r   r   r   r   r   r   r   r   @py_assert8r   @py_format10@py_format12s                r&   (test_a4_no_signals_classified_as_unknownr      s   !d;E5!55555!555555555555555555555!5555!55555555&&/%/&%////&%//////5///5///&///%///////$$--$----$------5---5---$----------!!*U*!U****!U******5***5***!***U*******&&.$.&$....&$......5...5...&...$.......++3t3+t3333+t33333353335333+333t3333333))A;)*Ak.A.AA*.AAAAA*.AAAAAAA;AAA;AAAAAAuAAAuAAA)AAA*AAAAAAkAAAkAAA.AAAAAAAAr(   c                4   t        | |i      }t        dd| g|      }|j                  }d}||u }|st        j                  d|fd||f      dt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      t        j                  |      dz  }d	d
|iz  }t        t        j                  |            dx}x}}|j                  }d}||k(  }|st        j                  d|fd||f      dt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      t        j                  |      dz  }d	d
|iz  }t        t        j                  |            dx}x}}|j                  }d}||u }|st        j                  d|fd||f      dt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      t        j                  |      dz  }d	d
|iz  }t        t        j                  |            dx}x}}|j                  }d}||k(  }|st        j                  d|fd||f      dt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      t        j                  |      dz  }d	d
|iz  }t        t        j                  |            dx}x}}|j                  }d}||u }|st        j                  d|fd||f      dt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      t        j                  |      dz  }d	d
|iz  }t        t        j                  |            dx}x}}t        |      }	t         j"                  }|	|k(  }|st        j                  d|fd|	|f      dt        j                         v st        j                  |	      rt        j                  |	      nddt        j                         v st        j                  t               rt        j                  t               ndt        j                  |      dz  }
dd|
iz  }t        t        j                  |            dx}}t%        | t'        t(        dt(        i      |d   d   |d   d   |j+                  di       j+                  d       |j+                  di       j+                  d!      "      }|j,                  }|t.        k(  }|st        j                  d|fd#|t.        f      d$t        j                         v st        j                  |      rt        j                  |      nd$t        j                  |      d%t        j                         v st        j                  t.              rt        j                  t.              nd%dz  }
dd|
iz  }t        t        j                  |            dx}}|j0                  }d}||k(  }|st        j                  d|fd&||f      d$t        j                         v st        j                  |      rt        j                  |      nd$t        j                  |      t        j                  |      dz  }d	d
|iz  }t        t        j                  |            dx}x}}|j2                  }d}||u }|st        j                  d|fd'||f      d$t        j                         v st        j                  |      rt        j                  |      nd$t        j                  |      t        j                  |      dz  }d	d
|iz  }t        t        j                  |            dx}x}}|j4                  }d}||u }|st        j                  d|fd(||f      d$t        j                         v st        j                  |      rt        j                  |      nd$t        j                  |      t        j                  |      dz  }d	d
|iz  }t        t        j                  |            dx}x}}|j6                  }d}||u }|st        j                  d|fd)||f      d$t        j                         v st        j                  |      rt        j                  |      nd$t        j                  |      t        j                  |      dz  }d	d
|iz  }t        t        j                  |            dx}x}}y)*uS   공통 검증: PR fixture replay → owner_pat fallback 박제 + autonomy gap True.Jeon-Jonghyukdev_workspacer<   Tru   zH%(py2)s
{%(py2)s = %(py0)s.fallback_to_owner_token_detected
} is %(py5)sidentityrx   rz   r{   N	owner_patrk   )z4%(py2)s
{%(py2)s = %(py0)s.token_source
} == %(py5)sFz<%(py2)s
{%(py2)s = %(py0)s.bot_can_merge_as_app
} is %(py5)srO   )z9%(py2)s
{%(py2)s = %(py0)s.merge_actor_login
} == %(py5)s)z:%(py2)s
{%(py2)s = %(py0)s.merge_actor_is_bot
} is %(py5)s)zA%(py0)s == %(py4)s
{%(py4)s = %(py2)s.AUTOMATION_CAPABILITY_GAP
}blockedr   ro   rs   rt   r   rh   rV   rQ   rR   rW   mergeCommitrS   )	pr_numbertoken_probemergedBy_loginmergedBy_typemerge_commit_sharS   )z9%(py2)s
{%(py2)s = %(py0)s.token_source_used
} == %(py4)srecordr   )z6%(py2)s
{%(py2)s = %(py0)s.mergedBy_login
} == %(py5)sz7%(py2)s
{%(py2)s = %(py0)s.mergedBy_is_bot
} is %(py5)sz=%(py2)s
{%(py2)s = %(py0)s.expected_bot_identity
} is %(py5)sz?%(py2)s
{%(py2)s = %(py0)s.autonomy_capability_gap
} is %(py5)s)rA   r    fallback_to_owner_token_detectedr   r   r   r   r   r   r   r   r   bot_can_merge_as_appmerge_actor_loginmerge_actor_is_botr   r   AUTOMATION_CAPABILITY_GAPr   r   r   r5   token_source_usedr   r   mergedBy_is_botexpected_bot_identityautonomy_capability_gap)r   fixturer<   r   r   r   r   r   r   r   r   r   r   s                r&   _replay_pr_owner_pat_fallbackr      s    )W!56F'9+fH 44<<4<<<<4<<<<<<8<<<8<<<4<<<<<<<<<<  /K/ K//// K//////8///8/// ///K///////((1E1(E1111(E11111181118111(111E1111111%%77%7777%77777787778777%7777777777&&/%/&%////&%//////8///8///&///%///////%h/G#===7=====7=======7===7======m===m===========  )9@A
 z*73j)&1 Wb155mDGR(,,Y7
F ##=#'=====#'=======6===6===#======'===='========  2N2 N2222 N22222262226222 222N2222222!!*U*!U****!U******6***6***!***U*******''050'50000'500000060006000'00050000000))1T1)T1111)T11111161116111)111T1111111r(   c                 $    t        dt               y)u>   (5) PR #68 mergedBy=JonghyukJeon — task-2517 fixture replay.rN   N)r   rY   r@   r(   r&   'test_b1_pr_68_owner_pat_fallback_replayr         !"m4r(   c                 $    t        dt               y)u>   (6) PR #69 mergedBy=JonghyukJeon — task-2519 fixture replay.rZ   N)r   r[   r@   r(   r&   'test_b2_pr_69_owner_pat_fallback_replayr     r   r(   c                 $    t        dt               y)u>   (7) PR #70 mergedBy=JonghyukJeon — task-2518 fixture replay.r\   N)r   r]   r@   r(   r&   'test_b3_pr_70_owner_pat_fallback_replayr     r   r(   c                 $    t        dt               y)u>   (8) PR #71 mergedBy=JonghyukJeon — task-2520 fixture replay.r^   N)r   r_   r@   r(   r&   'test_b4_pr_71_owner_pat_fallback_replayr     r   r(   c                 z   t        dt               t        t        t        t
        t        t        d      } t        ddg d|       }|j                  }t        |      }d}||k(  }|s
t        j                  d|fd||f      d	t        j                         v st        j                  t              rt        j                  t              nd	d
t        j                         v st        j                  |      rt        j                  |      nd
t        j                  |      t        j                  |      t        j                  |      dz  }dd|iz  }t!        t        j"                  |            dx}x}x}}d |j                  D        }t%        |      }	|	sddt        j                         v st        j                  t$              rt        j                  t$              ndt        j                  |      t        j                  |	      dz  }
t!        t        j"                  |
            dx}}	|j&                  }d}||u }	|	st        j                  d|	fd||f      d
t        j                         v st        j                  |      rt        j                  |      nd
t        j                  |      t        j                  |      dz  }dd|iz  }t!        t        j"                  |            dx}x}	}|j(                  }d}||u }	|	st        j                  d|	fd||f      d
t        j                         v st        j                  |      rt        j                  |      nd
t        j                  |      t        j                  |      dz  }dd|iz  }t!        t        j"                  |            dx}x}	}t+        ddit-               t.        j0                        }|j2                  }d}||k(  }	|	st        j                  d|	fd||f      dt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      t        j                  |      dz  }dd|iz  }t!        t        j"                  |            dx}x}	}|j4                  }d}||u }	|	st        j                  d|	fd||f      dt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      t        j                  |      dz  }dd|iz  }t!        t        j"                  |            dx}x}	}|j6                  }d}||u }	|	st        j                  d|	fd ||f      dt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      t        j                  |      dz  }dd|iz  }t!        t        j"                  |            dx}x}	}y)!u  (9) PR #72 mergedBy=JonghyukJeon — task-2521 fixture replay (본 task의 직전 PR).

    회장 §본질: task-2521 자체가 owner_pat fallback으로 머지되어 5 연속 패턴 종결.
    select_merge_path → escalate_capability_gap. 회장 직접 머지 X (ops 채널만).
    r`   )rN   rZ   r\   r^   r`   r   r   r   r}   rk   )zZ%(py5)s
{%(py5)s = %(py0)s(%(py3)s
{%(py3)s = %(py1)s.merge_identity_audit
})
} == %(py8)sr2   r   r   r   r   Nc              3  4   K   | ]  }|j                     y wr=   )fallback_to_owner_token).0rs     r&   	<genexpr>z:test_b5_pr_72_owner_pat_fallback_replay.<locals>.<genexpr>0  s     PQq((Ps   z,assert %(py4)s
{%(py4)s = %(py0)s(%(py2)s)
}allro   Tru   r   rx   rz   r{   Fr   rU   escalate_capability_gap)z.%(py2)s
{%(py2)s = %(py0)s.action
} == %(py5)splan)z6%(py2)s
{%(py2)s = %(py0)s.requires_chair
} is %(py5)s)z6%(py2)s
{%(py2)s = %(py0)s.capability_gap
} is %(py5)s)r   rb   rA   rY   r[   r]   r_   r   merge_identity_auditr2   r   r   r   r   r   r   r   r   r   r   r   r   rM   r   r   actionrequires_chaircapability_gap)r<   r   r   r   r   r   r   r   r   r   r   r   r   r   s                 r&   'test_b5_pr_72_owner_pat_fallback_replayr     s    ""m4 !}-}" F (*>vH ,,23,-22-2222-22222232223222222x222x222,222-2222222222P(2O2OPP3PPPPPPPPP3PPP3PPPPPPPPPPPPPP44<<4<<<<4<<<<<<8<<<8<<<4<<<<<<<<<<((1E1(E1111(E11111181118111(111E1111111	2//D
 ;;333;33333;333333343334333;33333333333'%'%''''%''''''4'''4''''''%'''''''&$&$&&&&$&&&&&&4&&&4&&&&&&$&&&&&&&r(   c                    t        di       } | j                  }|t        k(  }|st        j                  d|fd|t        f      dt        j                         v st        j                  |       rt        j                  |       ndt        j                  |      dt        j                         v st        j                  t              rt        j                  t              nddz  }dd	|iz  }t        t        j                  |            dx}}t        d
      }t        || j                        }|j                  }d}||u }|st        j                  d|fd||f      dt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      t        j                  |      dz  }dd|iz  }	t        t        j                  |	            dx}x}}t        | j                        }
|
d   }d}||u }|slt        j                  d|fd||f      t        j                  |      t        j                  |      dz  }dd	|iz  }t        t        j                  |            dx}x}}|
d   }d}||k(  }|slt        j                  d|fd||f      t        j                  |      t        j                  |      dz  }dd	|iz  }t        t        j                  |            dx}x}}|
d   }d
}||u }|slt        j                  d|fd||f      t        j                  |      t        j                  |      dz  }dd	|iz  }t        t        j                  |            dx}x}}y)u   (10) bot/app token 없음 (UNKNOWN) → reevaluate가 bot_can_merge=False 강제.

    select_merge_token_decision → AUTOMATION_CAPABILITY_GAP (allow_merge=False).
    Nrh   rk   rm   rn   r   ro   rs   rt   TrG   r   Fru   z5%(py2)s
{%(py2)s = %(py0)s.bot_can_merge
} is %(py5)sreevalrx   rz   r{   allow_mergez%(py1)s is %(py4)sr   rr   decisionr   z%(py1)s == %(py4)sr   )r   r   r   r   r   r   r   r   r   r   r   rM   r   rG   r   )rn   r   r   r   r   capr   r   r   r   r  r   r   s                r&   @test_c1_no_bot_app_token_classified_as_automation_capability_gapr  C  s.   
 "d;E5!55555!555555555555555555555!5555!55555555

-C7%J\J\]F(5(5((((5((((((6(((6((((((5(((((((*5+=+=>HM"+e+"e++++"e+++"+++e+++++++J>#>>#>>>>>#>>>>>>>#>>>>>>>>$%--%----%---%----------r(   c                    t        t        dt        i      } | j                  }|t        k(  }|st	        j
                  d|fd|t        f      dt        j                         v st	        j                  |       rt	        j                  |       ndt	        j                  |      dt        j                         v st	        j                  t              rt	        j                  t              nddz  }dd	|iz  }t        t	        j                  |            d
x}}t        d      }t        || j                        }|j                  }d}||u }|st	        j
                  d|fd||f      dt        j                         v st	        j                  |      rt	        j                  |      ndt	        j                  |      t	        j                  |      dz  }dd|iz  }	t        t	        j                  |	            d
x}x}}||k(  }|st	        j
                  d|fd||f      dt        j                         v st	        j                  |      rt	        j                  |      nddt        j                         v st	        j                  |      rt	        j                  |      nddz  }
dd|
iz  }t        t	        j                  |            d
}t        | j                        }|d   }d}||u }|slt	        j
                  d|fd||f      t	        j                  |      t	        j                  |      dz  }dd	|iz  }t        t	        j                  |            d
x}x}}|d   }d}||k(  }|slt	        j
                  d|fd||f      t	        j                  |      t	        j                  |      dz  }dd	|iz  }t        t	        j                  |            d
x}x}}|d   }d }||u }|slt	        j
                  d|fd||f      t	        j                  |      t	        j                  |      dz  }dd	|iz  }t        t	        j                  |            d
x}x}}y
)!uV   (11) bot/app token 있음 + ruleset 허용 → bot_can_merge 유지, allow_merge=True.rg   rh   rk   rm   rn   r   ro   rs   rt   NTr   r   ru   r   r   rx   rz   r{   z%(py0)s == %(py2)sr  rp   rq   assert %(py4)srr   r   r  r  r  APP_TOKEN_OKr  r   F)r   r   r   r   r   r   r   r   r   r   r   r   rM   r   rG   r   )rn   r   r   r   r   r  r   r   r   r   @py_format3r  r   r   s                 r&   /test_c2_app_token_with_ruleset_allows_bot_merger  U  s   !6,.PQE 8!88888!888888858885888888888!8888!88888888

-C7%J\J\]F'4'4''''4''''''6'''6''''''4'''''''S=6S66SS*5+=+=>HM"*d*"d****"d***"***d*******J1>1>1111>111111>1111111$%..%....%...%..........r(   c                 .   t        t        dt        i      } t        d| ddd      }|j                  }d}||u }|st	        j
                  d	|fd
||f      dt        j                         v st	        j                  |      rt	        j                  |      ndt	        j                  |      t	        j                  |      dz  }dd|iz  }t        t	        j                  |            dx}x}}t        d|      }|j                  }d}||k(  }|st	        j
                  d|fd||f      dt        j                         v st	        j                  |      rt	        j                  |      ndt	        j                  |      t	        j                  |      dz  }dd|iz  }t        t	        j                  |            dx}x}}|j                  }d}||k(  }|st	        j
                  d|fd||f      dt        j                         v st	        j                  |      rt	        j                  |      ndt	        j                  |      t	        j                  |      dz  }dd|iz  }t        t	        j                  |            dx}x}}|j                  }d}| }||k(  }|st	        j
                  d|fd||f      dt        j                         v st	        j                  |      rt	        j                  |      ndt	        j                  |      t	        j                  |      dz  }	dd|	iz  }
t        t	        j                  |
            dx}x}x}}g }d}|j                   }|j"                  } |       }||v }|}|s'd}|j                   }|j"                  } |       }||v }|}|st	        j
                  d|fd||f      t	        j                  |      dt        j                         v st	        j                  |      rt	        j                  |      ndt	        j                  |      t	        j                  |      t	        j                  |      dz  }d d!|iz  }|j%                  |       |st	        j
                  dfd"f      t	        j                  |      dt        j                         v st	        j                  |      rt	        j                  |      ndt	        j                        t	        j                        t	        j                  |      d#z  }d$d%|iz  }|j%                  |       t	        j&                  |d      i z  }d&d'|iz  }t        t	        j                  |            dx}x}x}x}x}x}x}x}x}x}x}}y)(u   (12) mergedBy = owner (사람) → autonomy_score 유지 또는 -1.

    회장 §본질: owner 직접 머지는 5 연속 패턴 → score 하락 신호.
    r   rh   r`   rO   rP   ra   r   r   r   r   rS   Tru   r   r   rx   rz   r{   N   previous_scorer   rk   )z6%(py2)s
{%(py2)s = %(py0)s.previous_score
} == %(py5)sdelta   z1%(py2)s
{%(py2)s = %(py0)s.new_score
} == %(py5)sr0   z.%(py2)s
{%(py2)s = %(py0)s.delta
} == -%(py5)sassert %(py8)sr   r   zowner directin)zb%(py3)s in %(py11)s
{%(py11)s = %(py9)s
{%(py9)s = %(py7)s
{%(py7)s = %(py5)s.reason
}.lower
}()
})r   ry   r{   r   r   z%(py13)spy13)zh%(py16)s in %(py24)s
{%(py24)s = %(py22)s
{%(py22)s = %(py20)s
{%(py20)s = %(py18)s.reason
}.lower
}()
})py16py18py20py22py24z%(py26)spy26zassert %(py29)spy29)r   r   r   r   r   r   r   r   r   r   r   r   r   r  	new_scorer  reasonlowerappend_format_boolop)rn   r   r   r   r   r   r   r  r   r   r   r   r   @py_assert10r   @py_assert15@py_assert19@py_assert21@py_assert23@py_assert17r   @py_format14@py_format25@py_format27@py_format28@py_format30s                             r&   ,test_c3_owner_merged_score_held_or_decreasedr2  i  sT   
 "5<=E  %F ))1T1)T1111)T11111161116111)111T1111111(&IE$1$1$$$$1$$$$$$5$$$5$$$$$$1$$$$$$$??a?a?a55?a;;11";";"55;1X;X%,,X,,,X,.X;..X.XELLXLDVDVXDVDXX.DX2XXXXX;.XXX;XXXXXX%XXX%XXX,XXX,XXX.XXXXXXX.DXXXX.XXXXXXEXXXEXXXLXXXDVXXXDXXXXXXXXXXXXXXXXr(   c                 6   t        t        dt        i      } t        d| ddd      }|j                  }d}||u }|st	        j
                  d	|fd
||f      dt        j                         v st	        j                  |      rt	        j                  |      ndt	        j                  |      t	        j                  |      dz  }dd|iz  }t        t	        j                  |            dx}x}}|j                  }d}||u }|st	        j
                  d	|fd||f      dt        j                         v st	        j                  |      rt	        j                  |      ndt	        j                  |      t	        j                  |      dz  }dd|iz  }t        t	        j                  |            dx}x}}|j                  }d}||u }|st	        j
                  d	|fd||f      dt        j                         v st	        j                  |      rt	        j                  |      ndt	        j                  |      t	        j                  |      dz  }dd|iz  }t        t	        j                  |            dx}x}}t        d|      }|j                  }d}||k(  }|st	        j
                  d|fd||f      dt        j                         v st	        j                  |      rt	        j                  |      ndt	        j                  |      t	        j                  |      dz  }dd|iz  }t        t	        j                  |            dx}x}}|j                   }d}||k(  }|st	        j
                  d|fd||f      dt        j                         v st	        j                  |      rt	        j                  |      ndt	        j                  |      t	        j                  |      dz  }dd|iz  }t        t	        j                  |            dx}x}}y)u   (13) mergedBy = bot/app + token_source = GITHUB_APP_* → autonomy_score +1.

    회장 §본질: 본 task의 종결 목표 — 다음 PR이 bot으로 머지되면 7→8.
    rg   rh   i  github-actions[bot]Bot	task-2522r  Fru   r   r   rx   rz   r{   NTr   r   r  r  r   rk   r  r  r0   )z-%(py2)s
{%(py2)s = %(py0)s.delta
} == %(py5)s)r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r"  r  )rn   r   r   r   r   r   r   r  s           r&   1test_c4_bot_merged_with_app_token_score_increasedr7    ss   
 "6,.PQE  ,F ))2U2)U2222)U22222262226222)222U2222222''/4/'4////'4//////6///6///'///4///////!!)T)!T))))!T))))))6)))6)))!)))T)))))))(&IE??a?a?a55?a;;!;!;!55;!r(   c                 n   t        t        dt        i      } t        | j                        }|d   }d}||u }|slt	        j
                  d|fd||f      t	        j                  |      t	        j                  |      dz  }dd	|iz  }t        t	        j                  |            d
x}x}}|d   }|t        k(  }|st	        j
                  d|fd|t        f      t	        j                  |      dt        j                         v st	        j                  t              rt	        j                  t              nddz  }dd|iz  }t        t	        j                  |            d
x}}|d   }d}||u }|slt	        j
                  d|fd||f      t	        j                  |      t	        j                  |      dz  }dd	|iz  }t        t	        j                  |            d
x}x}}t        d      }	t        |	| j                        }
|
j                  }d}||u }|st	        j
                  d|fd||f      dt        j                         v st	        j                  |
      rt	        j                  |
      ndt	        j                  |      t	        j                  |      dz  }dd|iz  }t        t	        j                  |            d
x}x}}t!        d| ddd      }t"        d z  d!z  d"z  }|j%                         r|j'                          t)        ||#      }||k(  }|st	        j
                  d|fd$||f      d%t        j                         v st	        j                  |      rt	        j                  |      nd%d&t        j                         v st	        j                  |      rt	        j                  |      nd&d'z  }d(d)|iz  }t        t	        j                  |            d
}|j$                  } |       }|sd*d&t        j                         v st	        j                  |      rt	        j                  |      nd&t	        j                  |      t	        j                  |      d+z  }t        t	        j                  |            d
x}}|j+                  d,-      j-                         j/                         d.   }t1        j2                  |      }t        d/d
 }||v}|st	        j
                  d0|fd1||f      t	        j                  |      d2t        j                         v st	        j                  |      rt	        j                  |      nd2dz  }t	        j4                  d3      d4z   d|iz  }t        t	        j                  |            d
x}}|d5   }d}||u }|slt	        j
                  d|fd||f      t	        j                  |      t	        j                  |      dz  }dd	|iz  }t        t	        j                  |            d
x}x}}|d6   }|t6        k(  }|st	        j
                  d|fd|t6        f      t	        j                  |      d7t        j                         v st	        j                  t6              rt	        j                  t6              nd7dz  }dd|iz  }t        t	        j                  |            d
x}}|j'                  d8       t9        d9|:      }|j:                  }d;}||k(  }|st	        j
                  d|fd<||f      d=t        j                         v st	        j                  |      rt	        j                  |      nd=t	        j                  |      t	        j                  |      dz  }dd|iz  }t        t	        j                  |            d
x}x}}y
)>u`  (14) owner_pat fallback → 자동 머지 거부, AUTOMATION_CAPABILITY_GAP marker로 박제.

    회장 §5 명시:
      - owner_pat fallback 발생 → Critical 7종 아님, AUTOMATION_CAPABILITY_GAP marker
      - select_merge_token_decision은 OWNER_PAT_FALLBACK_BLOCKED + capability_gap=True
      - audit JSONL append + 다음 score 산출
    r   rh   r   Fru   r  r  rs   rt   Nr  rk   )z%(py1)s == %(py3)sr   r   assert %(py5)sry   r   Tr   r   r   r   rx   rz   r{   r`   rO   rP   r6  r  memoryeventsz&test_bot_merge_identity_2522_tmp.jsonl)
audit_pathr  written_pathtmpr	  r
  rr   zAassert %(py4)s
{%(py4)s = %(py2)s
{%(py2)s = %(py0)s.exists
}()
}ro   zutf-8)encodingr}   r   r   linez(raw token suffix leaked into JSONL auditr   r   r   r   )
missing_okr  r  r  r  r  )r   r   r   r   r   r   r   r   r   r   r   r   r   rM   r   rG   r   _WORKTREE_ROOTexistsunlinkr   	read_textstrip
splitlinesr6   loadsr   r   r   r"  )rn   r  r   r   r   r   r   r   r   r  r   r   r   r   r   r>  r=  r  rA  r:   r  s                        r&   8test_c5_owner_pat_fallback_blocks_auto_merge_with_markerrJ    s    "5<=E +5+=+=>HM"+e+"e++++"e+++"+++e+++++++J=#=====#==========#====#========$%--%----%---%----------

-C7%J\J\]F(5(5((((5((((((6(((6((((((5(((((((  %F 8
#h
.1Y
YC
zz|

%f=L3<3<<33:::<<33:<=='=*002==?CDjjG,QR0 0<  0    1      9=    9=    	3     ,-55-5555-555-5555555555&'A'+AAAAA'+AAAA'AAAAAA+AAAA+AAAAAAAAJJ$J )&IE??a?a?a55?ar(   c                    t         D  ch c]  } | j                   }} t        t        t        t
        h}||k(  }|st        j                  d|fd||f      dt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      dz  }dd|iz  }t        t        j                  |            dx}}yc c} w )uE   sanity: TokenSource enum 정확히 4종 — 회장 §1 추가 금지.rk   z%(py0)s == %(py3)svaluesrp   r   r9  ry   N)r
   valuer   r   r   r   r   r   r   r   r   r   r   r   )memberrM  r   r   r   r   s         r&   ,test_sanity_token_source_enum_exact_4_valuesrQ    s    )45vfll5F5#	 6   
 6   
  
    
    
     
   6s   Cc                    t        t              } | j                  }d} ||      }|st        j                  |       dz   dt        j                         v st        j                  |       rt        j                  |       ndt        j                  |      t        j                  |      t        j                  |      dz  }t        t        j                  |            dx}x}}y)uR   sanity: default audit path가 memory/orchestration-audit/bot-merge-identity.jsonl.zbot-merge-identity.jsonlzL
>assert %(py6)s
{%(py6)s = %(py2)s
{%(py2)s = %(py0)s.endswith
}(%(py4)s)
}p)rp   rq   rr   rt   N)strr   endswithr   r   r   r   r   r   r   r   )rS  r   r   @py_assert5r   s        r&   5test_sanity_default_audit_jsonl_path_inside_workspacerW    s    $%A::404:014144144444414441444:44404441444444r(   c                 "   d} t        | d| i      }t        d|dd      }t        j                  |j	                         d	      }d
}||v}|st        j                  d|fd||f      t        j                  |      dt        j                         v st        j                  |      rt        j                  |      nddz  }dd|iz  }t        t        j                  |            dx}}d}||v }|st        j                  d|fd||f      t        j                  |      dt        j                         v st        j                  |      rt        j                  |      nddz  }dd|iz  }t        t        j                  |            dx}}y)uV   sanity: build_audit_record 결과 직렬화 시 raw token 5자 이후 부분 노출 X.ghs_aaaaSECRETSUFFIX1234567890rg   rh   r0   r4  r5  )r   r   r   r   F)ensure_asciiSECRETSUFFIXr   r   r   r   r9  ry   Nghs_ar  )z%(py1)s in %(py3)s)r   r   r6   r7   r   r   r   r   r   r   r   r   r   )
fake_tokenrn   r   r   r   r   r   r   s           r&   0test_sanity_no_raw_token_in_record_serialisationr^    s    1J!,j9E  ,	F FNN,5AJ+>++++>+++>++++++++++++++++ 7j    7j   7      j   j       r(   c                 	   d} d}t        | |      }d}||u }|st        j                  d|fd||f      dt        j                         v st        j
                  t               rt        j                  t               ndt        j                  |       t        j                  |      t        j                  |      t        j                  |      dz  }dd	|iz  }t        t        j                  |            d
x} x}x}x}}d} d}t        | |      }d}||u }|st        j                  d|fd||f      dt        j                         v st        j
                  t               rt        j                  t               ndt        j                  |       t        j                  |      t        j                  |      t        j                  |      dz  }dd	|iz  }t        t        j                  |            d
x} x}x}x}}d} d}t        | |      }d}||u }|st        j                  d|fd||f      dt        j                         v st        j
                  t               rt        j                  t               ndt        j                  |       t        j                  |      t        j                  |      t        j                  |      dz  }dd	|iz  }t        t        j                  |            d
x} x}x}x}}d} d}t        | |      }d}||u }|st        j                  d|fd||f      dt        j                         v st        j
                  t               rt        j                  t               ndt        j                  |       t        j                  |      t        j                  |      t        j                  |      dz  }dd	|iz  }t        t        j                  |            d
x} x}x}x}}d} d}t        | |      }d}||u }|st        j                  d|fd||f      dt        j                         v st        j
                  t               rt        j                  t               ndt        j                  |       t        j                  |      t        j                  |      t        j                  |      dz  }dd	|iz  }t        t        j                  |            d
x} x}x}x}}y
)uM   sanity: expected_bot_identity_for_actor — bot suffix or type==Bot → True.r4  r5  Tru   )z9%(py6)s
{%(py6)s = %(py0)s(%(py2)s, %(py4)s)
} is %(py9)sr   )rp   rq   rr   rt   r   r   r   Nzdependabot[bot]rP   renovaterO   Fr1   )	r   r   r   r   r   r   r   r   r   )r   r   rV  r   r   r   r   s          r&   (test_sanity_expected_bot_identity_helperra    s   +@P%P*+@%HPDPHDPPPPHDPPPPPP*PPP*PPP+@PPP%PPPHPPPDPPPPPPP+<MfM*+<fEMMEMMMMEMMMMMM*MMM*MMM+<MMMfMMMEMMMMMMMMMM+5EuE*:u=EE=EEEE=EEEEEE*EEE*EEE:EEEuEEE=EEEEEEEEEE+9K6K*>6BKeKBeKKKKBeKKKKKK*KKK*KKK>KKK6KKKBKKKeKKKKKKK+->u>*2u5>>5>>>>5>>>>>>*>>>*>>>2>>>u>>>5>>>>>>>>>>>r(   c            	        d} d}t        t        | |      }d}||u }|s&t        j                  d|fd||f      dt	        j
                         v st        j                  t               rt        j                  t               nddt	        j
                         v st        j                  t              rt        j                  t              ndt        j                  |       t        j                  |      t        j                  |      t        j                  |      dz  }d	d
|iz  }t        t        j                  |            dx} x}x}x}}y)uB   sanity: token_source=UNKNOWN → 무조건 GAP=True (fail-closed).r4  T)r   r   r   ru   )zo%(py7)s
{%(py7)s = %(py0)s(token_source=%(py1)s, mergedBy_login=%(py3)s, mergedBy_is_bot=%(py5)s)
} is %(py10)sr   r   )rp   r   r   ry   r{   r   zassert %(py12)spy12N)
r   r   r   r   r   r   r   r   r   r   )r   r   r   @py_assert9r   r   @py_format13s          r&   @test_sanity_decide_autonomy_capability_gap_unknown_is_failclosedrf    sR    - )),  
	  
	   	  
	  v	  	 *   I	 *   v	   *  I *  I -  I   I	   I	    	  r(   c                 4   t        d      } d}| |u}|st        j                  d|fd| |f      dt        j                         v st        j
                  |       rt        j                  |       ndt        j                  |      dz  }dd|iz  }t        t        j                  |            dx}}t        |       }d	}||k(  }|st        j                  d
|fd||f      dt        j                         v st        j
                  t              rt        j                  t              nddt        j                         v st        j
                  |       rt        j                  |       ndt        j                  |      t        j                  |      dz  }dd|iz  }t        t        j                  |            dx}x}}t        | d       d}t        |      }	d}
|	|
u }|st        j                  d|fd|	|
f      dt        j                         v st        j
                  t               rt        j                  t               ndt        j                  |      t        j                  |	      t        j                  |
      dz  }dd|iz  }t        t        j                  |            dx}x}	x}}
d}t        |      }	d}
|	|
u }|st        j                  d|fd|	|
f      dt        j                         v st        j
                  t               rt        j                  t               ndt        j                  |      t        j                  |	      t        j                  |
      dz  }dd|iz  }t        t        j                  |            dx}x}	x}}
y)u;   sanity: token fingerprint는 sha256의 첫 8 hex 문자만.ghs_test_value_xyzNr~   )z%(py0)s is not %(py3)sfprN  r9  ry   r   rk   )z0%(py3)s
{%(py3)s = %(py0)s(%(py1)s)
} == %(py6)sr2   )rp   r   r   rt   r  r      ru   )z0%(py4)s
{%(py4)s = %(py0)s(%(py2)s)
} is %(py7)sr   )rp   rq   rr   r{   zassert %(py9)sr   r1   )r   r   r   r   r   r   r   r   r   r2   r3   )ri  r   r   r   r   rV  r   r   r   r   r   r   r   s                r&   1test_sanity_fingerprint_truncation_to_8_hex_charsrk    s   	$%9	:B2T>2T22Tr7a7a<7a33rr7aBK'+4&t,44,4444,444444&444&444t444,4444444444')2&r*2d2*d2222*d222222&222&222r222*222d2222222r(   c                    t        ddi      } | j                  }|t        k(  }|st        j                  d|fd|t        f      dt        j                         v st        j                  |       rt        j                  |       ndt        j                  |      dt        j                         v st        j                  t              rt        j                  t              nddz  }d	d
|iz  }t        t        j                  |            dx}}t        j                  | j                               }d}||v}|st        j                  d|fd||f      t        j                  |      dt        j                         v st        j                  |      rt        j                  |      nddz  }dd|iz  }	t        t        j                  |	            dx}}d}||v}|st        j                  d|fd||f      t        j                  |      dt        j                         v st        j                  |      rt        j                  |      nddz  }dd|iz  }	t        t        j                  |	            dx}}y)uU   sanity: probe_token_source_from_env() 결과는 raw token 값을 보유하지 않음.r   ghp_abcdefghijk0123456789)rj   rk   rm   rn   r   ro   rs   rt   Nabcdefghijkr   r   r   r   r9  ry   
0123456789)r   r   r   r   r   r   r   r   r   r   r   r6   r7   r   )
rn   r   r   r   r   r   r   r   r   r   s
             r&   =test_sanity_probe_token_source_from_env_no_raw_value_returnedrp    s]   '\;V,WXE7!77777!777777757775777777777!7777!77777777EMMO,J*=
****=
***=******
***
*******)<z))))<z)))<))))))z)))z)))))))r(   c                 p   ddl m}   | t              D ch c]  }|j                   }}h d}|j                  } ||      }|st        j                  d||z
         dz   dt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      dt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      dz  }t        t        j                  |            d	x}}y	c c}w )
uB   sanity: MergeIdentityAuditRecord 회장 §3 필수 7 field 존재.r   )fields>   r   	timestampr   r   r   r   r   zrequired fields missing: zL
>assert %(py5)s
{%(py5)s = %(py2)s
{%(py2)s = %(py0)s.issubset
}(%(py3)s)
}expected_requiredfield_names)rp   rq   r   ry   N)dataclassesrr  r	   nameissubsetr   r   r   r   r   r   r   r   )_fieldsfru  rt  r   r   r   s          r&   Ctest_sanity_merge_identity_audit_record_dataclass_7_required_fieldsr{    s   -#*+C#DEa166EKE %% %k2 2   $$5$C#DE             &      '2    '2    3      Fs   D3c                 r   dt         fdt        fdt        fdt        fdt        fg} d}| D ]d  \  }}t        t        dt        i      }t        |||d	   d
   |d	   d   |j                  di       j                  d            }t        ||      }|j                  }d}| }	||	k(  }
|
st        j                  d|
fd||	f      dt        j                         v st        j                  |      rt        j                   |      ndt        j                   |      t        j                   |      dz  }t        j"                  d| d|j                         dz   d|iz  }t%        t        j&                  |            dx}x}
x}}	|j(                  }g d}||k(  }|st        j                  d|fd||f      dt        j                         v st        j                  |      rt        j                   |      ndt        j                   |      dz  }dd|iz  }t%        t        j&                  |            dx}}y) u   integration: PR #68~#72 5건 모두 owner_pat fallback → score 7→2 (5회 -1).

    회장 §본질 5 연속 패턴 박제. score floor=0 검증.
    rN   rZ   r\   r^   r`   r  r   rh   rV   rQ   rR   rW   rS   r  r  r0   rk   r  r  rx   zPR #u   : 기대 -1, 실제 z
>assert %(py8)sr   N   rL  scorerN  r9  ry   )rY   r[   r]   r_   rb   r   r   r   r5   r   r  r   r   r   r   r   r   r   r   r   r"  )fixturesr~  pr_numfixrn   r   r  r   r   r   r   r   r   r   r   r   s                   r&   ;test_integration_5pr_consecutive_owner_pat_fallback_patternr  2  s    
]	]	]	]	]H E  %9@A
 $z?73j/&1GGGR(,,Y7
 -E&Q{{RqRqbR{b RRR{bRRRRRRuRRRuRRR{RRRqRRRD0DU[[M"RRRRRRRR   5A:5A55Ar(   )r   r1   r1   )r!   r3   r"   rT  r#   rT  r>   r?   )r;   zDict[int, Any])r>   r   )r   r3   r   rX   r>   None)X__doc__
__future__r   builtinsr   _pytest.assertion.rewrite	assertionrewriter   r6   r$   syspathlibr   typingr   r   r   __file__resolveparentrC  rT  pathremoveinsertutils.bot_merge_identityr   r	   r
   r   r   r   r   r   r   r   r   r   r   r   r   utils.merge_queue_executorr   r   utils.repository_policy_adapterr   r   r   r   r   r   r'   rA   rM   rY   __annotations__r[   r]   r_   rb   r   r   r   r   r   r   r   r   r   r   r   r   r   r  r  r2  r7  rJ  rQ  rW  r^  ra  rf  rk  rp  r{  r  r@   r(   r&   <module>r     s  ( #     
  " "
 h'')0077>>~#(("HHOOC'( 3~& '    " e&
(( (&9$2HI!~  (&9$2HI!~  (&9$2HI!~  (&9$2HI!~  (&9$2HI!~  &0 "$. !(8 %(,&1.
B$ 2F5
5
5
5
'H.$/(Y22/ n5!&?3*.r(   