
     j t                    4   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 ddlZ ee      j%                         j&                  j&                  j&                  Z ee      ej,                  v r!ej,                  j/                   ee             ej,                  j1                  d ee             ddlmZmZmZmZmZmZm Z  ddZ! G d d	      Z" G d
 d      Z# G d d      Z$ G d d      Z% G d d      Z& G d d      Z' G d d      Z(y)u   tests/regression/test_lifecycle_reconciliation_manager_2518.py — 14 회귀 + 5 replay fixture.

회장 명시 P0: lifecycle state machine + bot session decoupling + source-of-truth + idempotent reconcile.
    )annotationsN)Path)Any)LifecycleStateStuckReasonLifecycleEvidencedetermine_statedetect_stuck_cases	reconcileassert_no_manual_done_forgeryc                     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}|j                  |        t        di |S )zIDefault 'clean baseline' evidence; tests override fields they care about.task_id	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 )dictupdater   )	overridesbases     R/home/jay/workspace/tests/regression/test_lifecycle_reconciliation_manager_2518.pymake_evidencer)   $   s       	
           "  %)!" "'#$  %& '( !&)D, 	KK	$t$$    c                      e Zd ZdZd Zy)TestLifecycleStateEnumu,   A-1. LifecycleState enum 7종 멤버 검증.c           	     4   h d}t         D ch c]  }|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                  |      rt        j                  |      nddz  }t        j                  d| d|       d	z   d
|iz  }t        t        j                  |            d}t        t               }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                  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                  |	      dz  }dd|iz  }t        t        j                  |            dx}x}x}
}	yc c}w )u7   회장 명시: LifecycleState가 정확히 7종 멤버.>   PR_OPENRUNNING	ESCALATED	FINALIZEDRECONCILINGSTUCK_NEEDS_RECONCILEMERGED_PENDING_RECONCILE==)z%(py0)s == %(py2)sactualexpected)py0py2u/   LifecycleState enum 멤버 불일치: expected=	, actual=z
>assert %(py4)spy4N   zN%(py6)s
{%(py6)s = %(py0)s(%(py4)s
{%(py4)s = %(py1)s(%(py2)s)
})
} == %(py9)slenlistr   r9   py1r:   r<   py6py9zassert %(py11)spy11)r   value
@pytest_ar_call_reprcompare@py_builtinslocals_should_repr_global_name	_saferepr_format_assertmsgAssertionError_format_explanationr@   r?   )selfr8   memberr7   @py_assert1@py_format3@py_format5@py_assert3@py_assert5@py_assert8@py_assert7@py_format10@py_format12s                r(   'test_lifecycle_state_enum_seven_membersz>TestLifecycleStateEnum.test_lifecycle_state_enum_seven_membersG   s   
 .<<6&,,<<! 	
 	
v 	
 	
	6	
 	
   	
 	
 		  	
 	
	6	
 	
  " 	
 	
 		 " 	
 	
  >hZyQWPXY	
 	
 	
 	
 	
 '-s'(-A-(A----(A------s---s------4---4------------'---(---A-------	 =s   JN)__name__
__module____qualname____doc__r[   r#   r*   r(   r,   r,   D   s
    6.r*   r,   c                  "    e Zd ZdZd Zd Zd Zy)TestSourceOfTruthu1   A-2~4. source-of-truth evidence → state 결정.c                   t        ddddddddd	      }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  }t	        j                  d|       dz   d|iz  }t        t	        j                  |            dx}}g }||k(  }|st	        j
                  d|fd||f      dt        j                         v st	        j                  |      rt	        j                  |      ndt	        j                  |      dz  }	t	        j                  d|       dz   d|	iz  }
t        t	        j                  |
            dx}}y)uh   A-2: PR merged + ci PASS + smoke PASS + has_done_acked + has_merge_done + timer completed → FINALIZED.MERGED4d45947eaabbccddTSUCCESSPASS	completed)	r   r   r   r   r   r   r   r   r   r5   )z1%(py0)s == %(py4)s
{%(py4)s = %(py2)s.FINALIZED
}stater   r9   r:   r<   u   FINALIZED 기대, 실제: 
>assert %(py6)srC   N)z%(py0)s == %(py3)sstuck_casesr9   py3u+   FINALIZED에는 stuck_cases 없어야 함: 
>assert %(py5)spy5)r)   r	   r   r1   rG   rH   rI   rJ   rK   rL   rM   rN   rO   )rP   evidencerh   rk   rU   rR   rT   @py_format7@py_assert2@py_format4@py_format6s              r(   /test_source_of_truth_merged_smoke_pass_finalizezATestSourceOfTruth.test_source_of_truth_merged_smoke_pass_finalize\   s    +!$

 -X6{&00 	
u00 	
 	
u0 	
 	
	6	
 	
   	
 	
 		  	
 	
	6	
 	
  ' 	
 	
 		 ' 	
 	
 		 1 	
 	
  )0	
 	
 	
 	
 	
 !]{b ]]]{b]]]]]]{]]]{]]]b]]]$OP[}"]]]]]]]r*   c                h   t        ddd      }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  }t	        j                  d
