
    Pju                       d Z ddlmZ ddlZddlmc mZ ddl	Z	ddl
Z
ddlZddlmZ ddlmZmZmZ ddlZ ee      j)                         j*                  d   Z ee      ej0                  vr"ej0                  j3                  d ee             ddlmZmZmZmZmZm Z m!Z!m"Z"m#Z#m$Z$m%Z% ddl&m'Z'm(Z(m)Z)m*Z* d/d0d
Z+dZ,dZ-dZ.ddddddeddd	d
	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 d1dZ/d2dZ0ejb                  d3d       Z2ejb                  d3d       Z3ejb                  d3d       Z4ejb                  d3d       Z5ejb                  d3d       Z6ejb                  	 	 	 	 	 	 	 	 d4d       Z7ejb                  	 	 	 	 	 	 	 	 d5d       Z8	 	 	 	 	 	 	 	 	 	 	 	 d6dZ9	 	 	 	 	 	 	 	 	 	 	 	 d6d Z:	 	 	 	 	 	 	 	 d7d!Z;	 	 	 	 	 	 	 	 	 	 	 	 d6d"Z<	 	 	 	 	 	 	 	 	 	 	 	 	 	 d8d#Z=	 	 	 	 	 	 	 	 	 	 	 	 d6d$Z>	 	 	 	 	 	 	 	 	 	 	 	 d6d%Z?	 	 	 	 	 	 	 	 	 	 	 	 d6d&Z@	 	 	 	 	 	 d9d'ZA	 	 	 	 	 	 d9d(ZB	 	 	 	 	 	 	 	 	 	 	 	 d6d)ZC	 	 	 	 	 	 	 	 	 	 	 	 d6d*ZD	 	 	 	 	 	 	 	 	 	 	 	 d6d+ZE	 	 	 	 	 	 	 	 	 	 	 	 d6d,ZF	 	 	 	 	 	 d:d-ZG	 	 	 	 	 	 d:d.ZHy);u  anu_v2.tests.test_owner_trigger_pat_phase3_integration_2553 — Phase 3 통합.

회장 §명시 12 필수 + 11/12번 (task-2553):
  - merge_queue_executor 가 queue-head PR 의 Gemini evidence missing 시 주입된
    owner_trigger 인스턴스를 호출하여 `/gemini review` 댓글 1회 작성.
  - Gemini fresh evidence (commit_id == current_head) 도착 후에는 BOT_GITHUB_TOKEN
    경로 머지로 진행 (OWNER PAT 은 머지에 사용 X — 격리).
  - self-resume (OWNER manual 개입 0).

회귀 박제:
  1. evidence missing + queue-head + owner_trigger 주입 → OWNER_TRIGGER_REQUESTED.
  2. evidence 도착 후 → AUTO_MERGE_ALLOWED (4 gate PASS).
  3. owner_trigger=None → 기존 GEMINI_UNRESOLVED_BLOCK 그대로 (회귀 방지).
  4. queue_predecessors_open > 0 → trigger 호출 0 (queue-head only).
  5. owner_trigger 호출 ↔ BOT_GITHUB_TOKEN 머지 경로 분리 (env 검증).

mock 패턴은 `test_merge_queue_executor_2531.py` + `test_owner_trigger_pat_phase2_2553.py`
와 동일.
    )annotationsN)Path)AnyMappingSequence   )AUTO_MERGE_ALLOWEDAUTO_MERGE_SUCCESSGEMINI_COMPLETEDGEMINI_SCOPE_EXPANSIONGEMINI_UNRESOLVEDGEMINI_UNRESOLVED_BLOCKNON_CRITICAL_AUTO_RESOLVEDOWNER_TRIGGER_REQUESTEDSTALE_EVIDENCE_BLOCKMergeQueueExecutorPRMeta)ALLOWED_COMMENT_BODYOWNER_PAT_ENV_NAMEOwnerTriggerPatwrite_decision_json c                4    t        j                  g | ||      S )Nargs
returncodestdoutstderr)
subprocessCompletedProcess)r   r   r   s      R/home/jay/workspace/anu_v2/tests/test_owner_trigger_pat_phase3_integration_2553.py_cpr"   :   s    &&B:f]cdd    github_pat_FAKE_OWNER_PHASE3ghs_BOT_PHASE3z2026-05-11T12:00:00+00:00Q   zheadsha-currentztask/task-2553-dev5main)zanu_v2/__init__.pyzanu_v2/owner_trigger_pat.pyzanu_v2/merge_queue_executor.pyzanu_v2/tests/__init__.pyz>anu_v2/tests/test_owner_trigger_pat_phase3_integration_2553.pyTCLEAN
numberhead_shahead_refbase_refchanged_filesci_required_all_successgemini_statusmerge_state_statusqueue_predecessors_opengemini_commit_idc        
        >    t        | |||t        |      |||||	
      S )Nr)   )r   tupler)   s
             r!   _make_prr6   C   s4    & M* 7#- 7) r#   c                \    g d}| dz  }|j                  dj                  |      d       |S )N)z# task-2553r   z```yamlzexpected_files:z  - "anu_v2/__init__.py"z!  - "anu_v2/owner_trigger_pat.py"z$  - "anu_v2/merge_queue_executor.py"z  - "anu_v2/tests/__init__.py"zD  - "anu_v2/tests/test_owner_trigger_pat_phase3_integration_2553.py"zcherry_pick_allowed: falsez```ztask-2553.md
