
    ^jVR                    Z   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ZddlmZ  ee      j!                         j"                  d   Zedz  dz  Zi e
j(                  dd	dd	d
ZdZddddZdddZddZd dZd!dZd"dZd#d$dZd%dZdd&dZd'dZ d(dZ!d(dZ"d(dZ#d(dZ$y))u:  task-2818 회귀 테스트 — scope-guard stale-base 오탐 근절 (양방향).

테스터: 벨레스(Veles), dev6팀

배경 (task-2818):
    finish-task.sh scope-guard 는 diff 계산 기준(base)을 잘못 잡으면 두 가지
    실패 모드를 낳는다.
      (a) stale base(예: task 분기 이전의 더 오래된 커밋)를 쓰면, task 분기
          "이전"에 main 에 머지된 무관한 변경까지 diff 에 섞여 들어와
          scope 위반으로 오탐(false positive)한다.
      (b) base 를 전혀 확정하지 못했는데 빈 diff 로 "통과"시켜 버리면
          (fail-open) 실제 위반이 있어도 조용히 스킵된다.
    task-2818 수정 후 base 해석 우선순위는 다음과 같다:
      1순위: memory/events/<task_id>.worktree-base.json 의 base_sha (authoritative)
      2순위: 없으면 git fetch origin <main> 후 merge-base(origin/<main>, HEAD)
      3순위: 그래도 없으면 fail-closed(exit 1) — 빈 diff로 조용히 PASS 금지
      + diff 계산 전 `git merge-base --is-ancestor <base> HEAD` ancestor 가드.
        base 가 HEAD 의 조상이 아니면 fail-closed.

이 테스트는:
  - 위 base 해석 로직을 (scripts/ 를 건드리지 않고) 이 테스트 파일 내부의
    독립 bash 재현 스크립트(_RESOLVE_SCOPE_BASE_SH)로 재현한다. 실제
    finish-task.sh 의 scope-guard 블록(약 807-891행)이 구현해야 하는
    사양을 그대로 인코딩한 것이며, task-scope-guard.sh 는 실제 스크립트를
    subprocess 로 직접 호출해 검증한다(가장 직접적인 부분).
  - tmp_path 에 실제 git repo(+origin bare remote)를 만들어 커밋 이력을
    재현하고, 실제 diff 계산 결과를 실제 task-scope-guard.sh 에 먹인다.

케이스:
  T1 test_stale_base_false_positive_vs_correct_base_pass
      오탐0 핵심 회귀: 올바른 base(분기점, worktree-base.json 기록)로 계산하면
      scope 내 파일만 diff 에 잡혀 PASS. 대조군으로 stale base 를 쓰면
      무관한 커밋의 파일(server/main.py)이 diff 에 섞여 위반으로 뜨는 것을
      별도로 보여준다(오탐 재현).
  T2 test_real_violation_detected_with_correct_base
      올바른 base 를 쓰더라도 task 브랜치 자체가 scope 밖 파일을 건드리면
      진짜 위반은 여전히 검출된다(FAIL + scope-violation.json).
  T3 test_fail_closed_when_base_undeterminable
      worktree-base.json 도 없고 origin fetch/merge-base 도 실패하는 상황에서
      base 해석이 fail-closed(exit 1) 하고, 빈 diff로 조용히 PASS 되는 일이
      없음을 명시적으로 검증한다.
  T4 test_ancestor_guard_rejects_non_ancestor_base
      worktree-base.json 의 base_sha 가 HEAD 의 조상이 아니면(다른 브랜치의
      커밋) ancestor 가드가 fail-closed 시킴을 검증한다.
    )annotationsN)Path   scriptsztask-scope-guard.shtestzt@t.com)GIT_AUTHOR_NAMEGIT_AUTHOR_EMAILGIT_COMMITTER_NAMEGIT_COMMITTER_EMAILu@  #!/bin/bash
# 사용법: resolve_scope_base.sh <task_id> <scope_proj_dir> <events_dir>
# stdout: 확정된 SCOPE_BASE sha (성공 시)
# exit 0 = base 확정 + ancestor 검증 통과
# exit 1 = fail-closed (base 미확정 또는 ancestor 아님)
set -euo pipefail

TASK_ID="$1"
SCOPE_PROJ_DIR="$2"
EVENTS_DIR="$3"

MAIN_BRANCH=$(git -C "$SCOPE_PROJ_DIR" rev-parse --verify main >/dev/null 2>&1 && echo main || echo master)