|       dz   d|iz  }t        t	        j                  |            dx}}y)u9   A-3: timer running + PR OPEN → RUNNING 유지 (정상).OPEN*   running)r   r   r   r5   )z/%(py0)s == %(py4)s
{%(py4)s = %(py2)s.RUNNING
}rh   r   ri   u2   RUNNING 기대 (PR OPEN + timer running), 실제: rj   rC   N)r)   r	   r   r/   rG   rH   rI   rJ   rK   rL   rM   rN   rO   )rP   rp   rh   _stuckrU   rR   rT   rq   s           r(   2test_source_of_truth_timer_running_pr_open_runningzDTestSourceOfTruth.test_source_of_truth_timer_running_pr_open_runningo   s    "

 (1v&.. 	
u.. 	
 	
u. 	
 	
	6	
 	
   	
 	
 		  	
 	
	6	
 	
  ' 	
 	
 		 ' 	
 	
 		 / 	
 	
  AH	
 	
 	
 	
 	
r*   c                \   t        dddd      }t        |      \  }}t        j                  t        j                  h}||v }|st        j                  d|fd||f      dt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      d	z  }t        j                  d
|       dz   d|iz  }t        t        j                  |            dx}}|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 )u   A-4: timer running인데 PR MERGED → GitHub 우선, state ∈ {STUCK_NEEDS_RECONCILE, MERGED_PENDING_RECONCILE}.

        timer는 stuck signal 또는 backfill 대상.
        rc   11223344aabbccddTry   )r   r   r   r   inz%(py0)s in %(py3)srh   rl   uK   GitHub PR MERGED > timer running 우선순위 반영 필요, 실제 state: rn   ro   NzC%(py2)s
{%(py2)s = %(py0)s.TIMER_RUNNING_BUT_PR_MERGED
} in %(py4)sr   stuck_reasonsri   u?   TIMER_RUNNING_BUT_PR_MERGED stuck case 기대, actual reasons: rj   rC   )r)   r	   r   r3   r4   rG   rH   rI   rJ   rK   rL   rM   rN   rO   reasonr   TIMER_RUNNING_BUT_PR_MERGED)rP   rp   rh   rk   rr   rR   rs   rt   scr   rU   rT   rq   s                r(   (test_evidence_conflict_github_over_timerz:TestSourceOfTruth.test_evidence_conflict_github_over_timer{   s   
 !+!"	
 -X6{0033
 	
u 
 
 	

 	
u 
 	
 	

 
6	
 	

   	
 	

 
	  	
 	

 
	
 	
 	

  ZZ_Y`a		
 	
 	

 	
 	
 .99r9966 	
6-G 	
 	
6- 	
 	
	6	
 	
   	
 	
 		  	
 	
 		 7 	
 	
	6	
 	
  ;H 	
 	
 		 ;H 	
 	
  Nm_]	
 	
 	
 	
 	
 :s   >H)N)r\   r]   r^   r_   ru   r{   r   r#   r*   r(   ra   ra   Y   s    ;^&


r*   ra   c                  @    e Zd ZdZd Zd Zd Zd Zd Zd Z	d Z
d	 Zy
)TestStuckDetectionuC   B. stuck detection 8 케이스 — 회장 §1~7 + Telegram cut-off.c                   t        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 )uj   B-5: timer running + PR merged → TIMER_RUNNING_BUT_PR_MERGED 감지 (회장 §2, task-2517 dev2 사례).rc   d   abcdef99Fry   r   r   r   r   r   r~   r   r   reasonsri   u,   TIMER_RUNNING_BUT_PR_MERGED 기대, actual: rj   rC   N)r)   r
   r   r   r   rG   rH   rI   rJ   rK   rL   rM   rN   rO   	rP   rp   casesr   r   rR   rU   rT   rq   s	            r(   &test_stuck_timer_running_but_pr_mergedz9TestStuckDetection.test_stuck_timer_running_but_pr_merged   s%    #""
 #8,',-299--66 	
6'A 	
 	
6' 	
 	
	6	
 	
   	
 	
 		  	
 	
 		 7 	
 	
	6	
 	
  ;B 	
 	
 		 ;B 	
 	
  ;7)D	
 	
 	
 	
 	
 .   Ec           	        t        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   B-6: PR merged + .done 없음 → PR_MERGED_BUT_DONE_MISSING 감지 (회장 §1).rc      abcdef12TFr   r   r   r   r   r   r   r~   zB%(py2)s
{%(py2)s = %(py0)s.PR_MERGED_BUT_DONE_MISSING
} in %(py4)sr   r   ri   u+   PR_MERGED_BUT_DONE_MISSING 기대, actual: rj   rC   N)r)   r
   r   r   PR_MERGED_BUT_DONE_MISSINGrG   rH   rI   rJ   rK   rL   rM   rN   rO   r   s	            r(   %test_stuck_pr_merged_but_done_missingz8TestStuckDetection.test_stuck_pr_merged_but_done_missing   s+    #!  
 #8,',-299--55 	
5@ 	
 	
5 	
 	
	6	
 	
   	
 	
 		  	
 	
 		 6 	
 	
	6	
 	
  :A 	
 	
 		 :A 	
 	
  :'C	
 	
 	
 	
 	
 .   Ec                   t        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   B-7: mergeCommit 존재 + .merge-done 없음 → MERGE_COMMIT_BUT_MERGE_DONE_MISSING 감지 (회장 §1).rc   deadbeef12345678TF)r   r   r   r   r~   zK%(py2)s
{%(py2)s = %(py0)s.MERGE_COMMIT_BUT_MERGE_DONE_MISSING
} in %(py4)sr   r   ri   u4   MERGE_COMMIT_BUT_MERGE_DONE_MISSING 기대, actual: rj   rC   N)r)   r
   r   r   #MERGE_COMMIT_BUT_MERGE_DONE_MISSINGrG   rH   rI   rJ   rK   rL   rM   rN   rO   r   s	            r(   .test_stuck_merge_commit_but_merge_done_missingzATestStuckDetection.test_stuck_merge_commit_but_merge_done_missing   s%    +! 	
 #8,',-299-->> 	
>'I 	
 	
>' 	
 	
	6	
 	
   	
 	
 		  	
 	
 		 ? 	
 	
	6	
 	
  CJ 	
 	
 		 CJ 	
 	
  C7)L	
 	
 	
 	
 	
 .s   E
c           	        t        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 )ue   B-8: PR merged + CI PASS + smoke PASS + .done.acked/.merge-done 누락 → CI_PASS_BUT_NOT_FINALIZED.rc   cafebabe12341234Tre   rf   F)r   r   r   r   r   r   r   r~   )zA%(py2)s
{%(py2)s = %(py0)s.CI_PASS_BUT_NOT_FINALIZED
} in %(py4)sr   r   ri   u*   CI_PASS_BUT_NOT_FINALIZED 기대, actual: rj   rC   N)r)   r
   r   r   CI_PASS_BUT_NOT_FINALIZEDrG   rH   rI   rJ   rK   rL   rM   rN   rO   r   s	            r(   $test_stuck_ci_pass_but_not_finalizedz7TestStuckDetection.test_stuck_ci_pass_but_not_finalized   s+    +!  
 #8,',-299--44 	
4? 	
 	
4 	
 	
	6	
 	
   	
 	
 		  	
 	
 		 5 	
 	
	6	
 	
  9@ 	
 	
 		 9@ 	
 	
  9	B	
 	
 	
 	
 	
 .r   c                   t        d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 )uu   B-9: cron history 마지막 라인 truncated → TELEGRAM_REPLY_CUT_OFF 감지 (task-2517 dev2 cron 2BAB8982 패턴).	task-2517rc   4d45947eTre   rf   rg   )
r   r   r   r   r   r   r   r   r   r   r~   z>%(py2)s
{%(py2)s = %(py0)s.TELEGRAM_REPLY_CUT_OFF
} in %(py4)sr   r   ri   u'   TELEGRAM_REPLY_CUT_OFF 기대, actual: rj   rC   Nr)   r
   r   r   TELEGRAM_REPLY_CUT_OFFrG   rH   rI   rJ   rK   rL   rM   rN   rO   r   s	            r(   !test_stuck_telegram_reply_cut_offz4TestStuckDetection.test_stuck_telegram_reply_cut_off   s2    #!$%)
 #8,',-299--11 	
1W< 	
 	
1W 	
 	
	6	
 	
   	
 	
 		  	
 	
 		 2 	
 	
	6	
 	
  6= 	
 	
 		 6= 	
 	
  6gY?	
 	
 	
 	
 	
 .s   Ec                   dD ]N  }t        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|       dz   d|iz  }	t        t        j                  |	            dx}}Q yc c}w )ur   B-10: cron status=cancelled/error + task evidence 정상(merged_into_main=True) → BOT_SESSION_ENDED_BUT_TASK_OK.)	cancellederrorrc   aabbccdd11223344T)r   r   r   r    r~   )zE%(py2)s
{%(py2)s = %(py0)s.BOT_SESSION_ENDED_BUT_TASK_OK
} in %(py4)sr   r   ri   u9   BOT_SESSION_ENDED_BUT_TASK_OK 기대 (bot_session_status=z), actual: rj   rC   N)r)   r
   r   r   BOT_SESSION_ENDED_BUT_TASK_OKrG   rH   rI   rJ   rK   rL   rM   rN   rO   )
rP   statusrp   r   r   r   rR   rU   rT   rq   s
             r(   (test_stuck_bot_session_ended_but_task_okz;TestStuckDetection.test_stuck_bot_session_ended_but_task_ok   s=   , 	F$!/!%#)	H 'x0E+01Rryy1G1<< <G  <  v     I   I =  v   AH  I AH    LF8S^_f^gh    	 2s   Ec                   t        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 )u[   B-11: worktree 존재 + branch_pushed_to_remote + PR 미생성 → FINISH_TASK_INTERRUPTED.TNr!   r"   r   r~   z?%(py2)s
{%(py2)s = %(py0)s.FINISH_TASK_INTERRUPTED
} in %(py4)sr   r   ri   u(   FINISH_TASK_INTERRUPTED 기대, actual: rj   rC   r)   r
   r   r   FINISH_TASK_INTERRUPTEDrG   rH   rI   rJ   rK   rL   rM   rN   rO   r   s	            r(   "test_stuck_finish_task_interruptedz5TestStuckDetection.test_stuck_finish_task_interrupted   s     $(

 #8,',-299--22 	
2g= 	
 	
2g 	
 	
	6	
 	
   	
 	
 		  	
 	
 		 3 	
 	
	6	
 	
  7> 	
 	
 		 7> 	
 	
  7wi@	
 	
 	
 	
 	
 .   E	c                   t        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   B-12: has_escalate_marker + age > 30분 + Critical 7종 매칭 evidence 없음 → STALE_ESCALATE_MARKER.Tg     F@re   rc   )r   r   r   r   r   r~   )z=%(py2)s
{%(py2)s = %(py0)s.STALE_ESCALATE_MARKER
} in %(py4)sr   r   ri   uF   STALE_ESCALATE_MARKER 기대 (age=45min, no active critical), actual: rj   rC   N)r)   r
   r   r   STALE_ESCALATE_MARKERrG   rH   rI   rJ   rK   rL   rM   rN   rO   r   s	            r(    test_stuck_stale_escalate_markerz3TestStuckDetection.test_stuck_stale_escalate_marker  s&     $(,!
 #8,',-299--00 	
0G; 	
 	
0G 	
 	
	6	
 	
   	
 	
 		  	
 	
 		 1 	
 	
	6	
 	
  5< 	
 	
 		 5< 	
 	
  UU\T]^	
 	
 	
 	
 	
 .r   N)r\   r]   r^   r_   r   r   r   r   r   r   r   r   r#   r*   r(   r   r      s-    M

"

"
(

r*   r   c                  "    e Zd ZdZd Zd Zd Zy)TestIdempotentAndForgeryBlocku5   C. idempotent reconcile + manual .done 위장 차단.c                   dd}dd}g }t        d      D ]#  }t        dd|||      }|j                  |       % |D ch c]  }|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                  |
      dz  }t        j                  d|D cg c]  }|j                   c}       dz   d|iz  }t        t        j                  |            dx}	x}}
t        |      D ]  \  }}|j                  }g }||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z    d|j                         dz   d|iz  }t        t        j                  |            dx}x}} |d   }|j                   }	d}
|	|
u }|st        j                  d|fd|	|
f      t        j                  |      t        j                  |	      t        j                  |
      dz  }dd|iz  }t        t        j                  |            dx}x}	x}}
yc c}w c c}w )uf   C-13: 동일 reconcile 3회 호출 (apply=False) → state 동일, actions_taken 누적 없음, no-op.c                    ddddidS )Ni  rc   oiddeadbeef00000001numberrh   mergeCommitr#   _task_ids    r(   fake_pr_lookupzXTestIdempotentAndForgeryBlock.test_repeated_reconcile_idempotent.<locals>.fake_pr_lookup&      ! %'9: r*   c                    dddS )Nrg   z2026-05-09T00:00:00Zr   end_timer#   r   s    r(   fake_timer_loaderz[TestIdempotentAndForgeryBlock.test_repeated_reconcile_idempotent.<locals>.fake_timer_loader-      )7MNNr*      r   F)applyworkspace_root	pr_lookuptimer_loader   r5   )z0%(py3)s
{%(py3)s = %(py0)s(%(py1)s)
} == %(py6)sr?   states)r9   rB   rm   rC   u   3회 호출 state 불일치: 
>assert %(py8)spy8Nz5%(py2)s
{%(py2)s = %(py0)s.actions_taken
} == %(py5)srr9   r:   ro   zcall u<   : apply=False인데 actions_taken 비어있어야 함, got: 
>assert %(py7)spy7r   Tis)z/%(py3)s
{%(py3)s = %(py1)s.dry_run
} is %(py6)s)rB   rm   rC   zassert %(py8)sr   strreturnr$   )ranger   appendrh   r?   rG   rH   rI   rJ   rK   rL   rM   rN   rO   	enumerateactions_takendry_run)rP   tmp_pathr   r   results_reportr   r   rr   rV   @py_assert4rq   @py_format9irR   rU   rt   @py_format8@py_assert0s                       r(   "test_repeated_reconcile_idempotentz@TestIdempotentAndForgeryBlock.test_repeated_reconcile_idempotent#  s{   		O q 	#A'(.F NN6"	# $++a!''++6{]a]{a]]]{a]]]]]]s]]]s]]]]]]6]]]6]]]{]]]a]]]#@SZA[a!''A[@\!]]]]]]]] g& 	DAq?? b ?b(  ?b  v     I   I #  I ')    !uXYZYhYhXij     	 qz)z!!)T)!T))))!T)))z)))!)))T))))))) ,A[s    L=M
c                    t               }t        j                  t        d      5  t	        d||       ddd       y# 1 sw Y   yxY w)uv   C-14: evidence 부족 상태에서 assert_no_manual_done_forgery 호출 시 RuntimeError(MANUAL_DONE_FORGERY_BLOCKED).MANUAL_DONE_FORGERY_BLOCKEDmatchr   r   Nr)   pytestraisesRuntimeErrorr   rP   r   rp   s      r(    test_manual_done_forgery_blockedz>TestIdempotentAndForgeryBlock.test_manual_done_forgery_blockedF  sC      
 ]]</LM 	)'	 	 	s	   >Ac                    t        ddd      }t        j                  t        d      5  t	        d||       d	d	d	       y	# 1 sw Y   y	xY w)
uF   C-14 변형: merge_commit 있지만 merged_into_main=False → 차단.cafecafe12345678Fre   )r   r   r   r   r   r   r   Nr   r   s      r(   1test_manual_done_forgery_blocked_partial_evidencezOTestIdempotentAndForgeryBlock.test_manual_done_forgery_blocked_partial_evidenceR  sL     +"

 ]]</LM 	)'	 	 	s   AAN)r\   r]   r^   r_   r   r   r   r#   r*   r(   r   r      s    ?!*F
r*   r   c                  .    e Zd ZdZd Zd Zd Zd Zd Zy)TestReplayFixturesu   5 실제 사례 replay fixture.c                   t        dd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 )u  Fixture 1: task-2517 dev2 Telegram cut-off (cron 2BAB8982 마지막 'Pr'로 잘림).

        evidence: pr_state=MERGED, merge_commit=4d45947e..., merged_into_main=True,
                  ci_status=SUCCESS, smoke_status=PASS, timer_status=completed,
                  has_done=True, has_merge_done=True, telegram_reply_truncated=True
        기대: TELEGRAM_REPLY_CUT_OFF stuck case 감지
        r   rc   4d45947eaabb1234Tre   rf   rg   )r   r   r   r   r   r   r   r   r   r   r   r~   r   r   r   ri   u1   Fixture1: TELEGRAM_REPLY_CUT_OFF 기대, actual: rj   rC   Nr   r   s	            r(   -test_replay_fixture_task2517_telegram_cut_offz@TestReplayFixtures.test_replay_fixture_task2517_telegram_cut_offh  s8    !+!$%)
 #8,',-299--11 	
1W< 	
 	
1W 	
 	
	6	
 	
   	
 	
 		  	
 	
 		 2 	
 	
	6	
 	
  6= 	
 	
 		 6= 	
 	
  @yI	
 	
 	
 	
 	
 .s   Ec           	        t        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}}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 )u-  Fixture 2: PR merged but .done missing (회장 §1).

        evidence: pr_state=MERGED, merge_commit=abcdef12, merged_into_main=True,
                  has_done=False, has_done_acked=False, has_merge_done=False
        기대: PR_MERGED_BUT_DONE_MISSING + MERGE_COMMIT_BUT_MERGE_DONE_MISSING
        rc   i-  r   TFr   r~   r   r   r   ri   u5   Fixture2: PR_MERGED_BUT_DONE_MISSING 기대, actual: rj   rC   Nr   u>   Fixture2: MERGE_COMMIT_BUT_MERGE_DONE_MISSING 기대, actual: )r)   r
   r   r   r   rG   rH   rI   rJ   rK   rL   rM   rN   rO   r   r   s	            r(   *test_replay_fixture_pr_merged_done_missingz=TestReplayFixtures.test_replay_fixture_pr_merged_done_missing  s    !#!  
 #8,',-299--55 	
5@ 	
 	
5 	
 	
	6	
 	
   	
 	
 		  	
 	
 		 6 	
 	
	6	
 	
  :A 	
 	
 		 :A 	
 	
  DG9M	
 	
 	
 	
 	
 >> 	
>'I 	
 	
>' 	
 	
	6	
 	
   	
 	
 		  	
 	
 		 ? 	
 	
	6	
 	
  CJ 	
 	
 		 CJ 	
 	
  MWIV	
 	
 	
 	
 	
	 .s   I"c                t   t        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}}t        |      \  }	}
t        j                   t        j"                  h}|	|v }|st        j                  d|fd|	|f      dt        j                         v st        j                  |	      rt        j                  |	      ndt        j                  |      dz  }t        j                  d|	       dz   d|iz  }t        t        j                  |            dx}}yc c}w )u  Fixture 3: mergeCommit 존재 + timer running.

        evidence: pr_state=MERGED, merge_commit=11223344, merged_into_main=True, timer_status=running
        기대: TIMER_RUNNING_BUT_PR_MERGED + state ∈ {STUCK_NEEDS_RECONCILE, MERGED_PENDING_RECONCILE}
        rc   i  r}   Try   r   r~   r   r   r   ri   u6   Fixture3: TIMER_RUNNING_BUT_PR_MERGED 기대, actual: rj   rC   Nr   rh   rl   uV   Fixture3: state ∈ {STUCK_NEEDS_RECONCILE, MERGED_PENDING_RECONCILE} 기대, actual: rn   ro   )r)   r
   r   r   r   rG   rH   rI   rJ   rK   rL   rM   rN   rO   r	   r   r3   r4   )rP   rp   r   r   r   rR   rU   rT   rq   rh   r   rr   rs   rt   s                 r(   .test_replay_fixture_merge_commit_timer_runningzATestReplayFixtures.test_replay_fixture_merge_commit_timer_running  s    !+!"
 #8,',-299--66 	
6'A 	
 	
6' 	
 	
	6	
 	
   	
 	
 		  	
 	
 		 7 	
 	
	6	
 	
  ;B 	
 	
 		 ;B 	
 	
  EWIN	
 	
 	
 	
 	
 #8,q0033
 	
u 
 
 	

 	
u 
 	
 	

 
6	
 	

   	
 	

 
	  	
 	

 
	
 	
 	

  gglfmn		
 	
 	

 	
 	
 .s   H5c                   t        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 )u   Fixture 4: finish-task interrupted.

        evidence: worktree_exists=True, branch_pushed_to_remote=True, pr_number=None
        기대: FINISH_TASK_INTERRUPTED
        TNr   r~   r   r   r   ri   u2   Fixture4: FINISH_TASK_INTERRUPTED 기대, actual: rj   rC   r   r   s	            r(   +test_replay_fixture_finish_task_interruptedz>TestReplayFixtures.test_replay_fixture_finish_task_interrupted  s     ! $(

 #8,',-299--22 	
2g= 	
 	
2g 	
 	
	6	
 	
   	
 	
 		  	
 	
 		 3 	
 	
	6	
 	
  7> 	
 	
 		 7> 	
 	
  A	J	
 	
 	
 	
 	
 .r   c           
     b  $% d5d}d5d}g $d6$fd}d7d}g }t        d      D ]  }t        dd|||||      }|j                  |j                         |j                  }	g }
|	|
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|j                         dz   d|iz  }t        t        j                  |            dx}	x}}
 t        |      }t        |      }d}||k(  }|slt        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dt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      t        j                  |      t        j                  |      dz  }t        j                  d|       dz   d|iz  }t        t        j                  |            dx}x}x}}d8d}t        dd||||||      }d5d}d5d}|dz  d z  }|j!                  dd!       |d"z  j#                  d#       |d$z  j#                  d#       |d%z  j#                  d#       g %d6%fd&}t        dd||||||      }g }	|j                  }t$        j&                  }||k(  }|}|s|j                  }g }||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  }|	j                  |       |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/d0| iz  }!|	j                  |!       t        j(                  |	d      i z  }"t        j                  d1|j                   d2|j                         d3z   d4|"iz  }#t        t        j                  |#            dx}x}	x}x}x}x}x}}y)9u)  Fixture 5: repeated reconcile idempotency.

        - 동일 evidence로 reconcile 3회 호출 (apply=False) → state 동일
        - apply=True 첫 호출 → 일부 backfill 액션 (planned/taken)
        - evidence(backfill 후) + 두번째 apply=True → 추가 액션 0건 (멱등)
        c                    ddddidS Ni  rc   r   f1x7ure5abcdef12r   r#   r   s    r(   fake_pr_lookup_pendingzeTestReplayFixtures.test_replay_fixture_repeated_reconcile_idempotency.<locals>.fake_pr_lookup_pending  r   r*   c                    dddS Nrg   z2026-05-09T01:00:00Zr   r#   r   s    r(   fake_timer_loader_completedzjTestReplayFixtures.test_replay_fixture_repeated_reconcile_idempotency.<locals>.fake_timer_loader_completed  r   r*   c                ,    j                  | |f       y Nr   )pathcontentcaptured_writess     r(   fake_file_writerz_TestReplayFixtures.test_replay_fixture_repeated_reconcile_idempotency.<locals>.fake_file_writer  s    ""D'?3r*   c                     y r  r#   )r   _timer_datas     r(   fake_timer_writerz`TestReplayFixtures.test_replay_fixture_repeated_reconcile_idempotency.<locals>.fake_timer_writer  s    r*   r   ztask-fixture5F)r   r   r   r   file_writertimer_writerr5   r   r   r   5   apply=False인데 actions_taken 비어있어야 함: r   r   Nr   r>   r?   set
dry_statesrA   u   3회 dry-run state 불일치: z
>assert %(py11)srE   c                4    t        j                  | ddd      S )Nr   zf1x7ure5abcdef12
 stdoutstderr
subprocessCompletedProcessargs_kwargss     r(   fake_runner_foundz`TestReplayFixtures.test_replay_fixture_repeated_reconcile_idempotency.<locals>.fake_runner_found  s    ..tQ?S\^__r*   T)r   r   r   r   r  r  runnerc                    ddddidS r
  r#   r   s    r(   fake_pr_lookup_finalizedzgTestReplayFixtures.test_replay_fixture_repeated_reconcile_idempotency.<locals>.fake_pr_lookup_finalized
  r   r*   c                    dddS r  r#   r   s    r(   fake_timer_loader_finalizedzjTestReplayFixtures.test_replay_fixture_repeated_reconcile_idempotency.<locals>.fake_timer_loader_finalized  r   r*   memoryeventsparentsexist_okztask-fixture5.donez{}ztask-fixture5.done.ackedztask-fixture5.merge-donec                ,    j                  | |f       y r  r  )r  r  captured_writes_seconds     r(   fake_file_writer2z`TestReplayFixtures.test_replay_fixture_repeated_reconcile_idempotency.<locals>.fake_file_writer2  s    "))4/:r*   )zL%(py4)s
{%(py4)s = %(py2)s.state
} == %(py8)s
{%(py8)s = %(py6)s.FINALIZED
}report_apply2r   )r:   r<   rC   r   z%(py10)spy10)z9%(py14)s
{%(py14)s = %(py12)s.actions_taken
} == %(py17)s)py12py14py17z%(py19)spy19uF   두번째 apply=True: 추가 액션 없거나 FINALIZED 기대, state=z, actions_taken=z
>assert %(py22)spy22r   )r  r   r  r   r   None)r   r   r  r$   r   r?  r(  r@   r   zsubprocess.CompletedProcess)r   r   r   rh   r   rG   rH   rI   rJ   rK   rL   rM   rN   rO   r  r?   mkdir
write_textr   r1   _format_boolop)&rP   r   r  r  r  r  r  r   r   rR   r   rU   rt   r   rV   rW   rX   rY   rZ   r*  report_apply1r-  r/  
events_dirr7  r8  r   @py_assert13@py_assert16@py_assert15r   @py_format11@py_format18@py_format20@py_format21@py_format23r  r6  s&                                       @@r(   2test_replay_fixture_repeated_reconcile_idempotencyzETestReplayFixtures.test_replay_fixture_repeated_reconcile_idempotency  s   		O (*	4	 
q 	A'08,.F fll+'' 2 '2-  '2  v     I   I (  I ,.    HH\H\G]^     	 z?Ws?#WqW#q(WWW#qWWWWWWsWWWsWWWWWW3WWW3WWWWWWzWWWzWWW?WWW#WWWqWWW,J:,*WWWWWWWW	` "#,4(*$	
		O (83
5	*	*66t<	0	0<<TB	0	0<<TB.0	; "#.4)*$	
	
}"" 	
n&>&> 	
"&>> 	
-B]B] 	
ac 	
B]acBc 	
 	
 	
"&> 	
 	
 
6	
 	
   	
 	
 
	  	
 	
 
	 # 	
 	
 