utf-8encoding)
write_textjoin)tmp_pathbodyps      r!   _write_task_mdrA   d   s2    D 	>!ALL47L3Hr#   c                     g S )u.   OWNER PAT 으로 호출된 gh args/env 수집. rC   r#   r!   gh_owner_callsrD   x   	     Ir#   c                     g S )u,   BOT 토큰 머지 경로 gh args/env 수집.rC   rC   r#   r!   gh_bot_callsrG   ~   rE   r#   c                     g S NrC   rC   r#   r!   audit_callsrJ          Ir#   c                     g S rI   rC   rC   r#   r!   trigger_audit_callsrM      rK   r#   c                     g S rI   rC   rC   r#   r!   decision_callsrO      rK   r#   c                P     d fd}d	fd}d
fd}t        |||ddd       S )u?   OWNER PAT trigger 인스턴스 — OWNER 토큰 env 만 읽음.c                l    j                  t        |       t        |xs i       d       t               S Nr   envappendlistdictr"   )r   rT   rD   s     r!   	gh_runnerz owner_trigger.<locals>.gh_runner   s)    tDz$syb/JKur#   c                :    j                  t        |              y rI   rV   rX   )recordrM   s    r!   audit_writerz#owner_trigger.<locals>.audit_writer   s    ""4<0r#   c                j    j                  t        |       t        |      d       t        | |       y )Npayloadpath)rV   rX   strr   )r`   ra   rO   s     r!   decision_writerz&owner_trigger.<locals>.decision_writer   s(    $w-TKLGT*r#   jeon-jonghyuktaskctl-anuc                     t         S rI   	_FIXED_TSrC   r#   r!   <lambda>zowner_trigger.<locals>.<lambda>       i r#   rY   r]   rc   ownerrepoclockr   Sequence[str]rT   zMapping[str, str]returnsubprocess.CompletedProcessr\   Mapping[str, Any]rq   Noner`   rt   ra   r   rq   ru   )r   )rD   rM   rO   rY   r]   rc   s   ```   r!   owner_triggerrw      s3    1+ !' r#   c                N    dfd}dd}dd}d	fd}t        |||||       S )
u6   머지 큐 executor — BOT 토큰 머지 경로 mock.c                l    j                  t        |       t        |xs i       d       t               S rR   rU   )r   rT   rG   s     r!   rY   zexecutor.<locals>.gh_runner   s)    T$ZSYBHIur#   c                     t               S rI   r"   _argss    r!   
git_runnerzexecutor.<locals>.git_runner   	    ur#   c                     y)Nr   rC   r|   s    r!   pytest_runnerzexecutor.<locals>.pytest_runner   s    r#   c                :    j                  t        |              y rI   r[   r\   rJ   s    r!   r]   zexecutor.<locals>.audit_writer       4<(r#   )rY   r~   r   r]   task_md_root)r   rp   rT   zMapping[str, str] | Nonerq   rr   )r}   r   rq   rr   )r}   rp   rq   intrs   )r   )r>   rG   rJ   rY   r~   r   r]   s    ``    r!   executorr      s5    ) #! r#   c                n   t        |        |j                  t        t               | dz  }| dz  }t	        dt
        d      }|j                  |d|||      }|j                  }	|	t        k(  }
|
st        j                  d|
fd|	t        f      d	t        j                         v st        j                  |      rt        j                  |      nd	t        j                  |	      d
t        j                         v st        j                  t              rt        j                  t              nd
dz  }dd|iz  }t        t        j                   |            dx}	}
|j"                  }	d}|	|k(  }
|
st        j                  d|
fd|	|f      d	t        j                         v st        j                  |      rt        j                  |      nd	t        j                  |	      t        j                  |      dz  }dd|iz  }t        t        j                   |            dx}	x}
}|j$                  d   }t&        t(        f}
||
v }|slt        j                  d|fd||
f      t        j                  |      t        j                  |
      dz  }dd|iz  }t        t        j                   |            dx}x}}
t+        |      }d}||k(  }|st        j                  d|fd||f      dt        j                         v st        j                  t*              rt        j                  t*              nddt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      t        j                  |      dz  }dd|iz  }t        t        j                   |            dx}x}}|d   }|d   }d d!d"d#|j,                   d$d%d&t.         g}
||
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)   }|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}}|j0                  }	 |	       }
|
sd/d0t        j                         v st        j                  |      rt        j                  |      nd0t        j                  |	      t        j                  |
      dz  }t        t        j                   |            dx}	}
t3        j4                  |j7                  d12            }|d3   }d4}
||
k(  }|slt        j                  d|fd'||
f      t        j                  |      t        j                  |
      dz  }dd|iz  }t        t        j                   |            dx}x}}
|d5   }|j,                  }||k(  }|st        j                  d|fd6||f      t        j                  |      d7t        j                         v st        j                  |      rt        j                  |      nd7t        j                  |      d8z  }dd|iz  }t        t        j                   |            dx}x}}y)9u   evidence missing + queue-head + owner_trigger 주입 → OWNER PAT 으로 `/gemini review`
    댓글 1회 작성 + OWNER_TRIGGER_REQUESTED 반환.zowner_trigger_audit.jsonlzowner_trigger_decision.json