SCOPE_BASE=""
BASE_SOURCE=""

# 1순위: worktree-base.json (authoritative)
WT_BASE_FILE="$EVENTS_DIR/${TASK_ID}.worktree-base.json"
if [ -f "$WT_BASE_FILE" ]; then
    SCOPE_BASE=$(WT_BASE_FILE="$WT_BASE_FILE" python3 -c "import json,os;print(json.load(open(os.environ['WT_BASE_FILE'])).get('base_sha') or '')" 2>/dev/null || echo "")
    if [ -n "$SCOPE_BASE" ]; then
        BASE_SOURCE="worktree-base.json"
    fi
fi

# 2순위: git fetch origin <main> 후 merge-base(origin/<main>, HEAD)
if [ -z "$SCOPE_BASE" ]; then
    if git -C "$SCOPE_PROJ_DIR" fetch origin "$MAIN_BRANCH" >/dev/null 2>&1; then
        SCOPE_BASE=$(git -C "$SCOPE_PROJ_DIR" merge-base "origin/${MAIN_BRANCH}" HEAD 2>/dev/null || echo "")
        if [ -n "$SCOPE_BASE" ]; then
            BASE_SOURCE="merge-base(origin/${MAIN_BRANCH})"
        fi
    fi
fi

# 3순위: fail-closed — 빈 diff로 조용히 PASS 금지
if [ -z "$SCOPE_BASE" ]; then
    echo "[SCOPE-BASE] ERROR: base 확정 불가 (worktree-base.json 없음 + origin merge-base 실패) — fail-closed" >&2
    exit 1
fi

# ancestor 가드: base 가 HEAD 의 조상이 아니면 fail-closed
if ! git -C "$SCOPE_PROJ_DIR" merge-base --is-ancestor "$SCOPE_BASE" HEAD 2>/dev/null; then
    echo "[SCOPE-BASE] ERROR: base($SCOPE_BASE) 는 HEAD 의 조상이 아님 — fail-closed" >&2
    exit 1
fi

echo "$SCOPE_BASE"
echo "[SCOPE-BASE] OK: source=$BASE_SOURCE base=$SCOPE_BASE" >&2
exit 0
T)checkc          	     v    t        j                  ddt        |       ddddgt        |      z   ddt        |      S )Ngit-Cz-czuser.email=t@t.comzuser.name=testTcapture_outputtextenvr   )
subprocessrunstrlistGIT_ENV)repor   argss      =/home/jay/workspace/tests/test_scope_guard_stale_base_2818.py_gitr      sC    >>	c$i';TCSTW[\`Waa     c                L    t        | d|      j                  j                         S )Nz	rev-parse)r   stdoutstrip)r   refs     r   
_rev_parser"      s     k3'..4466r   c                d    | j                   j                  dd       | j                  |d       y )NTparentsexist_okutf-8encoding)parentmkdir
write_text)pathcontents     r   _writer/      s)    KKdT2OOGgO.r   c                N    t        | dd       t        | dd|       t        |       S )Naddz-Acommitz-m)r   r"   )r   messages     r   _commit_allr4      s'    udxw'dr   c           
     r   | dz  }|j                          t        j                  dddddt        |      gddt        d       | d	z  }t        j                  ddddt        |      gddt        d       t        |d
ddt        |             t        |dz  d       t        |d       t        |ddd       ||fS )uV   origin(bare) + clone(main 브랜치, 초기 커밋 C0) 생성. (clone, origin) 반환.z
origin.gitr   initz--bare-bmainTr   r   remoter1   origin	README.mdinit
zC0: initpush)r+   r   r   r   r   r   r/   r4   )tmp_pathr:   clones      r   _init_origin_and_cloner@      s    $F
LLNNN	$F<$G4
 vENN	fc%j1$G4 	%3v;7
5;)z"&)&=r   c                    | j                  dd       | | dz  }t        |t        j                  ||d             |S )NTr$   .worktree-base.json)task_idbase_shar+   r/   jsondumps)
events_dirrC   rD   ps       r   write_worktree_baserJ      sD    TD1y 344A
1djjW(CDEHr   c           	         | j                  dd       |dd||xs g g dddd}| | d	z  }t        |t        j                  |             |S )
NTr$   z2026-07-21T00:00:00deadbeeftiered   )pathsforbidden_pathscommandsmerge_policy	ttl_hours)rC   captured_atsource_sha256allowed_resourcesz.jsonrE   )caps_dirrC   rO   	forbiddensnaprI   s         r   write_snapshotrZ      se    NN4$N/,#(B$
	D 	gYe$$A
