
     jR                       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
mZ ddlZ ee      j                         j                  j                  j                  Z ee      e	j$                  v r!e	j$                  j'                   ee             e	j$                  j)                  d ee             ddlmZmZmZmZmZmZmZ ddlmZmZm Z m!Z!m"Z" ddl#m$Z$m%Z%m&Z&m'Z'm(Z( dZ)d	Z*dd
Z+ejX                  dd       Z-d Z.d Z/ddZ0ejb                  je                  dg d      dd       Z3ejb                  je                  dg d      	 	 	 	 dd       Z4ddZ5d Z6d Z7d Z8d Z9y)u  tests/regression/test_auto_finalize_chain_default_2529.py

회귀 테스트 — task-2529 auto finalize chain default (시스템 결함 fix).

회장 §명시 (2026-05-10):
  봇이 본질 작업과 자체 검증을 완료하면, 회장이 별도로 말하지 않아도 자동으로
  commit → push → PR → CI/Gemini → bot identity merge → smoke → reconcile까지
  진입한다. 명시적 opt-out이 없는 모든 code task는 자동 finalize chain을
  기본값으로 가진다.

회장 §명시 5 회귀 (정확히 5건):
  1. task-2524+1 사례 박제 — 자체 검증 PASS 후 PR 미생성 →
     lifecycle stuck SELF_VERIFIED_BUT_NOT_FINALIZED 자동 분류
  1-b. task-2528 사례 박제 (task-2529+1 보강, 2026-05-10) — 자체 검증 PASS 후
       commit/push/PR 미진입 → lifecycle stuck CODE_DONE_BUT_NO_COMMIT /
       SELF_VERIFIED_BUT_NOT_FINALIZED 자동 분류
  2. task md에 12단계 누락 → wrapper가 footer 자동 삽입
  3. read_only task → finalize 생략
  4. report_only task → finalize 생략
  5. code task → finalize 자동 진입 (footer 삽입 + lifecycle 정상)

본 사건 fixture (회장 §1 / §6 사례):
  - task-2524+1 (dev5 사라스와티, 2026-05-10) — 회귀/구현 PASS 후 PR 미생성
  - task-2528  (dev1 헤르메스, 2026-05-10)   — 자체 검증 PASS 후 커밋/푸시 미진입
                                                ("커밋/푸시는 별도 회장 명령 시 진행하겠습니다")

테스트 카운트 메모 (task-2529+1 정정, 2026-05-10):
  - def test_ 함수: 10개 (task-2528 fixture 추가 후)
  - parametrize 전개 후 실제 pytest collect 카운트: 15개
  - 계산: def 10 + test_regression_3(3 cases - 1) + test_regression_4(4 cases - 1) = 15
  - 봇 보고 기준 task-2529 시점 14는 def 9 + (3-1) + (4-1) = 14 — parametrize collapse가
    아니라 실제 실행 카운트로 일관됐음. 봇 보고 9건은 def test_ 함수 수, 14건은 collect 카운트.
    )annotationsN)Path)AUTO_FINALIZE_FOOTER_MARKERAUTO_FINALIZE_OPT_OUT_TOKENSDispatchStatusauto_inject_finalize_footeris_finalize_opt_outsafe_cron_dispatch"should_auto_inject_finalize_footer)TASK_KIND_BOTTASK_KIND_FOLLOWUP_ROTASK_KIND_HUMAN_RESPONSETASK_KIND_INDEPENDENTTASK_KIND_MERGE)LifecycleEvidenceStuckReasondetect_stuck_casesdetermine_stateLifecycleState