locked-shar   r+   r0   r2   prhead_sha_at_lockrw   audit_log_pathdecision_json_path==z0%(py2)s
{%(py2)s = %(py0)s.decision
} == %(py4)soutr   py0py2py4assert %(py6)spy6N owner_trigger_pat_comment_postedz.%(py2)s
{%(py2)s = %(py0)s.reason
} == %(py5)sr   r   py5assert %(py7)spy7prior_decision)in)z%(py1)s in %(py4)spy1r      z0%(py3)s
{%(py3)s = %(py0)s(%(py1)s)
} == %(py6)slenrD   r   r   py3r   assert %(py8)spy8r   apiz-XPOSTz(/repos/jeon-jonghyuk/taskctl-anu/issues/z	/commentsz-fzbody=z%(py1)s == %(py4)srT   GH_TOKENz%(py1)s == %(py3)s_FAKE_OWNER_TOKENr   r   assert %(py5)sr   zAassert %(py4)s
{%(py4)s = %(py2)s
{%(py2)s = %(py0)s.exists
}()
}decision_pathr9   r:   decisionPASS	pr_number)z.%(py1)s == %(py5)s
{%(py5)s = %(py3)s.number
}r   )r   r   r   )rA   setenvr   r   r6   r   evaluate_with_owner_triggerr   r   
@pytest_ar_call_reprcompare@py_builtinslocals_should_repr_global_name	_safereprAssertionError_format_explanationreasonextrar   r   r   r*   r   existsjsonloads	read_text)r>   r   rw   rD   monkeypatch
audit_pathr   r   r   @py_assert1@py_assert3@py_format5@py_format7@py_assert4@py_format6@py_format8@py_assert0@py_assert2@py_assert5@py_format9call@py_format4decision_datas                          r!   >test_evaluate_with_owner_trigger_missing_evidence_triggers_patr      s    8)+<=77J<<M	' !
B
 
.
.%#!( / C <<2<22222<222222232223222<222222222222222222::;;;:;;;;;:;;;;;;;3;;;3;;;:;;;;;;;;;;;99%& "+ & +   & +    '   +       ~#!#!####!######3###3######~###~######!#######!D< tV
2299+YG*+, <    	<    	    	     	 
 ;z"7"&77777"&7777"777777&7777&77777777 !!!!!!!!!=!!!=!!!!!!!!!!!!!JJ}666HIM$..$....$...$..........%22%2222%222%2222222222222222222r#   c                <   t        |        |j                  t        t               | dz  }| dz  }t	        dt
        d      }|j                  |d|||      }|j                  }	|	t        k(  }
|
st        j                  d|
fd|	t        f      d	t        j                         v st        j                  |      rt        j                  |      nd	t        j                  |	      d
t        j                         v st        j                  t              rt        j                  t              nd
dz  }dd|iz  }t        t        j                   |            dx}	}
|j"                  }	|	sydd	t        j                         v st        j                  |      rt        j                  |      nd	t        j                  |	      dz  }t        t        j                   |            d}	t%        |      }d}||k(  }|st        j                  d|fd||f      dt        j                         v st        j                  t$              rt        j                  t$              nddt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      t        j                  |      dz  }dd|iz  }t        t        j                   |            dx}x}}|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}	x}
}y)u   Gemini evidence 도착 (GEMINI_COMPLETED) 후 → 4 gate 모두 PASS → AUTO_MERGE_ALLOWED.
    OWNER trigger 는 호출되지 않아야 함 (이미 evidence 있음).audit.jsonldecision.jsonr   r   r   r   r   r   r   r	   r   r   r   Nz*assert %(py2)s
{%(py2)s = %(py0)s.passed
}r   r   r   r   rD   r   r   r   Eassert not %(py4)s
{%(py4)s = %(py2)s
{%(py2)s = %(py0)s.exists
}()
}r   )rA   r   r   r   r6   r   r   r   r	   r   r   r   r   r   r   r   r   passedr   r   )r>   r   rw   rD   r   r   r   r   r   r   r   r   r   @py_format3r   r   r   r   r   s                      r!   Ctest_evaluate_with_owner_trigger_evidence_present_proceeds_to_merger     s)    8)+<=M)J.M	& !
B
 
.
.%#!( / C <<-<-----<-------3---3---<------------------:::33:~#!#!####!######3###3######~###~######!#########%#%%%%%%%%%%%}%%%}%%%#%%%%%%%%%%r#   c                   t        |        | dz  }| dz  }t        dt        d      }|j                  |dd||      }|j                  }|t
        k7  }|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                  }|t        k(  }|st        j                  d|fd|t        f      d
t        j                         v st        j                  |      rt        j                  |      nd
t        j                  |      dt        j                         v st        j                  t              rt        j                  t              nddz  }	dd|	iz  }
t        t        j                  |
            dx}}t        |      }d}||k(  }|st        j                  d|fd||f      dt        j                         v st        j                  t              rt        j                  t              nddt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      t        j                  |      dz  }