1djjHr   c           	     f   t        j                  ddd      5 }|j                  t               |j                  }ddd       	 t        j                  d| t        |      t        |      gddt              t        j                  |       S # 1 sw Y   SxY w# t        j                         w xY w)	u1   task-2818 base 해석 재현 스크립트 실행.wz.shFsuffixdeleteNbashTr   r   r   )tempfileNamedTemporaryFilewrite_RESOLVE_SCOPE_BASE_SHnamer   r   r   r   osunlink)rC   scope_proj_dirrH   fscript_paths        r   resolve_scope_baserl      s    		$	$Su	E 	&'ff~~['3~+>JPd

 			+  			+s   "B3B BB0c                    t        | dd| d|       }|j                  j                         D cg c]#  }|j                         s|j                         % c}S c c}w )Ndiffz--name-onlyz..)r   r   
splitlinesr    )r   baseheadrlines        r   compute_diffrt      sL    T6=TF"TF*;<A%&XX%8%8%:KTdjjlDJJLKKKs   AAc                   t        j                  ddd      5 }|j                  dj                  |      |rdndz          |j                  }ddd       	 t
        j                  j                         }t        |      |d<   t        j                  d	t        t              | gd
d
|      t        j                  |       S # 1 sw Y   uxY w# t        j                         w xY w)u=   실제 scripts/task-scope-guard.sh 를 subprocess 로 호출.r\   z.txtFr]   
 N	WORKSPACEr`   Tra   )rb   rc   rd   joinrf   rg   environcopyr   r   r   SCOPE_GUARD_SCRIPTrh   )rC   
diff_files	workspacerj   	diff_filer   s         r   run_scope_guardr      s    		$	$S	F !			*%DEFF	jjooy>K~~S+,gyAd

 			)  			)s   4CAC C
C$c                
   d}t        |       \  }}| dz  }|dz  dz  }|dz  dz  }t        |dz  dz  d       t        |d	z  d
z  d       t        |d      }t        |ddd       t        |ddd       t        |dz  dz  d       t        |d      }t	        |      }	|	|k(  }
|
st        j                  d|
fd|	|f      dt        j                         v st        j                  |	      rt        j                  |	      nddt        j                         v st        j                  |      rt        j                  |      nddz  }dd|iz  }t        t        j                  |            d }
t        |||       t        ||dg       t        |||      }|j                   }
d }|
|k(  }|st        j                  d|fd!|
|f      d"t        j                         v st        j                  |      rt        j                  |      nd"t        j                  |
      t        j                  |      d#z  }t        j"                  d$|j$                         d%z   d&|iz  }t        t        j                  |            d x}
x}}|j&                  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*z   d|iz  }t        t        j                  |            d }
t+        ||      }d+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/|       d0z   d1|iz  }t        t        j                  |            d x}
}d2}||v}|st        j                  d3|fd4||f      t        j                  |      d-t        j                         v st        j                  |      rt        j                  |      nd-d5z  }d6d1|iz  }t        t        j                  |            d x}}d7}||v}|st        j                  d3|fd4||f      t        j                  |      d-t        j                         v st        j                  |      rt        j                  |      nd-d5z  }d6d1|iz  }t        t        j                  |            d x}}t-        |||      }|j                   }
d }|
|k(  }|st        j                  d|fd!|
|f      d8t        j                         v st        j                  |      rt        j                  |      nd8t        j                  |
      t        j                  |      d#z  }t        j"                  d9|j                    d:|j&                   d;|j$                         d%z   d&|iz  }t        t        j                  |            d x}
x}}d<}|j&                  }||v }|st        j                  d=|fd>||f      t        j                  |      d8t        j                         v st        j                  |      rt        j                  |      nd8t        j                  |      d?z  }d@d&|iz  }t        t        j                  |            d x}x}}t        |dAdBdC      }|j&                  j/                         D cg c]  }|j)                         s| }}|d    }||k7  }
|
st        j                  dD|
fdE||f      dFt        j                         v st        j                  |      rt        j                  |      ndFd(t        j                         v st        j                  |      rt        j                  |      nd(dz  }dd|iz  }t        t        j                  |            d }
t+        ||      }d2}||v }|st        j                  d=|fdG||f      t        j                  |      dHt        j                         v st        j                  |      rt        j                  |      ndHd5z  }t        j"                  dI|       d0z   d1|iz  }t        t        j                  |            d x}}d7}||v }|st        j                  d=|fdG||f      t        j                  |      dHt        j                         v st        j                  |      rt        j                  |      ndHd5z  }d6d1|iz  }t        t        j                  |            d x}}d+}||v }|st        j                  d=|fdG||f      t        j                  |      dHt        j                         v st        j                  |      rt        j                  |      ndHd5z  }d6d1|iz  }t        t        j                  |            d x}}t-        |||      }|j                   }
dJ}|
|k(  }|st        j                  d|fd!|
|f      dKt        j                         v st        j                  |      rt        j                  |      ndKt        j                  |
      t        j                  |      d#z  }t        j"                  dL|j                          d%z   d&|iz  }t        t        j                  |            d x}
x}}dM |j$                  j/                         D        }
t1        |
      }|st        j"                  dN|j$                         dOz   dPt        j                         v st        j                  t0              rt        j                  t0              ndPt        j                  |
      t        j                  |      dQz  }t        t        j                  |            d x}
}y c c}w )RNztest-2818-t1r~   memoryeventscapabilitiesservermain.pyprint('server')
docszx.mdz# doc
z7C1: unrelated merge to main (server/main.py, docs/x.md)r=   r:   r8   checkoutr7   task-branchr   finish-task.sh#!/bin/bash
echo patched
zC2: task work, scripts only==z%(py0)s == %(py2)srq   c2py0py2assert %(py4)spy4
scripts/**rO   r   z2%(py2)s
{%(py2)s = %(py0)s.returncode
} == %(py5)sresolvedr   r   py5   base 해석 실패: 
>assert %(py7)spy7
scope_basec1u@   worktree-base.json 의 base_sha(C1)가 채택되어야 함, got z
>assert %(py4)szscripts/finish-task.shz%(py0)s == %(py3)scorrect_diffr   py3uM   올바른 base(C1) diff 는 scripts/finish-task.sh 만 포함해야 함, got 
>assert %(py5)sr   server/main.pynot in)z%(py1)s not in %(py3)spy1r   assert %(py5)sz	docs/x.mdresult_correctu.   올바른 base 사용 시 PASS 기대, got rc=
stdout=
stderr=PASSin)z.%(py1)s in %(py5)s
{%(py5)s = %(py3)s.stdout
})r   r   r   assert %(py7)slogz--format=%Hz	--reverse!=)z%(py0)s != %(py2)sc0)z%(py1)s in %(py3)s
stale_diffu   stale base(C0) 사용 시 C1 에서 도입된 무관한 파일(server/main.py)이 diff 에 섞여야 오탐 재현이 성립함, got r   result_staleu   stale base 를 쓰면 무관한 server/main.py 가 scope 위반으로 오탐되어야 함 (이것이 task-2818 이 고치는 버그), got rc=c              3  $   K   | ]  }d |v  
 yw)r   N ).0rs   s     r   	<genexpr>zFtest_stale_base_false_positive_vs_correct_base_pass.<locals>.<genexpr>0  s      %)D s   uF   stale base 오탐에 server/main.py 위반이 나타나야 함
stderr=z.
>assert %(py4)s
{%(py4)s = %(py0)s(%(py2)s)
}anyr   r   r   )r@   r/   r4   r   r"   
@pytest_ar_call_reprcompare@py_builtinslocals_should_repr_global_name	_safereprAssertionError_format_explanationrJ   rZ   rl   
returncode_format_assertmsgstderrr   r    rt   r   ro   r   )r>   rC   r   _r~   rH   rW   r   r   rq   @py_assert1@py_format3@py_format5r   @py_assert4@py_assert3@py_format6@py_format8r   r   @py_assert2@py_format4@py_assert0r   r   sall_shasr   r   r   s                                 r   3test_stale_base_false_positive_vs_correct_base_passr      s	   G$X.GD!;&IX%0J8#n4H 4(?Y&(;<
4&=6!9-	TT	UBvx( 	z4/
4)..0MN	T8	9BdD2:424422 
GR08W\N; "'4<HM!M!#MMM!MMMMMM8MMM8MMMMMM!MMM';HOO;L%MMMMMMMM&&(Jlll:llllll:lll:lllllllllllll_`j_klllllll  j1L45 <55  <5              6    XXdWef     /<////</////////<///<///////*;l****;l***;******l***l*******$WlIFN$$  $)  $              %    )*    99R9R8S T ''(	.2G2G1H	J     *^***6*****6****6******^***^*********** tUM;
7C::002@aaggi@H@	!B8OOO2OOOOOO2OOO2OOOOOOOOOOOOOOOOdB'J z)  z           *     *   	>>H\	K     $;*$$$$;*$$$;$$$$$$*$$$*$$$$$$$#1#z1111#z111#111111z111z1111111"7J	BL"" a "a'  "a              #    '(   	>>J>U>U=V	X    -9-@-@-K-K-M g3   g  gUfUf	PQ]QdQdPefg g`f`fg gNfNf  g g]f]f  g g]f]f g g]f]f g g gSfSfg g# As   r /r c                   d}t        |       \  }}| dz  }|dz  dz  }|dz  dz  }t        |dz  dz  d       t        |d	      }t        |d
dd       t        |ddd       t        |dz  dz  d       t        |d       t	        |||       t        ||dgdg       t        |||      }|j                  }	d}
|	|
k(  }|st        j                  d|fd|	|
f      dt        j                         v st        j                  |      rt        j                  |      ndt        j                  |	      t        j                  |
      dz  }t        j                  d|j                         dz   d|iz  }t!        t        j"                  |            d x}	x}}