6937032012f3e244a7f4f0d036c                     t        di ddddddddddd	dd
ddddddddddddddddddddddddddddddddddddddd}|j                  |        t        di |S )uW   LifecycleEvidence 기본값 (FINALIZED 직전 상태) → 회귀에서 필드 override.task_idz	task-9999	pr_numberNpr_statemerge_commitmerged_into_mainF	ci_statussmoke_statustimer_statustimer_end_timehas_donehas_done_ackedhas_merge_donehas_qc_resulthas_followuphas_escalate_markerescalate_marker_age_minutestelegram_reply_truncatedbot_session_statusworktree_existsbranch_pushed_to_remoteworktree_mtime_seconds_agohas_pushed_commitsreport_artifact_presentprocess_alivepr_open_age_secondsreport_artifact_age_seconds )dictupdater   )	overridesbases     M/home/jay/workspace/tests/regression/test_auto_finalize_chain_default_2529.py_make_evidencer9   R   s(      	
           "  %)!" "'#$  %& '( !&)* $(+, !-. !&/0 12 !34 %)5D8 	KK	$t$$    c                    | dz  S )u<   production audit-jsonl 오염 방지 — tmp_path에 격리.zcron-targeting-audit.jsonlr3   )tmp_paths    r8   
audit_pathr=   t   s     222r:   c                 
   t        ddddddddddd      } t        |       }|D ch c]  }|j                   }}t        j                  }||v }|st        j                  d|fd||f      d	t        j                         v st        j                  t              rt        j                  t              nd	t        j                  |      d
t        j                         v st        j                  |      rt        j                  |      nd
dz  }t        j                  d|D cg c]  }|j                  j                   c}       dz   d|iz  }t        t        j                  |            dx}}t        j                  }||v }|st        j                  d|fd||f      d	t        j                         v st        j                  t              rt        j                  t              nd	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}}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}}yc c}w c c}w )u   본 사건 fixture: dev5 사라스와티가 회귀/구현 PASS 후 PR 미생성한 사례.

    재발 시 lifecycle_reconciliation_manager가 stuck으로 자동 분류해야 한다.
    ztask-2524+1T     @NF)r   r/   r2   r   r   r   r+   r-   r.   r,   r    inzG%(py2)s
{%(py2)s = %(py0)s.SELF_VERIFIED_BUT_NOT_FINALIZED
} in %(py4)sr   reasonspy0py2py4u;   task-2524+1 본 사건이 stuck 분류되지 않음. cases=
>assert %(py6)spy6z?%(py2)s
{%(py2)s = %(py0)s.CODE_DONE_BUT_NO_COMMIT
} in %(py4)sassert %(py6)s==z=%(py0)s == %(py4)s
{%(py4)s = %(py2)s.STUCK_NEEDS_RECONCILE
}stater   )r9   r   reasonr   SELF_VERIFIED_BUT_NOT_FINALIZED
@pytest_ar_call_reprcompare@py_builtinslocals_should_repr_global_name	_saferepr_format_assertmsgvalueAssertionError_format_explanationCODE_DONE_BUT_NO_COMMITr   r   STUCK_NEEDS_RECONCILE)
evidencecasescrC   @py_assert1@py_assert3@py_format5@py_format7rO   _s
             r8   Ktest_regression_1_task_2524_plus_1_self_verified_but_no_pr_finalize_missingrf      sm   
  $$)#(  %H" x(E!&'Aqxx'G' 66 6'A   6'              7      ;B    ;B    F_dFeZ[qxx~~FeEfg     ..9.'9999.'999999;999;999.999999'999'9999999 x(HE1"8885888885888888858885888888N888N88888888888 ( Gfs   M;#N 
c                 6   t        ddddddddddd      } t        |       }|D ch c]  }|j                   }}g }t        j                  }||v }|}|st        j
                  }||v }	|	}|s%t        j                  d|fd||f      d	t        j                         v st        j                  t              rt        j                  t              nd	t        j                  |      d
t        j                         v st        j                  |      rt        j                  |      nd
dz  }
dd|
iz  }|j                  |       |st        j                  d	fd|f      d	t        j                         v st        j                  t              rt        j                  t              nd	t        j                  |      d
t        j                         v st        j                  |      rt        j                  |      nd
dz  }dd|iz  }|j                  |       t        j                  |d      i z  }t        j                  d|D cg c]  }|j                  j                   c}       dz   d|iz  }t!        t        j"                  |            dx}x}x}x}x}}	t        j
                  }||v }|st        j                  d|fd||f      d	t        j                         v st        j                  t              rt        j                  t              nd	t        j                  |      d