dd|
iz  }t        t        j                  |            dx}x}}|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}x}}y)u4  owner_trigger 미주입 → 기존 evaluate() 동작 유지 (회귀 방지).

    GEMINI_UNRESOLVED_BLOCK 은 비critical 이므로 auto_handle_non_critical 에서
    NON_CRITICAL_AUTO_RESOLVED 로 변환되어 반환된다. 핵심은 OWNER_TRIGGER_REQUESTED
    가 절대 나오면 안 된다는 점.
    r   r   r   r   r   Nr   !=z0%(py2)s
{%(py2)s = %(py0)s.decision
} != %(py4)sr   r   r   r   r   r   r   r   r   r   rD   r   r   r   r   r   )rA   r6   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   )r>   r   rD   r   r   r   r   r   r   r   r   r   r   r   r   r   s                   r!   Ftest_evaluate_with_owner_trigger_no_injection_falls_back_to_unresolvedr   &  sR    8M)J.M	' !
B
 
.
.%!( / C <<2<22222<222222232223222<222222222222222222<<5<55555<555555535553555<555555555555555555~#!#!####!######3###3######~###~######!#########%#%%%%%%%%%%%}%%%}%%%#%%%%%%%%%%r#   c                *   t        |        |j                  t        t               | dz  }| dz  }t	        dt
        d      }|j                  |d|||      }|j                  }	|	t        k7  }
|
st        j                  d|
fd|	t        f      d	t        j                         v st        j                  |      rt        j                  |      nd	t        j                  |	      d
t        j                         v st        j                  t              rt        j                  t              nd
dz  }dd|iz  }t        t        j                   |            dx}	}
t#        |      }d}||k(  }|st        j                  d|fd||f      dt        j                         v st        j                  t"              rt        j                  t"              nddt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      t        j                  |      dz  }dd|iz  }t        t        j                   |            dx}x}}|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}	x}
}y)uJ   queue_predecessors_open > 0 → trigger 호출 0. mock counter 로 검증.r   r   r   r   r   r   r   r   r   r   r   r   r   Nr   r   r   r   rD   r   r   r   r   r   rA   r   r   r   r6   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r>   r   rw   rD   r   r   r   r   r   r   r   r   r   r   r   r   r   r   s                     r!   =test_evaluate_with_owner_trigger_non_queue_head_skips_triggerr   L  s    8)+<=M)J.M	' !
B
 
.
.%#!( / C <<2<22222<222222232223222<222222222222222222~#!#!####!######3###3######~###~######!#########%#%%%%%%%%%%%}%%%}%%%#%%%%%%%%%%r#   c           	     8   t        |        |j                  t        t               |j                  dt               |j                  dd       | dz  }| dz  }t        dt        d      }|j                  |d|||	      }	|	j                  }
|
t        k(  }|st        j                  d
|fd|
t        f      dt        j                         v st        j                  |	      rt        j                  |	      ndt        j                  |
      dt        j                         v st        j                  t              rt        j                  t              nddz  }dd|iz  }t!        t        j"                  |            dx}
}t%        |      }d}||k(  }|st        j                  d
|fd||f      dt        j                         v st        j                  t$              rt        j                  t$              nddt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      t        j                  |      dz  }dd|iz  }t!        t        j"                  |            dx}x}}|d   d   }|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    }|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}d!} |||      }t        |v}
|
s"t        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%t        j                  |      t        j                  |      t        j                  |      t        j                  |      d&z  }d'd(|iz  }t!        t        j"                  |            dx}
x}x}x}}|j&                  }d }d!} |||      }t        |v}
|
s"t        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%t        j                  |      t        j                  |      t        j                  |      t        j                  |      d&z  }d'd(|iz  }t!        t        j"                  |            dx}
x}x}x}}t%        |      }d}||k(  }|st        j                  d
|fd||f      dt        j                         v st        j                  t$              rt        j                  t$              ndd)t        j                         v st        j                  |      rt        j                  |      nd)t        j                  |      t        j                  |      dz  }dd|iz  }t!        t        j"                  |            dx}x}}t        dt(        d      }|j+                  |d*      }|j                  }
|
t,        k(  }|st        j                  d
|fd|
t,        f      d+t        j                         v st        j                  |      rt        j                  |      nd+t        j                  |
      d,t        j                         v st        j                  t,              rt        j                  t,              nd,dz  }dd|iz  }t!        t        j"                  |            dx}
}t%        |      }d}||k(  }|st        j                  d
|fd||f      dt        j                         v st        j                  t$              rt        j                  t$              ndd)t        j                         v st        j                  |      rt        j                  |      nd)t        j                  |      t        j                  |      dz  }dd|iz  }t!        t        j"                  |            dx}x}}|d   d   }|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    }|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}d!} |||      }t        |v}
|
s"t        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-t        j                  |      t        j                  |      t        j                  |      t        j                  |      d&z  }d'd(|iz  }t!        t        j"                  |            dx}
x}x}x}}|j&                  }d }d!} |||      }t        |v}
|
s"t        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-t        j                  |      t        j                  |      t        j                  |      t        j                  |      d&z  }d'd(|iz  }t!        t        j"                  |            dx}
x}x}x}}t%        |      }d}||k(  }|st        j                  d
|fd||f      dt        j                         v st        j                  t$              rt        j                  t$              nddt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      t        j                  |      dz  }dd|iz  }t!        t        j"                  |            dx}x}}y).uu  OWNER PAT trigger 호출 시 OWNER 토큰만 사용되고, BOT 토큰 머지 경로는 분리된 채
    BOT_GITHUB_TOKEN 으로 호출된다 (env mock 으로 검증).

    회장 §명시 — 두 토큰은 서로 다른 경로/env 로 격리:
      - OWNER PAT (`OWNER_GEMINI_TRIGGER_PAT`) → `/gemini review` comment only.
      - BOT_GITHUB_TOKEN → squash merge.
    BOT_GITHUB_TOKENPATHz/usr/binr   r   r   r   r   r   r   r   out1r   r   r   r   Nr   r   r   rD   r   r   r   rT   r   r   r   r   r   r   GITHUB_TOKENr   )not in)zX%(py0)s not in %(py10)s
{%(py10)s = %(py4)s
{%(py4)s = %(py2)s.get
}(%(py6)s, %(py8)s)
}_FAKE_BOT_TOKEN	owner_env)r   r   r   r   r   py10zassert %(py12)spy12rG   r   	merge_outr
   bot_env)rA   r   r   r   r   r6   r   r   r   r   r   r   r   r   r   r   r   r   r   getr   execute_bot_squash_merger
   )r>   r   rw   rD   rG   r   r   r   
