
    wj                        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ddlmZmZmZmZ dZdZddZed	fdd
Zd Zd Zd Zd Zd Zy)uZ  task-2554+2 §5 신규 fixture #1: PR #105 bootstrap gap 재현.

회장 §명시 (2026-05-12): head 08f2d29c 에 대해 stale 1e907722 review 만 존재할 때
``detect_gemini_stale_on_head`` 가 ``GEMINI_STALE_ON_HEAD`` 판정을 내려야 하며
``emit_owner_trigger_decision`` 이 OWNER_TRIGGER_REQUIRED 결정 파일을 생성해야 한다.
    )annotationsN)Path)GEMINI_STALE_ON_HEADOWNER_TRIGGER_REQUIREDMergeQueueExecutorPRMeta(08f2d29ccb149fd721722e69909e45ceaebc71ba(1e907722167fd1e0fe328c1196af76c049644b27c                :    d }d }d }d }t        |||||       S )u,   안전한 mock callable 로 executor 생성.c                    t        d      )Nz"gh runner not used in this fixtureNotImplementedError)argsenvs     J/home/jay/workspace/anu_v2/tests/test_owner_trigger_bootstrap_gap_pr105.pyghz_build_executor.<locals>.gh   s    !"FGG    c                    t        d      )Nzgit runner not usedr   )r   s    r   gitz_build_executor.<locals>.git!   s    !"788r   c                     y)Nr    )pathss    r   pytest_runnerz&_build_executor.<locals>.pytest_runner$   s    r   c                     y )Nr   )payloads    r   audit_writerz%_build_executor.<locals>.audit_writer'   s    r   )	gh_runner
git_runnerr   r   task_md_root)r   )tmp_pathr   r   r   r   s        r   _build_executorr!      s5    H9 #! r   i   c                *    t        || ddddddd	      S )	Ntask/task-2554+1-dev5mainr   TGEMINI_UNRESOLVEDBLOCKEDr   	numberhead_shahead_refbase_refchanged_filesci_required_all_successgemini_statusmerge_state_statusqueue_predecessors_open)r   )headr)   s     r   _prr3   3   s*    ( $)$ !
 
r   c                f   t        |       }|j                  t               t              }|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
   }|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}}|j                  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}}y	)uH   PR #105 head=08f2d29c vs stale 1e907722 review → GEMINI_STALE_ON_HEAD.prgemini_review_commit_id==)z0%(py2)s
{%(py2)s = %(py0)s.decision
} == %(py4)soutcomer   py0py2py4assert %(py6)spy6Nr2   z%(py1)s == %(py3)s_PR_105_HEADpy1py3assert %(py5)spy5r7   _STALE_REVIEW_COMMIT_ID)r!   detect_gemini_stale_on_headr3   rH   decisionr   
@pytest_ar_call_reprcompare@py_builtinslocals_should_repr_global_name	_safereprAssertionError_format_explanationextrarB   )r    executorr:   @py_assert1@py_assert3@py_format5@py_format7@py_assert0@py_assert2@py_format4@py_format6s              r   <test_pr105_head_vs_stale_review_detects_gemini_stale_on_headr]   A   s   x(H225 7 3 G 333333333333373337333333333333333333333== 0 L0000 L000 000000L000L0000000==23N37NNNNN37NNNN3NNNNNN7NNNN7NNNNNNNNr   c                   t        |       }| dz  dz  }|j                  dt               |      }|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}||k(  }|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}||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}||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}}|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!z  }|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}}t        j                  |j                  d%&            }||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}|d-z  }|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}}t        j                  |j                  d%&            }|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/   }|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}}|d0   }|t         k(  }|st        j                  d|fd|t         f      t        j
                  |      d1t        j                         v st        j                  t               rt        j
                  t               nd1dz  }	dd|	iz  }