t        j                         v st        j                  |      rt        j                  |      nd
dz  }t        j                  d|D cg c]  }|j                   c}       dz   d|iz  }
t!        t        j"                  |
            dx}}t        j                  }||v }|st        j                  d|fd||f      d	t        j                         v st        j                  t              rt        j                  t              nd	t        j                  |      d
t        j                         v st        j                  |      rt        j                  |      nd
dz  }t        j                  d|D cg c]  }|j                   c}       dz   d|iz  }
t!        t        j"                  |
            d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}}yc c}w c c}w c c}w c c}w )"u^  task-2528 사례 박제 — 자체 검증 PASS 후 commit/push/PR 미진입.

    회장 §6 (2026-05-10) 명시 충족: task-2524 / task-2528 사례 모두 회귀 fixture에 박제.
    회장 §명시 (2026-05-10): "lifecycle stuck enum 또는 audit log만으로 task-2528
    fixture 충족을 대체하지 않는다" → 명시 def test_ 함수로 박제.

    Source:
      - dev1 헤르메스, 2026-05-10 — 자체 검증 보고서(memory/reports/task-2528.md) 작성 후
        commit/push 단계 미진입.
      - 봇 명시 발언: "커밋/푸시는 별도 회장 명령 시 진행하겠습니다"
        (auto-finalize-chain-missing-260510.jsonl).
      - 결과: AUTO_FINALIZE_CHAIN_MISSING audit log 생성, 회장 §결정으로 task-2528+1 발행.

    재발 시 lifecycle_reconciliation_manager가 자동으로 stuck 분류해야 한다.
    z	task-2528Tr?   FN)r   r/   r2   r.   r,   r   r   r   r+   r-   r    r@   )zG%(py4)s
{%(py4)s = %(py2)s.SELF_VERIFIED_BUT_NOT_FINALIZED
} in %(py6)sr   rC   )rF   rG   rI   z%(py8)spy8)zC%(py12)s
{%(py12)s = %(py10)s.CODE_DONE_BUT_NO_COMMIT
} in %(py14)s)py10py12py14z%(py16)spy16   u9   task-2528 본 사건이 stuck 분류되지 않음. cases=z
>assert %(py19)spy19rJ   rD   u[   CODE_DONE_BUT_NO_COMMIT 미분류 — task-2528은 commit 단계 미진입 사례. reasons=rH   rI   rB   uk   SELF_VERIFIED_BUT_NOT_FINALIZED 미분류 — task-2528은 자체 검증 PASS 후 finalize 미완. reasons=rL   rN   rO   r   rK   )r9   r   rP   r   rQ   r\   rR   rS   rT   rU   rV   rW   append_format_booloprX   rY   rZ   r[   r   r   r]   )r^   r_   r`   rC   ra   rb   @py_assert5@py_assert0@py_assert11@py_assert13rd   @py_format9@py_format15@py_format17@py_format18@py_format20rc   rrO   re   s                       r8   Qtest_regression_1b_task_2528_dev1_hermes_self_verified_but_finalize_chain_missingr{      s      $$) ! %#(#H( x(E!&'Aqxx'G'333w>...'9  3w     	   	   	4     8?   8?    .'    	   	   	 /    	 3:  	 3:      */0Q!((..01	3	      .. .'9   .'              /      3:    3:   %,-AGG-.	0     66 6'A   6'              7      ;B    ;B   %,-AGG-.	0     x(HE1"8885888885888888858885888888N888N888888888885 ( 1 . .s   XX
X
5X
c           	        d}t         |v}|st        j                  d|fdt         |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dz  }dd|iz  }t        t        j                  |            d	}t        |      }| }|sd
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                  |      dz  }t        t        j                  |            d	x}}t        |dt        t        t        d	|       }|j                  }t        j                   }||k(  }	|	st        j                  d|	fd||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t        j                  |      dz  }
t        j"                  d|j$                         dz   d|
iz  }t        t        j                  |            d	x}x}	}t'        |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}}|j+                  d      }||dz      }t         |v }|st        j                  d|fdt         |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 dz  }t        j"                  d!      d"z   d|iz  }t        t        j                  |            d	}d#D ]  }||v }|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  }t        j"                  d%|d&      d"z   d|iz  }t        t        j                  |            d	} y	)'u   task md (cron prompt)에 finalize chain 명시가 빠져 있으면 wrapper가 footer를 자동 삽입.

    safe_cron_dispatch가 ALLOWED 상태로 진입하고 audit/preview에 footer가 포함된다.
    uM   [task-9001] dev2 indra: utils/feature_x.py에 새 helper 추가 + 회귀 3건not inz%(py0)s not in %(py2)sr   bare_promptrE   rF   assert %(py4)srG   Nz0assert not %(py3)s
{%(py3)s = %(py0)s(%(py1)s)
}r	   rE   py1py32mpromptschedulechattarget_bot_key	task_kind
session_idr=   rL   zK%(py2)s
{%(py2)s = %(py0)s.status
} == %(py6)s
{%(py6)s = %(py4)s.ALLOWED
}resultr   rE   rF   rG   rI   uC   footer 자동 삽입은 preflight 통과해야 함. blocked_reason=z
>assert %(py8)srh   --cronr@   )z%(py1)s in %(py3)sargv)r   r   assert %(py5)spy5rm   z%(py0)s in %(py2)sinjected_promptu3   wrapper가 footer를 prompt 끝에 삽입해야 함
>assert %(py4)s)commitpushPRmergesmoke	reconcilekeywordu
   footer에 u    누락)r   rR   rS   rT   rU   rV   rW   rZ   r[   r	   r
   
CHAIR_CHATDEV2_INDRA_KEYr   statusr   ALLOWEDrX   blocked_reasonlistcommand_argvindex)r=   r   ra   @py_format3rc   @py_assert2@py_assert4r   rq   rb   rd   ru   r   rr   @py_format4@py_format6cron_idxr   r   s                      r8   Atest_regression_2_task_md_missing_12_steps_wrapper_injects_footerr      s   
 bK 'k9999&k999999&999&999999k999k9999999";///////////"///"//////;///;//////////%F == N22 =22   =2                    +    +    3    NfNcNcMde    
 ##$D8t8t8ttzz(#H8a<(O&/9  &/      '    '      +:    +:    	>     K K/)JJJw/JJJJJJwJJJwJJJJJJ/JJJ/JJJJZ{'+JJJJJJJKr:   opt_out_phrase)zread_only: truezread_only:truezREAD_ONLY: TRUEc           	         d|  d}t        |      }|st        j                  d|       dz   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                  |      dz  }t        t        j                  |            d}t        t        |      }| }|sd	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dt        j                         v st        j
                  |      rt        j                  |      ndt        j                  |      dz  }t        t        j                  |            dx}}t        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  }
t        j                  d      dz   d|
iz  }t        t        j                  |            d}	t        |v}	|	st        j                  d|	fdt        |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dz  }
dd|
iz  }t        t        j                  |            d}	t        |dt        t         t        d|      }|j"                  }	t$        j&                  }|	|k(  }|st        j                  d|fd|	|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t        j                  |      dz  }dd|iz  }t        t        j                  |            dx}	x}}t)        |j*                        j-                  d       }|j*                  |d!z      }t        |v}	|	st        j                  d|	fd"t        |f      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}	}y)&uX   read_only opt-out이 명시된 task는 자동 finalize footer가 삽입되지 않는다.u   [task-9002] audit only — u   

status scan 후 보고.   opt-out 토큰 인식 실패: .
>assert %(py3)s
{%(py3)s = %(py0)s(%(py1)s)
}r	   r   r   Nz9assert not %(py4)s
{%(py4)s = %(py0)s(%(py1)s, %(py2)s)
}r   r   )rE   r   rF   rG   rL   z%(py0)s == %(py2)soutr   u8   read_only task에 footer가 삽입됨 — opt-out 위반r   rG   r}   r   r   r   r   r   r   r   r   r   assert %(py8)srh   r   rm   z%(py0)s not in %(py3)srE   r   r   r   )r	   rR   rX   rT   rU   rV   rW   rZ   r[   r   r   r   rS   r   r
   r   r   r   r   r   r   r   r   )r   r=   r   r   r   rb   rq   r   r   ra   r   rc   r   rd   ru   r   s                   r8   /test_regression_3_read_only_task_skips_finalizer     sR    +>*::UVFv&[&[[*HHZ([[[[[[[[[[[[[[[[v[[[v[[[&[[[[[[1-HHHHHHHHHHH1HHH1HHHHHH-HHH-HHHHHHHHHHHHHHHHHHH &mV
<C&=TTT3&TTTTTT3TTT3TTTTTT&TTT&TTTTTTTTTTT&c1111&c111111&111&111111c111c1111111  %F ==2N222=22222=222222262226222=222222N222N22222222222F''(..x8H.4.A.A(Q,.OO&.OOOOO&.OOOOOOO&OOO&OOO.OOOOOOOOr:   )zreport_only: truezanalysis_only: truezfinalize_policy: no_przfinalize_policy:no_prc           	     	   d|  d}t        |      }|st        j                  d|       dz   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                  |      dz  }t        t        j                  |            d}t        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}t        |v}|st        j                  d|fdt        |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dz  }dd|iz  }t        t        j                  |            d}t        |dt        t        t        d|      }	|	j                   }t"        j$                  }
||
k(  }|st        j                  d	|fd||
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t        j                  |
      dz  }dd|iz  }t        t        j                  |            dx}x}}
t'        |	j(                        j+                  d      }|	j(                  |dz      }t        |v}|st        j                  d|fdt        |f      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}}y) uS   report_only / analysis_only / finalize_policy:no_pr 모두 finalize 생략 default.u#   [task-9003] retrospective task — u   

회고만 작성.r   r   r	   r   r   NrL   r   r   r   r   rG   r}   r   r   r   r   r   r   r   r   r   rh   r   rm   r   r   r   r   )r	   rR   rX   rT   rU   rV   rW   rZ   r[   r   r   rS   r   r
   r   r   r   r   r   r   r   r   )r   r=   r   r   r   r   ra   r   rc   r   rq   rb   rd   ru   r   r   s                   r8   =test_regression_4_report_only_and_analysis_only_skip_finalizer   C  s    3>2BBWXFv&[&[[*HHZ([[[[[[[[[[[[[[[[v[[[v[[[&[[[[[[
%&;V
DC&=3&33&&&c1111&c111111&111&111111c111c1111111%'F ==2N222=22222=222222262226222=222222N222N22222222222F''(..x8H.4.A.A(Q,.OO&.OOOOO&.OOOOOOO&OOO&OOO.OOOOOOOOr:   c                   d}t         t        t        fD ]  }t        ||      }||k7  }|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  }t	        j                  | d      dz   d	|iz  }t        t	        j                  |            d
}t        |v }|st	        j
                  d|fdt        |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dz  }dd	|iz  }t        t	        j                  |            d
}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  }t	        j                  | d      dz   d	|iz  }t        t	        j                  |            d
}|j                  } |t              }d}	||	k(  }
|
s
t	        j
                  d|
fd||	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t	        j                  |      t	        j                  |	      dz  }dd|iz  }t        t	        j                  |            d
x}x}x}
}	  t        t         fD ]  }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  }t	        j                  | d      dz   d	|iz  }t        t	        j                  |            d
} t#        |dt$        t&        t        d
|       }|j(                  }t*        j,                  }||k(  }|st	        j
                  d|fd||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t	        j                  |      dz  }dd |iz  }t        t	        j                  |            d
x}x}}t/        |j0                        j3                  d!      }|j0                  |dz      }t        |v }|st	        j
                  d|fdt        |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"dz  }dd	|iz  }t        t	        j                  |            d
}t5        d#d$d%d&d'd(d)d*d+d'd'd'd'd',      }t7        |      \  }}t8        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                  t8              rt	        j                  t8              nd/t	        j                  |      d0z  }d1d2|iz  }t        t	        j                  |            d
x}}g }||k(  }|st	        j
                  d|fd3||f      d4t        j                         v st	        j                  |      rt	        j                  |      nd4t	        j                  |      d5z  }t	        j                  d6|D cg c]  }|j<                  j>                   c}       d7z   d8|iz  }t        t	        j                  |            d
x}}y
c c}w )9u[   code task (independent / merge / bot) 모두 footer 자동 삽입 + finalize 박제 정합.u1   [task-9004] dev2: utils/foo.py 변경 + 회귀 +1)!=)z%(py0)s != %(py2)sr   code_promptr   u   에서 footer 미삽입r   rG   Nr@   r   r   r   rL   r   twiceu    footer 멱등성 위반rm   )zK%(py5)s
{%(py5)s = %(py2)s
{%(py2)s = %(py0)s.count
}(%(py3)s)
} == %(py8)s)rE   rF   r   r   rh   zassert %(py10)sri   u)   는 footer 자동 삽입 대상이 아님r   r   r   r   r   r   r   rh   r   final_promptz	task-9004c   MERGED
abc1234567TSUCCESSPASS	completedz2026-05-10T12:00:00Z)r   r   r   r   r   r   r   r    r!   r"   r#   r$   r%   r/   )z1%(py0)s == %(py4)s
{%(py4)s = %(py2)s.FINALIZED
}rO   r   rD   rK   rI   )z%(py0)s == %(py3)sstuckr   u   FINALIZED 상태에서 stuck 분류는 0건이어야 함 — AUTO_FINALIZE_CHAIN_MISSING 4종이 false positive로 잡히면 안 됨. got: z
>assert %(py5)sr   ) r   r   r   r   rR   rS   rT   rU   rV   rW   rX   rZ   r[   r   countr   r   r
   r   r   r   r   r   r   r   r   r9   r   r   	FINALIZEDrP   rY   )r=   r   kindr   ra   r   rc   r   r   @py_assert7@py_assert6ru   @py_format11r   rq   rb   rd   r   r   finalized_evidencerO   r   r   r   sr   s                             r8   6test_regression_5_code_task_auto_enters_finalize_chainr   j  s   EK 'G =)$<k!CCCskCCCCCCsCCCsCCCCCCkCCCkCCCCdV+B#CCCCCCC*c1111*c111111*111*111111c111c1111111+D#6|>>>u>>>>>>u>>>u>>>>>>>>>>>>>v%=>>>>>>>{{<{67<1<71<<<<71<<<<<<u<<<u<<<{<<<<<<6<<<6<<<7<<<1<<<<<<<= '(@A V)$<k!UUUskUUUUUUsUUUsUUUUUUkUUUkUUUUdV+T#UUUUUUUV
  %F ==2N222=22222=222222262226222=222222N222N22222222222F''(..x8H&&x!|4L&,6666&,666666&666&666666,666,6666666 (! - $  ##56LE5",,,5,,,,,5,,,,,,,5,,,5,,,,,,N,,,N,,,,,,,,,,, 5B;  	5B   	  	    	    	    	)./A/0	2   	  0s    e1
c                    h d} t         D ch c]$  }|j                  d      d   j                         & }}| |z
  }| }|s~t        j                  d|       dz   ddt        j                         v st        j                  |      rt        j                  |      ndiz  }t        t        j                  |            d}yc c}w )	u`   회장 §명시 4 opt-out 토큰이 모두 카탈로그에 박제되어 있는지 정적 검증.>   	read_onlyreport_onlyanalysis_onlyfinalize_policy:r   u$   opt-out 토큰 카탈로그 누락: 