pr_missingr   r   r   r   r   r   r   r   r   r   r   r   r   @py_assert7@py_assert9@py_format11@py_format13pr_evidencer   r   s                                r!   Btest_evaluate_with_owner_trigger_owner_pat_isolated_from_bot_merger   n  s    8)+<=)?;vz*M)J.M ' !J
 //%#!( 0 D ==3=33333=333333343334333=333333333333333333~#!#!####!######3###3######~###~######!#######q!%(IZ 5 $55555 $5555 555555$5555$55555555^$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"+--?
?B?-
B"???"??????"??????????????????)???)???-???
???B???"????????"+--CCC-"CC?"CCCCC?"CCCCCCC?CCC?CCCCCC)CCC)CCC-CCCCCCCCC"CCCCCCCC|!!!!!!!!!!!!3!!!3!!!!!!|!!!|!!!!!!!!!!!!! & !K
 11+P\1]I3!33333!333333393339333333333!3333!33333333|!!!!!!!!!!!!3!!!3!!!!!!|!!!|!!!!!!!!!!!!!1oe$G:1/1111/111111111/111/1111111>"5"o5555"o555"555555o555o5555555$+KK?
?B?K
B$??$?????$????????????????G???G???K???
???B???$????????$+KKCCCK$CC$CCCCC$CCCCCCCCCCCCCCCCGCCCGCCCKCCCCCCCCC$CCCCCCCC~#!#!####!######3###3######~###~######!#######r#   c                   t        |        |j                  t        d       | dz  }| dz  }t        dt        d      }|j                  |d|||      }|j                  }	|	t        k7  }
|
st        j                  d	|
fd
|	t        f      dt        j                         v st        j                  |      rt        j                  |      ndt        j                  |	      dt        j                         v st        j                  t              rt        j                  t              nddz  }dd|iz  }t        t        j                  |            dx}	}
t!        |      }d}||k(  }|st        j                  d|fd||f      dt        j                         v st        j                  t               rt        j                  t               nddt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      t        j                  |      dz  }dd|iz  }t        t        j                  |            dx}x}}y)u   OWNER PAT env 미설정 → trigger 가 REJECT → 기존 evaluate 결과 그대로 (재시도 대기).

    OWNER_TRIGGER_REQUESTED 는 trigger outcome == "ok" 일 때만 반환된다.
    F)raisingr   r   r   r   r   r   r   r   r   r   r   r   r   Nr   r   r   rD   r   r   r   )rA   delenvr   r6   r   r   r   r   r   r   r   r   r   r   r   r   r   r>   r   rw   rD   r   r   r   r   r   r   r   r   r   r   r   r   r   s                    r!   ?test_evaluate_with_owner_trigger_rejected_falls_back_to_outcomer    s    8)59M)J.M	' !
B
 
.
.%#!( / C <<2<22222<222222232223222<222222222222222222~#!#!####!######3###3######~###~######!#######r#   c                   t        |        |j                  t        t               | dz  }| dz  }t	        dt
        dd      }|j                  |d      }|j                  }	|	t        k(  }
|
st        j                  d|
fd	|	t        f      d
t        j                         v st        j                  |      rt        j                  |      nd
t        j                  |	      dt        j                         v st        j                  t              rt        j                  t              nddz  }dd|iz  }t        t        j                   |            dx}	}
|j"                  }	d}|	|k(  }
|
st        j                  d|
fd|	|f      d
t        j                         v st        j                  |      rt        j                  |      nd
t        j                  |	      t        j                  |      dz  }dd|iz  }t        t        j                   |            dx}	x}
}|j$                  d   }d}
||
k(  }|slt        j                  d|fd||
f      t        j                  |      t        j                  |
      dz  }dd|iz  }t        t        j                   |            dx}x}}