t        t        j                  |
            dx}}y)2uB   OWNER_TRIGGER_REQUIRED decision JSON v1 + requested marker 생성.memoryeventstask-2554+2task_idr6   decision_dirschemaz anu_v2.owner_trigger_decision.v1r8   )z%(py1)s == %(py4)s)rD   r>   r?   r@   Nr6   r"   current_headrA   rB   rC   rF   rG   allowed_action"POST_GEMINI_REVIEW_TRIGGER_COMMENTcomment_bodyz/gemini reviewallowedT)is)z%(py1)s is %(py4)sgemini_evidence_freshFnudge_count_for_pr_headr   z'task-2554+2.owner_trigger_decision.jsonzAassert %(py4)s
{%(py4)s = %(py2)s
{%(py2)s = %(py0)s.exists
}()
}decision_pathr;   zutf-8)encoding)z%(py0)s == %(py2)ssavedrJ   r<   r=   zassert %(py4)sr>   z#task-2554+2.owner-trigger.requestedmarker_pathr2   decision_coder   )r!   emit_owner_trigger_decisionr3   rK   rL   rP   rQ   rR   rB   rM   rN   rO   existsjsonloads	read_textr   )r    rT   rd   rJ   rY   rV   rZ   rW   rX   r[   r\   rn   rU   rp   @py_format3rr   marker_datas                    r   =test_emit_owner_trigger_decision_creates_v1_schema_and_markerr{   M   sq   x(Hh&1L335! 4 H HC!CC!CCCCC!CCCCCCC!CCCCCCCCD> S >S    >S   >   S       N#3#|3333#|333#333333|333|3333333$%M)MM%)MMMMM%)MMMM%MMM)MMMMMMMMN#7'77#'77777#'7777#777'77777777I&$&$&&&&$&&&&&&$&&&&&&&+,55,5555,555,5555555555-.3!3.!3333.!333.333!3333333 #LLM!!!!!!!!!=!!!=!!!!!!!!!!!!!JJ}...@AEH5H55HH!FFK;;**[22G2DEKt###################v.,....,.........,...,.......'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Ar   c                   t        |       }|j                  t               t              }|j                  }|syddt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      dz  }t        t        j                  |            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}}y)uJ   head == gemini review commit_id 일 때 AUTO_MERGE_ALLOWED (stale 아님).r5   z*assert %(py2)s
{%(py2)s = %(py0)s.passed
}r:   rq   Ngemini_review_fresh_on_headr8   z.%(py2)s
{%(py2)s = %(py0)s.reason
} == %(py5)sr<   r=   rG   assert %(py7)spy7)r!   rI   r3   rB   passedrM   rN   rK   rO   rP   rQ   rR   reasonrL   )	r    rT   r:   rU   ry   @py_assert4rV   r\   @py_format8s	            r   9test_fresh_review_on_head_does_not_trigger_stale_decisionr   m   s    x(H225 , 3 G >>>77>>>:::>:::::>:::::::7:::7:::>:::::::::::r   c                   t        |       }|j                  t               d      }|j                  }| }|syddt	        j
                         v st        j                  |      rt        j                  |      ndt        j                  |      dz  }t        t        j                  |            d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)uQ   gemini_review_commit_id=None → first-review-pending (외부 자동 1st 대기).Nr5   z.assert not %(py2)s
{%(py2)s = %(py0)s.passed
}r:   rq   gemini_first_review_pendingr8   r~   r   r   r   )r!   rI   r3   r   rM   rN   rK   rO   rP   rQ   rR   r   rL   )	r    rT   r:   rU   rV   r[   r   r\   r   s	            r   6test_missing_gemini_review_yields_first_review_pendingr   x   s    x(H225 $ 3 G ~~~ww~>>:::>:::::>:::::::7:::7:::>:::::::::::r   c                    t        |       }t        ddddddddd	
	      }t        j                  t        d      5  |j                  d||        ddd       y# 1 sw Y   yxY w)u=   pr.head_sha 가 40-char hex 아니면 ValueError fail-closed.r"   znot-a-valid-shar$   r%   r   Tr&   r'   r   r(   z40-char)matchra   rb   N)r!   r   pytestraises
ValueErrorrt   )r    rT   bad_prs      r   .test_emit_decision_rejects_invalid_pr_head_shar      sr    x(H"( $)$ !
F 
z	3 
,,!! 	- 	

 
 
s   AA")r    r   returnr   )r2   strr)   intr   r   )__doc__
__future__r   builtinsrM   _pytest.assertion.rewrite	assertionrewriterK   rv   pathlibr   r   anu_v2.merge_queue_executorr   r   r   r   rB   rH   r!   r3   r]   r{   r   r   r   r   r   r   <module>r      s`    #       :D 0 ! 	OB@;;
r   