>assert not %(py0)srE   missingN)r   splitstriprR   rX   rT   rU   rV   rW   rZ   r[   )expected_logicaltokfoundr   ra   @py_format2s         r8   (test_opt_out_tokens_catalog_completenessr     s    W2NO3SYYs^A$$&OEO&G;H;HH>wiHHHHHHHwHHHwHHHHHH Ps   )Cc                 V   t        di ddddddddd	d
dddddd
dd
dd
dddd
dddd
dd
dd} t        |       }t        j                  t        j                  t        j
                  t        j                  h}|D ch c]  }|j                   c}|z  }| }|s~t        j                  d|       dz   ddt        j                         v st        j                  |      rt        j                  |      ndiz  }t        t        j                  |            d}yc c}w ) ui   이미 PR이 MERGED인 task evidence는 AUTO_FINALIZE_CHAIN_MISSING 4종 어느 것도 잡히면 안 됨.r   z	task-9005r   d   r   r   r   
def4567890r   Tr   r   r   r   r"   r#   r$   r    r   r/   r2   g    ~.Ar.   r,   r-   uP   PR_MERGED 상태에서 AUTO_FINALIZE_CHAIN_MISSING이 false positive로 잡힘: r   rE   	triggeredNr3   )r9   r   r   r\   COMMIT_DONE_BUT_NO_PRPR_OPEN_BUT_NO_MERGE_ATTEMPTrQ   rP   rR   rX   rT   rU   rV   rW   rZ   r[   )merged_evidencer_   auto_finalize_reasonsr`   r   ra   r   s          r8   9test_auto_finalize_does_not_inject_for_merged_pr_evidencer     sv   $   "	
       ! !% %-   !%  $,!O$ /E++))0033	 $))a),AAI= =   [[dZef               *s   D&c                    t        ddddddddd	      } t        |       }|D ch c]  }|j                   }}t        j                  }||v }|st        j                  d	|fd