|j$                  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}}
|j&                  }	|	 }
|
sydd
t        j                         v st        j                  |      rt        j                  |      nd
t        j                  |	      dz  }t        t        j                   |            dx}	}
y)u^  회장 §명시 11번 — Gemini evidence commit_id 가 현재 head_sha 와 다르면 stale.

    gemini_status == GEMINI_COMPLETED 라도 gemini_commit_id != head_sha 면
    STALE_EVIDENCE_BLOCK (비critical, 다음 사이클 재검증 가능). 호출부가 BOT 머지
    경로로 잘못 진입하지 않게 4 gate 단계에서 차단된다.
    r   r   znewhead-after-update-branchzoldhead-before-update-branchr   r+   r0   r3   r2   r   r   r   r   r   r   r   r   N(gemini_evidence_stale_commit_id_mismatchr   r   r   r   evidence_commit_idr   r   current_headz3assert not %(py2)s
{%(py2)s = %(py0)s.is_critical
}r   )rA   r   r   r   r6   r   check_ci_gemini_clean_sha_lockr   r   r   r   r   r   r   r   r   r   r   r   is_critical)r>   r   rw   rD   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   s                      r!    test_stale_evidence_blocks_merger    s[    8)+<=M)J.M	.&7 !	
B 
1
1
6 2 C <</</////<///////3///3///<//////////////////::CCC:CCCCC:CCCCCCC3CCC3CCC:CCCCCCCCCCC99)*L.LL*.LLLLL*.LLLL*LLL.LLLLLLLL99^$E(EE$(EEEEE$(EEEE$EEE(EEEEEEEEssr#   c                   t        |        |j                  t        t               | dz  }| dz  }t	        dt
        dd      }|j                  |d|||      }|j                  }	|	t        k7  }
|
st        j                  d|
fd	|	t        f      d
t        j                         v st        j                  |      rt        j                  |      nd
t        j                  |	      dt        j                         v st        j                  t              rt        j                  t              nddz  }dd|iz  }t        t        j                   |            dx}	}
t#        |      }d}||k(  }|st        j                  d|fd||f      dt        j                         v st        j                  t"              rt        j                  t"              nddt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      t        j                  |      dz  }dd|iz  }t        t        j                   |            dx}x}}y)u   evaluate() 전체 파이프라인에서도 stale evidence 가 안전하게 차단되고 OWNER
    trigger 가 호출되지 않는지 검증.r   r   newheadoldheadr   r  r   r   r   r   r	   r   r   r   Nr   r   r   rD   r   r   r   )rA   r   r   r   r6   r   r   r   r	   r   r   r   r   r   r   r   r   r   r  s                    r!   5test_stale_evidence_via_evaluate_returns_non_criticalr    s    8)+<=M)J.M	&" !	
B 
.
."#!( / C <<-<-----<-------3---3---<------------------~#!#!####!######3###3######~###~######!#######r#   c                   t        dt        dd      }|j                  |d      }|j                  }|t        k(  }|st        j                  d|fd|t        f      dt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      dt        j                         v st        j                  t              rt        j                  t              ndd	z  }d
d|iz  }t        t        j                  |            dx}}|j                  }d}||k(  }|st        j                  d|fd||f      dt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      t        j                  |      dz  }	dd|	iz  }
t        t        j                  |
            dx}x}}y)u?   gemini_commit_id == head_sha 면 정상 통과 (회귀 방지).zsamehead-001r   r  r   r   r   r   r	   r   r   r   Nall_gates_cleanr   r   r   r   )r6   r   r	  r   r	   r   r   r   r   r   r   r   r   r   )r>   r   r   r   r   r   r   r   r   r   r   s              r!   'test_gemini_commit_id_match_passes_gater    s*   
 
&' !	
B 
1
1
' 2 C <<-<-----<-------3---3---<------------------::***:*****:*******3***3***:***********r#   c                R   t        dt        dd      }|j                  |d      }|j                  }|t        k(  }|st        j                  d|fd|t        f      dt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      d	t        j                         v st        j                  t              rt        j                  t              nd	d
z  }dd|iz  }t        t        j                  |            dx}}y)ua   gemini_commit_id 가 빈 문자열 (정보 미제공) 이면 stale 검사 skip — 하위 호환.anyheadr   r   r  r   r   r   r   r	   r   r   r   N)r6   r   r	  r   r	   r   r   r   r   r   r   r   r   )r>   r   r   r   r   r   r   r   s           r!   -test_gemini_commit_id_empty_skips_stale_checkr  0  s    
 
& !	
B 
1
1
" 2 C <<-<-----<-------3---3---<------------------r#   c                *   t        |        |j                  t        t               | dz  }| dz  }t	        dt
        d      }|j                  |d|||      }|j                  }	|	t        k7  }
|
st        j                  d|
fd	|	t        f      d
t        j                         v st        j                  |      rt        j                  |      nd
t        j                  |	      dt        j                         v st        j                  t              rt        j                  t              nddz  }dd|iz  }t        t        j                   |            dx}	}
t#        |      }d}||k(  }|st        j                  d|fd||f      dt        j                         v st        j                  t"              rt        j                  t"              nddt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      t        j                  |      dz  }dd|iz  }t        t        j                   |            dx}x}}|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}	x}
}y)u   회장 §명시 11번 — current head 미확정 (`pr.head_sha != head_sha_at_lock`) 상태에서는
    OWNER PAT trigger 발사 금지. update-branch 직후 새 head 가 생긴 경우 다음 사이클
    재검증으로 미룬다.
    r   r   znewhead-after-rebaser   r   zoldhead-lockedr   r   r   r   r   r   r   r   Nr   r   r   rD   r   r   r   r   r   r   r   s                     r!   $test_head_sha_changed_blocks_triggerr  C  s    8)+<=M)J.M	'' !
