신선한 클론 신원
누가 새로 clone 해도 그렇게 동작하는가.
한 줄 요약 — 머지 커밋의 신선한 클론 안에서만 PR 의 주장을 다시 돌려, 깨끗한 체크아웃이 주장대로 동작함을 증명하고 살아남은 발견만 신규 이슈로 남긴다.
작업 worktree 에서는 초록인데 다른 모든 클론과 CI 에서는 그 검사가 존재하지도 않는 상태.
누가 새로 clone 해도 그렇게 동작하는가.
지금 서빙 중인 프로세스가 대상 커밋을 담고 있는가.
자매 스킬과의 경계는 무엇을 증명하느냐로 갈린다.
shell 스크립트 · CLI · 라이브러리에서 머지된 PR 을 재검증할 때. 머지 후 점검이 더러운 worktree 에서 돌아 untracked-artifact 버그를 숨기는 곳이 대상이다.
이미 떠 있는 앱에 붙어 화면을 확인해야 한다면 gh-verify:live 다. 프론트엔드 PR 도 merged 로 유닛/빌드 재현성을, live 로 화면을 볼 수 있다.
머지 전 정적 리뷰 게이트는 gh-verify:review-all 이다.
state != MERGED 면 escape hatch 없이 정지한다(--allow-unmerged 같은 플래그는 없다). 머지 커밋이 없으면 "신선한 클론이 무엇을 담아야 하는지" 자체가 정의되지 않는다. 미머지 PR 브랜치 검증은 gh-verify:live 다.
이 스킬은 앱을 띄우지 않는다.
원인이 보여도 고치지 않는다. 읽기 전용 경계다.
작업 worktree 에서 테스트를 돌려 "검증했다"고 하는 것 — 이 스킬이 막으려는 실패 그 자체다.
/gh-verify:merged [pr-number] [remote] [flags]
/gh-verify:merged upstream 처럼 PR 자동 감지 + remote 지정이 가능하다.
| # | 이름 | 기본값 | 설명 |
|---|---|---|---|
| 1 | PR number, 또는 -h/--help/help | 자동 | 생략 시 현재 브랜치 → 실패하면 현재 커밋을 포함하는 PR 을 역추적 |
| 2 | remote name | origin | 대상 레포를 해석할 git remote |
| Flag | 기본값 | 설명 |
|---|---|---|
| --matrix auto|full | auto | auto 는 PATH 정규화 축만 돌고 나머지는 후보로만 보고, full 은 유도된 축을 전부 실행 |
| --env <csv> | 없음 | 돌릴 환경 축을 직접 고정 (path,locale,shell,eol). --matrix 보다 우선 |
| --clone-dir <path> | mktemp -d | 임시 클론 위치 고정. 지정하면 자동 정리하지 않는다 |
| --no-diff-check | off | 차등 검증(F-7)을 끈다. 끈 사실이 리포트 Unproven: 행에 남는다 |
| --dry-run | off | 이슈 본문을 작성해서 출력하되 등록하지 않는다 |
| --no-issue | off | 초안조차 쓰지 않고 리포트 행으로만 보고한다 |
| --no-comment | off | 리포트를 PR 코멘트로 게시하지 않는다 (기본은 게시) |
| -h / --help / help | — | 도움말 출력 후 정지 |
--dry-run 과 --no-issue 를 같이 주면 --no-issue 가 이긴다.
--no-comment 는 그 둘과 독립이다. 플래그는 모두 --env X 와 --env=X 두 형태를 받는다.
| Code | 원인 |
|---|---|
| 0 | 검증이 끝났다 — 발견이 0건이든 N건이든, 일부 축이 unverified 였든 포함 |
| 1 | 검증 전 단언 실패(머지 안 됨 · mergeCommit.oid null · 클론 실패 · HEAD 불일치 · 더러운 클론), gh 미인증 |
| 2 | 인자 오류: 숫자로 시작하는데 양의 정수가 아닌 PR#, auto|full 아닌 --matrix, 알 수 없는 --env 축, 값이 빈 플래그, 모르는 플래그, 남는 positional |
pr remote matrix env_axes clone_dir diff_check issue_mode post_comment 를 캡처한다.
gh pr view 로 state mergedAt mergeCommit baseRefName body files closingIssuesReferences 를 1회만 fetch 해 재사용하고, state != MERGED 이거나 .mergeCommit.oid == null 이면 정지한다.
mergeCommit.oid 를 체크아웃한 클론을 임시 디렉터리에 만들고(headRefOid 금지), 이후 모든 실행은 그 클론 안에서만 한다. 클론 실패 · HEAD 불일치 · git status --porcelain 이 비어 있지 않음은 측정하지 않고 정지다. 이어서 클론과 작업 트리에서 실제로 실행되는 테스트 케이스의 이름·개수를 비교해 한쪽에만 있는 케이스를 발견으로 올린다.
연결 이슈의 AC → PR Test plan 미체크 항목 → 커밋 메시지의 검증: 줄 → 질의 순으로 주장을 모으고, 프로젝트 자체 검증 명령을 사다리(AGENTS.md/CLAUDE.md/README → tox.ini → pyproject.toml → package.json test → tests/*.bats → .claude/scripts/test-*.sh)로 찾는다. 미탐지는 Unverified: 한 줄.
기본 축은 PATH 정규화 1개 — 같은 검증을 PATH=/usr/bin:/bin 으로 다시 돌려 사용자 셸의 도구 치환을 배제한다. 결과가 갈리면 그 자체가 발견이다. locale·셸·줄 끝 축은 --matrix full·--env 일 때만 실행한다.
주장 1건마다 PR 이전 상태로 같은 입력을 돌린다. 전·후 결과가 같으면 unproven — 둘 다 통과하는 검사는 아무것도 증명하지 않는다. 기본 on 이고 --no-diff-check 로만 끈다.
후보마다 반증 가설 4종(하네스 오류 · 환경 특수성 · 의도된 동작 · PR 과 무관한 기존 결함)을 세워 반증하고, 살아남은 것만 발견 1건 = 이슈 1건으로 gh:issue-create 에 넘긴다.
Clone: Claims: Matrix: Unproven: Unverified: Rejected: Findings: 를 모두 담고 마지막 줄은 항상 Next: 다. [OK]/[WARN] 이고 post_comment=1 일 때만 그 블록을 대상 PR 코멘트로 남기며, [FAIL] 은 --no-comment 와 무관하게 게시하지 않는다.
unverified 다. 측정하지 않은 통과를 보고하지 않는다.gh:issue-create 로 신규 이슈로만 나가고, 커밋도 push 도 하지 않는다.[FAIL] 이면 남기고 경로를 출력한다. Bash(rm:*) 같은 deny 규칙에 막히면 경로를 출력하고 사용자에게 맡긴다 — 우회 금지.