6	
 	
  '5 	
 	
 
	 '5 	
 	
 
	 '? 	
 	
 	
 
6	
 
	
 	
B]ac 	
 	
 
6	
 	
  CP 	
 	
 
	 CP 	
 	
 
	 C^ 	
 	
 
	 bd 	
 	
 	
 
6	
 
	
 	
 	
 "(())9-:U:U9VX	
 	
 	
 	
 	
 	
 	
r*   N)	r\   r]   r^   r_   r  r  r  r  rN  r#   r*   r(   r   r   e  s    )
6
2
6
"h
r*   r   c                      e Zd ZdZd Zy)TestLivePilotReplayu  task-2520 live pilot self-host 중 발견된 한계점 박제.

    다그다 hang 사례 (bot_session_status=cancelled + timer running + worktree/branch alive +
    PR 미생성)는 현 본체에서 FINISH_TASK_INTERRUPTED로만 매칭되며,
    bot_session_status=cancelled 단독 case는 어떤 stuck reason으로도 격상되지 않는다.
    operational hardening은 task-2521 영역.
    c                   t        ddddddddddddd      }t        |      \  }}|D ch c]  }|j                   }}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  }	t        j                  d|       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  }	t        j                  d|       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  }	t        j                  d      dz   d|	iz  }
t        t        j                  |
            dx}}d?d}d?d}d@d}|dz  dz  }|j#                  dd       |dz  }|j#                  dd       |d z  }|j%                  t'        j(                  d!dd"d#      d$z   d%&       t+        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.                  }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                  d0|j.                         d1z   d2|