B
 
.
.)#!( / C <<2<22222<222222232223222<222222222222222222~#!#!####!######3###3######~###~######!#########%#%%%%%%%%%%%}%%%}%%%#%%%%%%%%%%r#   c                   t        |        |j                  t        t               | dz  }| dz  }t	        dt
        d      }|j                  |d|||      }|j                  }	|	t        k(  }
|
st        j                  d|
fd|	t        f      d	t        j                         v st        j                  |      rt        j                  |      nd	t        j                  |	      d
t        j                         v st        j                  t              rt        j                  t              nd
dz  }dd|iz  }t        t        j                   |            dx}	}
t#        |      }d}||k(  }|st        j                  d|fd||f      dt        j                         v st        j                  t"              rt        j                  t"              nddt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      t        j                  |      dz  }dd|iz  }t        t        j                   |            dx}x}}y)uJ   head_sha == head_sha_at_lock 이면 정상 trigger 진행 (회귀 방지).r   r   zstable-headr   r   r   r   r   r   r   r   r   r   Nr   r   r   rD   r   r   r   rA   r   r   r   r6   r   r   r   r   r   r   r   r   r   r   r   r   r   r  s                    r!   "test_head_sha_match_still_triggersr  g  s}    8)+<=M)J.M	' !
B
 
.
.&#!( / C <<2<22222<222222232223222<222222222222222222~#!#!####!######3###3######~###~######!#######r#   c                   t        |        |j                  t        t               | dz  }| dz  }t	        ddt
        d      }|j                  |d|||      }|j                  }	|	t        k7  }
|
st        j                  d|
fd	|	t        f      d
t        j                         v st        j                  |      rt        j                  |      nd
t        j                  |	      dt        j                         v st        j                  t              rt        j                  t              nddz  }dd|iz  }t        t        j                   |            dx}	}
t#        |      }d}||k(  }|st        j                  d|fd||f      dt        j                         v st        j                  t"              rt        j                  t"              nddt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      t        j                  |      dz  }dd|iz  }t        t        j                   |            dx}x}}y)uT  회장 Codex G1 round 2 Critical — CI 실패 상황에서 OWNER trigger 발사 0.

    `ci_required_all_success=False` → `evaluate()` 가 CI_FAILURE_BLOCK 반환 →
    `evaluate_with_owner_trigger()` 가 `_gemini_unresolved_allowed=False` 로
    판정 → trigger 호출 0. 회장 §명시 "evidence missing 일 때만" 강제.
    r   r   zheadsha-ci-failFr   )r+   r/   r0   r2   r   r   r   r   r   r   r   r   Nr   r   r   rD   r   r   r   r  r  s                    r!   &test_g1_r2_ci_failure_does_not_triggerr    s    8)+<=M)J.M	" %' !	
B 
.
.*#!( / C <<2<22222<222222232223222<222222222222222222~#!#!####!######3###3######~###~######!#######r#   c                   t        |        |j                  t        t               | dz  }| dz  }t	        dt
        d      }|j                  |d|||      }|j                  }	|	t        k7  }
|
st        j                  d|
fd|	t        f      d	t        j                         v st        j                  |      rt        j                  |      nd	t        j                  |	      d
t        j                         v st        j                  t              rt        j                  t              nd
dz  }dd|iz  }t        t        j                   |            dx}	}
t#        |      }d}||k(  }|st        j                  d|fd||f      dt        j                         v st        j                  t"              rt        j                  t"              nddt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      t        j                  |      dz  }dd|iz  }t        t        j                   |            dx}x}}y)u   SCOPE_EXPANSION (critical) 상황에서도 OWNER trigger 발사 0.

    회장 §명시: critical 차단 상황은 `/gemini review` 트리거 대상 X.
    r   r   zheadsha-scoper   r   r   r   r   r   r   r   r   r   Nr   r   r   rD   r   r   r   )rA   r   r   r   r6   r   r   r   r   r   r   r   r   r   r   r   r   r   r  s                    r!   2test_g1_r2_gemini_scope_expansion_does_not_triggerr    s}    8)+<=M)J.M	 , !
B
 
.
.(#!( / C <<2<22222<222222232223222<222222222222222222~#!#!####!######3###3######~###~######!#######r#   c           	         ddl }dd}dd}dd}t        j                  t        t              5  t        |||ddd	
       ddd       y# 1 sw Y   yxY w)u  회장 Codex G1 round 2 High — token_env override 화이트리스트 강제.

    BOT_GITHUB_TOKEN 등 OWNER_GEMINI_TRIGGER_PAT 외 env 이름을 token_env 로
    넘기면 `__init__` 단계에서 즉시 ValueError. doctrine 위반 시나리오 API 차단.
    r   Nc                    t               S rI   r{   rS   s     r!   rY   zHtest_g1_r2_token_env_override_rejected_at_constructor.<locals>.gh_runner  r   r#   c                     y rI   rC   )r\   s    r!   r]   zKtest_g1_r2_token_env_override_rejected_at_constructor.<locals>.audit_writer      r#   c                     y rI   rC   r_   s     r!   rc   zNtest_g1_r2_token_env_override_rejected_at_constructor.<locals>.decision_writer  r"  r#   )matchrd   re   r   )rY   r]   rc   rl   rm   	token_envro   rs   rv   )r   pytestraises
ValueErrorr   r   )r>   r   r   rY   r]   rc   s         r!   5test_g1_r2_token_env_override_rejected_at_constructorr)    sV      
z);	< 
%+!(	

 
 
s   AAc                0   ddl |j                  t        t               | dz  }| dz  }ddig dfd}g d fd}d!d}t	        |||d	d
d       }|j                  dddd||      }|j                  }	d}
|	|
k(  }|st        j                  d|fd|	|
f      dt        j                         v st        j                  |      rt        j                  |      ndt        j                  |	      t        j                  |
      dz  }dd|iz  }t        t        j                  |            dx}	x}}