|j$                  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  }d!d"|iz  }t!        t        j"                  |            d }	t)        ||      }d#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}	}t+        |||      }|j                  }	d*}
|	|
k(  }|st        j                  d|fd|	|
f      d+t        j                         v st        j                  |      rt        j                  |      nd+t        j                  |	      t        j                  |
      dz  }t        j                  d,|j$                   d-|j                         dz   d|iz  }t!        t        j"                  |            d x}	x}}
|| d.z  }|j,                  }	 |	       }|st        j                  d/      d0z   d1t        j                         v st        j                  |      rt        j                  |      nd1t        j                  |	      t        j                  |      d2z  }t!        t        j"                  |            d x}	}t/        j0                  |j3                  d34            }|d5   }||k(  }|st        j                  d|fd6||f      t        j                  |      d5t        j                         v st        j                  |      rt        j                  |      nd5d7z  }d8d)|iz  }t!        t        j"                  |            d x}}d9 |d:   D        }	t5        |	      }|sd;d<t        j                         v st        j                  t4              rt        j                  t4              nd<t        j                  |	      t        j                  |      d2z  }t!        t        j"                  |            d x}	}d= |d:   D        }	t5        |	      }|sd;d<t        j                         v st        j                  t4              rt        j                  t4              nd<t        j                  |	      t        j                  |      d2z  }t!        t        j"                  |            d x}	}y )>Nztest-2818-t2r~   r   r   r   r   r   r   zC1: unrelated merge to mainr=   r:   r8   r   r7   r   z!print('server modified by task')
z,C2: task modifies server/main.py (violation)r   z	server/**)rO   rX   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r}   r   u[   올바른 base 로도 task 자체 변경인 server/main.py 만 diff 에 잡혀야 함, got r   r   r   resultu[   base 를 올바르게 잡아도 진짜 위반(server/main.py)은 FAIL 이어야 함
stdout=r   z.scope-violation.jsonu,   scope-violation.json 이 생성되어야 함zC
>assert %(py4)s
{%(py4)s = %(py2)s
{%(py2)s = %(py0)s.exists
}()
}violation_filer   r'   r(   rC   )z%(py1)s == %(py3)sr   r   c              3  *   K   | ]  }d |d   v   yw)r   r-   Nr   r   vs     r   r   zAtest_real_violation_detected_with_correct_base.<locals>.<genexpr>a  s     J1V9,J   
violationsz,assert %(py4)s
{%(py4)s = %(py0)s(%(py2)s)
}r   c              3  *   K   | ]  }d |d   v   yw)rP   reasonNr   r   s     r   r   zAtest_real_violation_detected_with_correct_base.<locals>.<genexpr>b  s     MA AhK/Mr   )r@   r/   r4   r   rJ   rZ   rl   r   r   r   r   r   r   r   r   r   r   r   r   r    rt   r   existsrF   loads	read_textr   )r>   rC   r   r   r~   rH   rW   r   r   r   r   r   r   r   r   r   r   r}   r   r   r   r   vdatar   s                           r   .test_real_violation_detected_with_correct_baser   9  s%   G$X.GD!;&IX%0J8#n4H 4(?Y&(;<	T8	9Bvx( 	z4/
4(?Y&(LMDE
GR08W\N{mT!'4<HM!M!#MMM!MMMMMM8MMM8MMMMMM!MMM';HOO;L%MMMMMMMM&&(J:::dJ/J*+ :++  :+              ,    ffpeqr     Wj)<F  !                    !"   --	&--	:    
  WI-B"CCN  R "R"RR$RRRRRRR>RRR>RRR RRR"RRRRRRJJ~///ABE&w&&&&w&&&&&&&&&w&&&w&&&&&&&JeL6IJJ3JJJJJJJJJ3JJJ3JJJJJJJJJJJJJJM|9LMM3MMMMMMMMM3MMM3MMMMMMMMMMMMMMr   c           	        d}| dz  }|dz  dz  }|dz  dz  }|j                  dd       | dz  }|j                          t        j                  d	d
ddt        |      gddt        d       t        |dz  d       t        |d       t        ||dg       | d}||z  }|j                  } |       }	|	 }
|
sddt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      t        j                  |      t        j                  |	      dz  }t        t        j                  |            d x}x}x}x}	}
t!        |d      j"                  j%                         }d}|j&                  } |       }	||	v}|st        j(                  d|fd||	f      t        j                  |      dt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      t        j                  |	      dz  }dd|iz  }t        t        j                  |            d x}x}x}}	t+        |||      }|j,                  }d}||k(  }|st        j(                  d |fd!||f      d"t        j                         v st        j                  |      rt        j                  |      nd"t        j                  |      t        j                  |      d#z  }t        j.                  d$|j,                   d%|j"                   d&|j0                         d'z   d(|iz  }t        t        j                  |            d x}x}}|j"                  }|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                  |      t        j                  |      t        j                  |
      d+z  }t        j.                  d,|j"                        d-z   d.|iz  }t        t        j                  |            d x}x}x}x}}
g }d/}|j0                  }	|	j2                  }
 |
       }||v }|}|sd0}|j0                  }||v }|}|st        j(                  d1|fd2||f      t        j                  |      d"t        j                         v st        j                  |      rt        j                  |      nd"t        j                  |	      t        j                  |
      t        j                  |      d3z  }d4d5|iz  }|j5                  |       |st        j(                  d1fd6f      t        j                  |      d"t        j                         v st        j                  |      rt        j                  |      nd"t        j                  |      d7z  }d8d9|iz  }|j5                  |       t        j6                  |d      i z  }d:d;|iz  }t        t        j                  |            d x}x}x}x}x}	x}
x}x}x}}t9        |g |      }|j,                  }d<}||k(  }|st        j(                  d |fd!||f      d=t        j                         v st        j                  |      rt        j                  |      nd=t        j                  |      t        j                  |      d#z  }t        j.                  d>      d'z   d(|iz  }t        t        j                  |            d x}x}}|j,                  }d<}||k7  }|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.                  dA      d'z   d(|iz  }t        t        j                  |            d x}x}}y )BNztest-2818-t3r~   r   r   r   Tr$   r   r   r6   r7   r8   r   r;   r<   zC0: init, no origin remoter   r   rB   zQassert not %(py7)s
{%(py7)s = %(py5)s
{%(py5)s = (%(py0)s / %(py2)s).exists
}()
}rH   )r   r   r   r   r9   r:   r   )zM%(py1)s not in %(py7)s
{%(py7)s = %(py5)s
{%(py5)s = %(py3)s.splitlines
}()
}remotes)r   r   r   r   zassert %(py9)spy9r   r   r   r   r   uC   base 확정 불가 상황에서 fail-closed(exit 1) 기대, got rc=r   r   r   r   rw   z`%(py6)s
{%(py6)s = %(py4)s
{%(py4)s = %(py2)s
{%(py2)s = %(py0)s.stdout
}.strip
}()
} == %(py9)sr   r   r   py6r   uE   fail-closed 시 base sha 를 stdout 으로 내보내면 안 됨, got 
>assert %(py11)spy11zfail-closedu   확정 불가r   )zb%(py3)s in %(py11)s
{%(py11)s = %(py9)s
{%(py9)s = %(py7)s
{%(py7)s = %(py5)s.stderr
}.lower
}()
})r   r   r   r   r   z%(py13)spy13)z2%(py16)s in %(py20)s
{%(py20)s = %(py18)s.stderr
})py16py18py20%(py22)spy22assert %(py25)spy25r   would_be_empty_diff_resultu   대조: 빈 diff 를 그대로 scope-guard 에 넘기면 (위반 파일이 없으므로) PASS 되어버린다 — 이것이 fail-open 위험이며, base 해석이 exit 1 로 그 이전에 막아야 하는 이유다.r   z2%(py2)s
{%(py2)s = %(py0)s.returncode
} != %(py5)suZ   base 해석이 실패(rc!=0)해야 empty-diff PASS 경로 진입이 차단됨을 재확인)r+   r   r   r   r   r/   r4   rZ   r   r   r   r   r   r   r   r   r   r   r    ro   r   rl   r   r   r   lowerappend_format_boolopr   ) r>   rC   r~   rH   rW   r   r   r   r   @py_assert6@py_assert8@py_format9r   r   r   r   @py_format10r   r   @py_assert5@py_assert7@py_format12@py_assert10@py_assert15@py_assert19@py_assert17@py_format14@py_format21@py_format23@py_format24@py_format26r   s                                    r   )test_fail_closed_when_base_undeterminabler  i  s   G;&IX%0J8#n4HTD1 fDJJLNNE64T;#'dtM
4+x(238W\N; !(y(;<F
<<F<DDFDFFFFFFFFFFF
FFF
FFF<FFFDFFFFFFFFFFF4"))//1G/7--/-//8/////8////8//////7///7///-///////////!'4<H ! !#  !                  #$    NhNaNaMb c//")HOO+<	>     ?? ?    " b "b(  "b                  !    #    ')    PPXP_P_Obc      Z=YHOOYO11Y13Y=33YY(//Y/7YYYYY=3YYY=YYYYYYHYYYHYYYOYYY1YYY3YYYYYYY/YYYYYYYYY(YYY(YYY/YYYYYYYYYYYYYYY "1"i!H%00 A 0A5  0A      &    &    1    56   	p      ! !#  !                  #$    	e     r   c           	        d}t        |       \  }}| dz  }|dz  dz  }|dz  dz  }t        |      }t        |ddd       t        |d	z  d
z  d       t	        |d       t        |      }t        |dd       t        |dz  dz  d       t	        |d      }	t        |dd       t        |      }
|
|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                  |
      dt        j                         v st        j                  |      rt        j                  |      nddz  }dd|iz  }t        t        j                  |            d x}
}t        j                  ddt        |      dd|	dgddt                }|j"                  }d!}||k7  }|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|iz  }t        t        j                  |            d x}x}}t'        |||	       t)        ||d(g)       t+        |||      }|j"                  }d*}||k(  }|st        j                  d|fd+||f      d,t        j                         v st        j                  |      rt        j                  |      nd,t        j                  |      t        j                  |      d%z  }t        j$                  d-|j"                   d.|j,                   d/|j.                         d'z   d|iz  }t        t        j                  |            d x}x}}|j,                  }|j0                  } |       }d0}||k(  }|st        j                  d|fd1||f      d,t        j                         v st        j                  |      rt        j                  |      nd,t        j                  |      t        j                  |      t        j                  |      t        j                  |      d2z  }t        j$                  d3      d4z   d5|iz  }t        t        j                  |            d x}x}x}x}}g }d6}
|j.                  }|
|v }|}|s'd7}|j.                  }|j2                  } |       }||v }|}|st        j                  d8|fd9|
|f      t        j                  |
      d,t        j                         v st        j                  |      rt        j                  |      nd,t        j                  |      d:z  }d;d<|iz  }|j5                  |       |st        j                  d8fd=f      t        j                  |      d,t        j                         v st        j                  |      rt        j                  |      nd,t        j                        t        j                        t        j                  |      d>z  }d?d@|iz  }|j5                  |       t        j6                  |d*      i z  } dAdB| iz  }!t        t        j                  |!            d x}x}x}
x}x}x}x}x}x}}t'        |||       t+        |||      }"|"j"                  }d!}||k(  }|st        j                  d|fd+||f      dCt        j                         v st        j                  |"      rt        j                  |"      ndCt        j                  |      t        j                  |      d%z  }dd|iz  }t        t        j                  |            d x}x}}|"j,                  }|j0                  } |       }||k(  }|st        j                  d|fdD||f      dCt        j                         v st        j                  |"      rt        j                  |"      ndCt        j                  |      t        j                  |      t        j                  |      dEt        j                         v st        j                  |      rt        j                  |      ndEdFz  }#dGdH|#iz  }$t        t        j                  |$            d x}x}x}}y )INztest-2818-t4r~   r   r   r   r   r7   r   r   r   r   zC2: task work on task-branchr8   r   r   z$print('unrelated main-only change')
z5C1': main-only commit, NOT an ancestor of task-branchr   )z0%(py3)s
{%(py3)s = %(py0)s(%(py1)s)
} == %(py5)sr"   r   rq   )r   r   r   r   r   r   r   r   z
merge-basez--is-ancestorHEADTra   r   r   r   is_ancestorr   u:   테스트 전제 실패: C1' 이 이미 HEAD 의 조상임r   r   r   r   r   r   uc   base 가 HEAD 의 조상이 아니면 ancestor 가드로 fail-closed(exit 1) 되어야 함, got rc=r   r   rw   r   r   uJ   ancestor 가드 실패 시 base sha 를 stdout 으로 내보내면 안 됨r   r   u   조상ancestorr   )z.%(py3)s in %(py7)s
{%(py7)s = %(py5)s.stderr
})r   r   r   z%(py9)sr   )zh%(py12)s in %(py20)s
{%(py20)s = %(py18)s
{%(py18)s = %(py16)s
{%(py16)s = %(py14)s.stderr
}.lower
}()
})py12py14r   r   r   r   r   r   r   resolved_ok)z`%(py6)s
{%(py6)s = %(py4)s
{%(py4)s = %(py2)s
{%(py2)s = %(py0)s.stdout
}.strip
}()
} == %(py8)sr   )r   r   r   r   py8zassert %(py10)spy10)r@   r"   r   r/   r4   r   r   r   r   r   r   r   r   r   r   r   r   r   r   rJ   rZ   rl   r   r   r    r   r   r   )%r>   rC   r   r   r~   rH   rW   r   rq   c1_primer   r   r   r   r  r   r   r   r   r   r  r   r  r   r   @py_assert11r  r  r  @py_assert13r  r	  r
  r  r  r   @py_format11s%                                        r   -test_ancestor_guard_rejects_non_ancestor_baser    su   G$X.GD!;&IX%0J8#n4H	D	B 	z4/
4)..0MN45dD 	z6"
4(?Y&(OP4!XYH 	z=)d#t####t######:###:######d###d#########t###t####### ..	c$i&Q$GK !!dQd!Q&ddd!Qdddddd;ddd;ddd!dddQddd(dddddddd 
GX68W\N;!'4<H ! !#  !                  #$   %%&i/@	(//IZ	\     ?? ?    " b "b(  "b                  !    #    ')    	U      P8OxO8&O*OO8M8MO8M8OO*8O*OOOOO8OOO8OOOOOOxOOOxOOOOOOOOOO*8OOOO*OOOOOOOOOOOOOOO8MOOO8OOOOOOOOOOOOOOOO 
GR0$WdJ?K!!&Q&!Q&&&&!Q&&&&&&;&&&;&&&!&&&Q&&&&&&&+##+#%+%++++%++++++;+++;++++++#+++%+++++++++++++++++r   )r   r   r   r   r   boolreturnsubprocess.CompletedProcess)r  )r   r   r!   r   r  r   )r-   r   r.   r   r  None)r   r   r3   r   r  r   )r>   r   r  ztuple[Path, Path])rH   r   rC   r   rD   r   r  r   )N)
rW   r   rC   r   rO   	list[str]rX   zlist[str] | Noner  r   )rC   r   ri   r   rH   r   r  r  )r   r   rp   r   rq   r   r  r  )rC   r   r}   r  r~   r   r  r  )r>   r   )%__doc__
__future__r   builtinsr   _pytest.assertion.rewrite	assertionrewriter   rF   rg   r   rb   pathlibr   __file__resolver%   REPOr|   rz   r   re   r   r"   r/   r4   r@   rJ   rZ   rl   rt   r   r   r   r  r  r   r   r   <module>r*     s   ,Z #    	   H~''*I%(== jj! $2 r 04 7/
*&L
(CgT)N`1p1,r   