iz  }t        t        j                  |            dx}x}}t1        d3 |j2                  D              }|st        j                  d4|j2                         d5z   d6d7t        j                         v st        j                  |      rt        j                  |      nd7iz  }t        t        j                  |            d8 |j2                  D        }t1        |      }| }|st        j                  d9|j2                         d:z   d;t        j                         v st        j                  t0              rt        j                  t0              nd;t        j                  |      t        j                  |      dz  }t        t        j                  |            dx}x}}|j4                  }g }||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=|j4                         d>z   d-|iz  }t        t        j                  |            dx}x}}yc c}w )Au  task-2520: bot 종료 + timer 미정지 + worktree/branch 살아있음 + PR 미생성.

        현 본체 동작 정확 박제 (본체 변경 시 회귀 깨짐):
        1. state == STUCK_NEEDS_RECONCILE
           (PR 없음, escalate 없음, stuck_cases 존재 → fallback)
        2. stuck_cases ⊃ {FINISH_TASK_INTERRUPTED}
           (worktree_exists + branch_pushed_to_remote + pr_number None 매칭)
        3. BOT_SESSION_ENDED_BUT_TASK_OK NOT in stuck reasons
           (merged_into_main=True 조건 매칭 실패 — 본체 한계점, task-2521 영역)
        4. reconcile(apply=False) → actions_planned에 'BLOCKED (insufficient evidence)' 포함
           (assert_no_manual_done_forgery 차단)
        z	task-2520NFry   r   Trf   )r   r   r   r   r   r   r   r   r   r    r!   r"   r   r5   )z=%(py0)s == %(py4)s
{%(py4)s = %(py2)s.STUCK_NEEDS_RECONCILE
}rh   r   ri   uG   STUCK_NEEDS_RECONCILE 기대 (PR 없음 + stuck_cases 존재), 실제: rj   rC   r~   r   r   r   uG   FINISH_TASK_INTERRUPTED 기대 (worktree+branch+no_pr 매칭), actual: )not in)zI%(py2)s
{%(py2)s = %(py0)s.BOT_SESSION_ENDED_BUT_TASK_OK
} not in %(py4)su   현 본체 한계점 회귀 박제: bot_session_status=cancelled 단독은 격상 안됨. 격상 시 task-2521에서 신규 stuck reason 추가.c                    i S r  r#   r   s    r(   r   zbTestLivePilotReplay.test_bot_session_cancelled_with_evidence_intact_replay.<locals>.fake_pr_lookupp  s    Ir*   c                    dd dS )Nry   r   r#   r   s    r(   r   zeTestLivePilotReplay.test_bot_session_cancelled_with_evidence_intact_replay.<locals>.fake_timer_loaders  s    'T::r*   c                n    d| v rt        j                  | ddd      S t        j                  | ddd      S )Nz	ls-remoter   z0deadbeefcafe1234	refs/heads/task/task-2520-dev4
r   r!  r   r$  r'  s     r(   fake_runnerz_TestLivePilotReplay.test_bot_session_cancelled_with_evidence_intact_replay.<locals>.fake_runnerv  sB    d"!22O	  ..tQr"MMr*   z
.worktreesztask-2520-dev4r2  cron_historyztask-2520.logz[task-2520] live pilotok)promptr   response
zutf-8)encoding)r   r   r+  cron_history_dirr   r   r   )z/%(py2)s
{%(py2)s = %(py0)s.dry_run
} is %(py5)sr   r   zassert %(py7)sr   )zX%(py2)s
{%(py2)s = %(py0)s.state
} == %(py6)s
{%(py6)s = %(py4)s.STUCK_NEEDS_RECONCILE
})r9   r:   r<   rC   u6   reconcile state STUCK_NEEDS_RECONCILE 기대, 실제: r   r   c              3  <   K   | ]  }d |v xr d|v xs d|v   yw)BLOCKEDzinsufficient evidencer   Nr#   .0actions     r(   	<genexpr>z]TestLivePilotReplay.test_bot_session_cancelled_with_evidence_intact_replay.<locals>.<genexpr>  s<      
  & F%<%F 7,67