|j                  ddd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}}
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}}y)"u/  회장 Codex G1 round 2 High — gh 실패 후 marker 정리 → 재시도 가능.

    gh runner 가 rc!=0 으로 실패하면 marker 가 자동 정리되어, 같은 PR/head 에
    대한 다음 사이클 trigger 가 dedupe 차단 없이 진행 가능해야 한다.
    self-resume 요구 박제.
    r   Nr   r   nc                    dxx   dz  cc<   d   dk(  r j                   g ddd      }n j                   g ddd      }j                  |       |S )Nr+  r   r   	temporaryr   r   ok)r    rV   )r   rT   r   
call_count
gh_outputsr   s      r!   rY   zGtest_g1_r2_marker_cleanup_on_gh_failure_allows_retry.<locals>.gh_runner  sb    31c?a-*--2!BWbcC-*--2!DY[\C#
r#   c                :    j                  t        |              y rI   r[   r   s    r!   r]   zJtest_g1_r2_marker_cleanup_on_gh_failure_allows_retry.<locals>.audit_writer  r   r#   c                    t        | |       y rI   )r   r_   s     r!   rc   zMtest_g1_r2_marker_cleanup_on_gh_failure_allows_retry.<locals>.decision_writer  s    GT*r#   rd   re   c                     t         S rI   rg   rC   r#   r!   ri   zFtest_g1_r2_marker_cleanup_on_gh_failure_allows_retry.<locals>.<lambda>  rj   r#   rk   c   z	retry-shamissing_for_current_head)r   r+   queue_positiongemini_evidence_stater   r   failedr   )z/%(py2)s
{%(py2)s = %(py0)s.outcome
} == %(py5)sr   r   r   r   r.  out2r   r   r   r   r   ro   rs   rv   )r   r   r   r   r   trigger_gemini_reviewoutcomer   r   r   r   r   r   r   r   )r>   r   r   r   rY   r]   rc   triggerr   r   r   r   r   r   r9  r   r   r   r   rJ   r/  r0  r   s                      @@@@r!   4test_g1_r2_marker_cleanup_on_gh_failure_allows_retryr=    s    )+<=M)J.MqJ46J )+K)+ !'G ((8!( ) D <<#8#<8####<8######4###4###<###8####### ((8!( ) D <<4<4<444<4c?a?a?a?ar#   )r   r   r   )r   r   r   rb   r   rb   rq   rr   )r*   r   r+   rb   r,   rb   r-   rb   r.   rp   r/   boolr0   rb   r1   rb   r2   r   r3   rb   rq   r   )r>   r   rq   r   )rq   list[dict[str, Any]])rD   r?  rM   r?  rO   r?  rq   r   )r>   r   rG   r?  rJ   r?  rq   r   )r>   r   r   r   rw   r   rD   r?  r   pytest.MonkeyPatchrq   ru   )r>   r   r   r   rD   r?  rq   ru   )r>   r   r   r   rw   r   rD   r?  rG   r?  r   r@  rq   ru   )r>   r   r   r   rq   ru   )r>   r   r   r@  rq   ru   )I__doc__
__future__r   builtinsr   _pytest.assertion.rewrite	assertionrewriter   r   r   syspathlibr   typingr   r   r   r&  __file__resolveparentsWORKSPACE_ROOTrb   ra   insertanu_v2.merge_queue_executorr	   r
   r   r   r   r   r   r   r   r   r   anu_v2.owner_trigger_patr   r   r   r   r"   r   r   rh   r6   rA   fixturerD   rG   rJ   rM   rO   rw   r   r   r   r   r   r   r  r  r  r  r  r  r  r  r  r)  r=  rC   r#   r!   <module>rR     s  ( #     
  ) )  h'')11!4~chh&HHOOAs>*+    e 3 "'	
 %)$ %)*%#$#  	
  ! "    !!" #$ %B(  
  
       (- ) 	 8 & & 	 <0303 03 #03 )	03
 $03 
03h&& & #& )	&
 $& 
&F"&"& "& )"& 
	"&L&& & #& )	&
 $& 
&DB$B$ B$ #B$ )	B$
 'B$ $B$ 
B$L $ $  $ # $ )	 $
 $ $ 
 $H!! ! #! )	!
 $! 
!H$$ $ #$ )	$
 $$ 
$B++ + 
+&.. . 
.&!&!& !& #!& )	!&
 $!& 
!&H$$ $ #$ )	$
 $$ 
$<#$#$ #$ ##$ )	#$
 $#$ 
#$L$$ $ #$ )	$
 $$ 
$N

#
 

>C C #C  
C r#   