||f      dt        j                         v st        j                  t              rt        j                  t              nd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c c}w )uQ   PR_OPEN_BUT_NO_MERGE_ATTEMPT — pr_state=OPEN + ci=SUCCESS + 5분+ 경과한 PR.z	task-9006   OPENNr   r?   T)	r   r   r   r   r   r1   r+   r,   r.   r@   )zD%(py2)s
{%(py2)s = %(py0)s.PR_OPEN_BUT_NO_MERGE_ATTEMPT
} in %(py4)sr   rC   rD   u@   PR_OPEN + CI SUCCESS + 10분 경과인데 stuck 분류 안 됨: rH   rI   )r9   r   rP   r   r   rR   rS   rT   rU   rV   rW   rX   rZ   r[   stuck_evidencer_   r`   rC   ra   rb   rc   rd   s           r8   +test_pr_open_but_no_merge_attempt_detectionr     s+   #! $
N ~.E!&'Aqxx'G'33 3w>  3w              4      8?    8?    K7)T     (s   Ec            
        t        dddddddd      } t        |       }|D ch c]  }|j                   }}t        j                  }||v }|st        j                  d|fd||f      dt        j                         v st        j                  t              rt        j                  t              nd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c c}w )uI   COMMIT_DONE_BUT_NO_PR — branch push되었지만 PR 없고 5분+ 경과.z	task-9007NTr?   )r   r   r   r   r+   r,   r.   r-   r@   )z=%(py2)s
{%(py2)s = %(py0)s.COMMIT_DONE_BUT_NO_PR
} in %(py4)sr   rC   rD   uD   branch_push + PR missing + 10분 경과인데 stuck 분류 안 됨: rH   rI   )r9   r   rP   r   r   rR   rS   rT   rU   rV   rW   rX   rZ   r[   r   s           r8   $test_commit_done_but_no_pr_detectionr     s(   # $#(	N ~.E!&'Aqxx'G',, ,7  ,              -      18    18    OwiX     (s   E)returnr   )r<   r   r   r   )r=   r   )r   strr=   r   ):__doc__
__future__r   builtinsrT   _pytest.assertion.rewrite	assertionrewriterR   syspathlibr   pytest__file__resolveparent_WORKTREE_ROOTr   pathremoveinsertscripts.safe_cron_dispatchr   r   r   r   r	   r
   r   utils.cron_targeting_auditr   r   r   r   r   &utils.lifecycle_reconciliation_managerr   r   r   r   r   r   r   r9   fixturer=   rf   r{   r   markparametrizer   r   r   r   r   r   r   r3   r:   r8   <module>r     sh   B #   
  
 h'')0077>>~#(("HHOOC'( 3~& '     
#%D 3 3"9V?9L%KX PP> PP%)PP<:BIB(r:   