s   uj   actions_planned에 'BLOCKED (insufficient evidence)' 또는 'MANUAL_DONE_FORGERY_BLOCKED' 기대, actual: z
>assert %(py0)sr9   forgery_blockedc              3  r   K   | ]/  }|j                  d       xs |j                  d      xs |dk(   1 yw)created_wrote_ended_timerN)
startswithr`  s     r(   rc  z]TestLivePilotReplay.test_bot_session_cancelled_with_evidence_intact_replay.<locals>.<genexpr>  sJ      
  j) '  *'&'
s   57uA   forgery 차단 후 다른 backfill 액션 기록 금지, actual: z2
>assert not %(py4)s
{%(py4)s = %(py0)s(%(py2)s)
}anyr   r  r   r   r@  )r)   r	   r   r   r3   rG   rH   rI   rJ   rK   rL   rM   rN   rO   r   r   r   rA  rB  jsondumpsr   r   rh   rj  actions_plannedr   )rP   r   rp   rh   rk   r   r   rU   rR   rT   rq   r   r   rV  worktree_dircron_dircron_logr   r   rt   r   rV   r   rd  @py_format1s                            r(   6test_bot_session_cancelled_with_evidence_intact_replayzJTestLivePilotReplay.test_bot_session_cancelled_with_evidence_intact_replay@  s    !""  * $(
  -X6{'2329933&<< 	
u<< 	
 	
u< 	
 	
	6	
 	
   	
 	
 		  	
 	
	6	
 	
  ' 	
 	
 		 ' 	
 	
 		 = 	
 	
  VV[U\]	
 	
 	
 	
 	
 22 	
2g= 	
 	
2g 	
 	
	6	
 	
   	
 	
 		  	
 	
 		 3 	
 	
	6	
 	
  7> 	
 	
 		 7> 	
 	
  VV]U^_	
 	
 	
 	
 	
 88 	
8G 	
 	
8 	
 	
 
6	
 	
   	
 	
 
	  	
 	
 
	 9 	
 	
 
6	
 	
  AH 	
 	
 
	 AH 	
 	
 E	
 	
 	
 	
 	
		;		N  ,.1AA4$7n,td3o-JJ6) $   	 
	
 #%$*
 ~~%%~%%%%~%%%%%%v%%%v%%%~%%%%%%%%%%|| 	
~CC 	
|CC 	
 	
 	
|C 	
 	
	6	
 	
   	
 	
 		  	
 	
 		  	
 	
	6	
 	
   . 	
 	
 		  . 	
 	
 		  D 	
 	
  EV\\NS	
 	
 	
 	
 	
  
 !00
 

  	
 ==C=S=S<TV	
 	
 
6	
 	
   	
 	
 
	  	
 	
 	
 	
 	


 !00	
 	
3 
 
 	
 
 
 	
 
 	
  PPVPfPfOgh	
 	
 
6	
 	
   	
 	
 
	  	
 	
 
	
 	
 	
 
	
 	
 	
 	
 	
 	
 ## 	
r 	
#r) 	
 	
#r 	
 	
	6	
 	
   	
 	
 		  	
 	
 		 $ 	
 	
 		 (* 	
 	
  DFDXDXCYZ	
 	
 	
 	
 	
 	
m 4s   a=N)r\   r]   r^   r_   rr  r#   r*   r(   rP  rP  7  s    v
r*   rP  c                      e Zd ZdZd Zy)TestStuckReasonEnumu   StuckReason enum이 회장 명시 8종(task-2518) 포함 확인.
    task-2521 §3에서 BOT_CANCELLED_* 4종이 추가되어 총 12종이 되었으므로
    superset 검증으로 전환 (task-2518 contract = 8종 모두 present).
    c                j   h d}t         D ch c]  }|j                   }}||z
  }| }|st        j                  d| 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 )N>   r   r   r   r   r   r   r   r   u&   task-2518 StuckReason 누락: missing=r;   z
>assert not %(py0)sr9   missing)
r   rF   rG   rM   rI   rJ   rK   rL   rN   rO   )rP   expected_2518rQ   r7   rv  rR   @py_format2s          r(   $test_stuck_reason_enum_eight_membersz8TestStuckReasonEnum.test_stuck_reason_enum_eight_members  s    	
 .996&,,99&({ 	
{ 	
  5WIYvhO	
 	
	6	
 	
   	
 	
 		  	
 	
 	
 	
 	
 :s   B0N)r\   r]   r^   r_   ry  r#   r*   r(   rt  rt    s    

r*   rt  )r   r   ))r_   
__future__r   builtinsrI   _pytest.assertion.rewrite	assertionrewriterG   rk  r%  syspathlibr   typingr   r   __file__resolveparent_WORKTREE_ROOTr   r  removeinsert&utils.lifecycle_reconciliation_managerr   r   r   r	   r
   r   r   r)   r,   ra   r   r   r   rP  rt  r#   r*   r(   <module>r     s    #     
    h'')0077>>~#(("HHOOC'( 3~& '  %@. .*9
 9
@@
 @
N> >JK
 K
d
 
L
 
r*   