마무리 (Closeout)
리뷰된 PR을 가져와 작업 공간을 깨끗한 기준 브랜치로 되돌립니다 — 병합, 워크트리 제거 전 셸 전환 후 제거, 병합된 브랜치 정리, 기준 브랜치 풀, 최종 상태 확인. 이는 파이프라인의 꼬리 부분입니다: 가장 반복되는 동작("다 됐어요, 병합하고 깨끗한 메인 브랜치로 돌려주세요")을 사용자의 머리에서 스킬로 옮긴 것입니다.
왜 존재하는가
/execute Step 0은 모든 슬라이스에 대해 워크트리를 생성합니다; 이 스킬이 있기 전까지는 아무것도 제거하지 않았습니다. 워크트리는 유입은 있지만 유출이 없는 재고(stock)이므로 재고는 제한 없이 증가합니다(Meadows, Thinking in Systems — 유입-무-유출 재고에 대한 구조적 탈출구는 누락된 피드백 루프를 추가하는 것이지, 더 열심히 설득하는 것이 아닙니다). 병합 → 해체 → 풀 시퀀스는 오직 사용자의 기억 속에만 존재했으며, "예상 기억은 조용히 실패합니다"(Norman, The Design of Everyday Things — 지식을 머리에서 세상으로 옮기십시오). 순서는 실제로 오류가 발생하기 쉽습니다: 셸의 현재 작업 디렉토리가 여전히 워크트리 안에 있는 상태에서 워크트리를 제거하면 셸이 삭제된 디렉토리에 갇히게 되고, 거기서 실행되는 node_modules 의존 Stop 훅은 실제 회귀처럼 읽히는 거짓 MODULE_NOT_FOUND "린트/타입 오류"를 쏟아냅니다. Step 4의 제거 전 기준 브랜치로 cd하는 순서가 바로 그 실수에 대한 하중 지지 수정입니다.
이 스킬은 기존 도구를 조율합니다(gh pr merge, wt remove / git worktree remove, commit-commands:clean_gone). 파일 시스템 상태를 도입하지 않습니다. 결과를 확인합니다 — 깨끗한 트리, 새로운 기준 브랜치, PR 병합됨 — 단순히 정리가 실행되었는지 여부가 아닙니다(Meadows의 "잘못된 목표 추구": "실행되었는가"로 측정된 마무리는 프록시를 최적화하고 깨지기 쉬운 의식을 만듭니다).
호출 위치
이것은 기본 제공 경로의 병합 → 정리 꼬리를 소유하는 기본 파이프라인 스킬입니다:
… → /pre-merge → /compound (PR 내부, 교훈이 있는 경우) → /pre-merge (복합 커밋에 대해 재실행; 재스탬프) → [병합 + 워크트리 해체 — 이 스킬] → [이슈 종료 — Step 9 산문]
다음과 같은 경우 /closeout을 사용하십시오:
/pre-merge가 PR을 생성했고 리뷰가 완료된 경우 (또는 변경 사항이 리뷰가 필요 없을 정도로 사소한 경우)- PR이 승인되고 병합 가능하며, 병합되고 작업 공간이 깨끗한 기준 브랜치로 돌아가기를 원하는 경우
- 사용자가 "마무리", "병합하고 정리", "워크트리 해체", 또는 "깨끗한 메인/기준 브랜치로 돌아가기"를 요청하는 경우
다음과 같은 경우 /closeout을 사용하지 마십시오:
- PR이 아직 생성되지 않았거나 여전히 리뷰 중인 경우 — 먼저
/pre-merge를 실행하십시오 - 지속 가능한 교훈을 포착하려는 경우 — 그것은
/compound이며, 기본적으로/closeout이 병합하기 전에 이미 PR을 타고 있습니다(병합 후/compound는 대체 방법입니다);/closeout은 교훈을 포착하지 않습니다 - PRD와 슬라이스 이슈를 종료하거나 리서치 아티팩트의 머리말을 조정하려는 경우 — 그것은
SYSTEM-OVERVIEW.mdStep 9의 정리 산문입니다;/closeout은 git-위생 절반을 수행하고 이슈 종료 및 리서치-아티팩트-대체 절반을 Step 9로 연기하며 중복하지 않습니다. 이 스킬이 만드는 유일한 종료는sidecar백엔드(Step 3)에서 병합된 슬라이스의 작업 항목입니다. 거기에는Closes #N줄이 병합 시 이를 수행하지 않기 때문입니다. - 변경 사항이 전혀 기능 브랜치에 없는 경우 (병합할 것이 없는 기준 브랜치에 있는 경우) — 마무리할 것이 없습니다
이것은 HITL-확인 및 비차단(non-blocking)입니다: 이미 선택적인 꼬리를 운영화합니다. 자동 병합하지 않습니다 — 병합은 외부 지향적이고 되돌리기 어려우므로 항상 먼저 확인합니다.
프로세스
이것을 do-confirm 체크리스트(Gawande)로 실행하십시오: 각 단계를 수행한 후 다음 단계 전에 그 결과를 확인하십시오. 파괴적인 단계(4–6)는 자체 보호됩니다 — 실행하기 전에 Step 2의 안전 전제 조건이 충족되는지 확인하십시오.
0. 호스트 프로비저닝 격리? 먼저 해체를 양도하십시오
병합/해체 시퀀스 전에 이 저장소의 격리가 호스트 소유(Conductor, Codespaces, devcontainers)인지 확인하십시오. 그런 경우, /closeout은 여전히 GitHub 네이티브 병합을 수행하지만 워크트리를 해체하거나 로컬 브랜치를 정리하지 않습니다 — 호스트가 해당 수명 주기의 절반을 소유하며, 이에 대항하는 것은 Meadows의 정책 저항(policy resistance)입니다 (동일한 재고를 밀어내는 두 행위자). 워크트리 재고를 호스트에 양도하십시오.
유출 감지는 /execute의 유입 검사보다 더 엄격하며 일반적인 "toplevel ≠ 기본 작업 트리" 휴리스틱만 사용해서는 안 됩니다: 파이프라인에서 만든 워크트리도 해당 테스트를 만족시키므로, 일반 신호는 "호스트가 해체를 소유함"과 "파이프라인이 이것을 만들었고 해체해야 함"을 구분할 수 없습니다. .claude/settings.json worktree.provisioning에서 해결하십시오 (없으면 기본값 "auto"), 그리고 /execute가 유입 시 하는 것과 정확히 동일하게 이 종료 지점에서 명시적 재정의를 존중하십시오:
host— 조건 없이 해체를 양도합니다.pipeline— 파이프라인이 해체를 소유합니다. 호스트 환경 변수가 있더라도 아래 Steps 4–6 전체를 실행하십시오 — 명시적pipeline설정은/execute가 워크트리를 자체적으로 프로비저닝했음을 의미하므로,/closeout이 이를 해체해야 합니다(호스트 이전 동작). 호스트 환경 변수는 명시적pipeline선택을 재정의하지 않습니다.auto(기본값) — 호스트 환경 변수가 이 트리를 설명하는 경우에만 해체를 양도하십시오: 아래 블록이host_owned=yes를 출력합니다. 일반적인 "toplevel ≠ 기본" 신호만으로 양도하지 말고,CONDUCTOR_WORKSPACE_PATH의 단순한 존재만으로도 양도하지 마십시오 — Conductor에서 시작된 셸은 이를 상속받아 다른 저장소의 작업 공간을 명명하는 것을 가질 수 있으며, 그것으로 양도하면 파이프라인에서 만든 워크트리를 해체할 사람 없이 남겨둡니다.
# 호스트 신호: 호스트 환경 변수가 이 셸이 아닌 이 트리를 설명합니까?
host_owned=no
top=$(cd "$(git rev-parse --show-toplevel)" && pwd -P)
if [ -n "${CONDUCTOR_WORKSPACE_PATH:-}" ]; then
ws=$(cd "$CONDUCTOR_WORKSPACE_PATH" 2>/dev/null && pwd -P) || ws=
if [ -n "$ws" ]; then
case "$top/" in "$ws"/*) host_owned=yes ;; esac
fi
fi
if [ -n "${CODESPACES:-}" ] || [ -n "${REMOTE_CONTAINERS:-}" ]; then host_owned=yes; fi
echo "host_owned=$host_owned"
해체가 양도되지 않은 경우 (worktree.provisioning: "auto"와 host_owned=no 포함), 파이프라인이 이를 소유합니다 — 아래 Steps 4–6을 작성된 대로 실행하십시오.
격리가 호스트 소유인 경우, /closeout은 축소된 시퀀스를 실행합니다:
- Step 3 (병합)은 여전히 완전히 실행됩니다 —
gh pr merge --delete-branch. Conductor 및 유사 호스트는 PR을 생성하지만 병합은 인간의 행동에 맡깁니다; 파이프라인이 GitHub 네이티브 병합을 수행하는 것이 추가하는 가치이며, 호스트는 결과를 반영합니다. 연기는 파일 시스템 해체로 범위가 제한되며, 절대 병합이 아닙니다. - Step 4의 재앵커, Step 5의
wt remove/git worktree remove/ExitWorktree { remove }, Step 6의 로컬 브랜치 정리를 건너뜁니다 — 호스트가 워크트리 및 브랜치 수명 주기를 소유합니다(Conductor는 작업 공간이 보관될 때 이를 회수합니다). 호스트 관리 트리에 대해 절대--force를 사용하지 마십시오. - Step 8의 체크리스트: "워크트리 제거됨" 및 "브랜치 정리됨"은 "해당 없음 — 호스트 관리" 가 됩니다. 병합, 깨끗한 트리, PR 병합됨, 및 원격 브랜치 확인은 여전히 적용됩니다. 마지막 항목은 동일한 N/A로 분류하기 쉽지만 그렇지 않습니다: 호스트가 소유하는 것은 파일 시스템 워크트리와 로컬 브랜치인 반면, 원격 브랜치는 이 스킬이 위 한 글머리 기호에서 여전히 완전히 실행하는
gh pr merge --delete-branch에 의해 삭제됩니다. 호스트가 소유하는 절반을 양도하는 것은 호스트가 소유하지 않는 절반을 양도하는 것이 아닙니다.
1. 의도 확인 및 상태 수집
절대 자동 병합하지 마십시오. 무엇을 하려는지 진술하고 명시적인 승인을 받으십시오.
먼저 사실을 수집하십시오 (읽기 전용):
git branch --show-current # 기능 브랜치
git rev-parse --show-toplevel # 현재 작업 트리 (워크트리일 수 있음)
git worktree list --porcelain | awk '/^worktree /{print $(2); exit}' # 기본 체크아웃 (메인 작업 트리)
gh pr view --json number,title,url,state,mergeable,mergeStateStatus,reviewDecision 2>/dev/null
PR이 대상으로 하는 기준 브랜치를 결정하십시오 — 저장소에 선언된 기본값, 가정이 아닙니다:
SC="<이 스킬의 디렉토리>/references/sidecar.sh"
bash "$SC" base-ref --name # 베어 브랜치 이름: prod, origin/prod 아님
이 사이트는 기준 브랜치 이름을 원하며, ref가 아닙니다 — Step 4에서 git switch <base-branch>에 제공되며, git switch는 원격 추적 ref를 완전히 거부합니다(fatal: a branch is expected, got remote branch 'origin/prod') — 곧 풀할 로컬 기준 브랜치를 원합니다. 따라서 base-ref --name을 요청하며, /pre-merge, /help, /walk-commits, /visual-recap, /compound, /execute가 취하는 ref 형식을 의도적으로 취하지 않습니다; 그들은 기준을 범위 끝점으로만 사용하기 때문에 ref가 필요하며, 이 스킬은 그렇게 하지 않습니다. 그들과 일치시키기 위해 "수정"하지 마십시오. base-ref --name이 0이 아닌 종료 코드로 종료되면 기준을 찾지 못한 것입니다: stderr를 중계하고 추측하지 말고 중단하십시오.
사용자에게 하나의 짧은 블록으로 알리십시오: 어떤 PR이 병합될지, 어떤 워크트리(있는 경우)와 브랜치가 해체될지, 그리고 어떤 기준 브랜치로 돌아가 풀할지. 확인을 기다리십시오. 이 브랜치에 PR이 없으면 중단하고 /pre-merge로 라우팅하십시오.
2. 파괴적 단계 전 안전 전제 조건 확인
해체는 파괴적입니다; 먼저 안전한지 확인하십시오 (자체 보호). 다음 모두 충족되어야 합니다:
- 기능 브랜치가 완전히 푸시되었습니다 —
git status에 푸시되지 않은 커밋이 없고,git log @{u}..이 비어 있습니다. - 이 브랜치에 대한 PR이 존재하고 병합 가능합니다 (
mergeable이MERGEABLE;mergeStateStatus가BLOCKED/DIRTY가 아님). - 필수 검사가 통과되었고 리뷰가 승인되었습니다 (
reviewDecision이APPROVED, 또는 저장소가 리뷰를 요구하지 않고 사용자가 명시적으로 수락했습니다).
전제 조건 중 하나라도 실패하면 중단하고 어떤 것인지 보고하십시오 — 병합하거나 아무것도 제거하지 마십시오. 실패한 전제 조건은 강제로 진행하는 것이 아니라 리뷰로 돌아가라는 신호입니다. 실패한 것이 리뷰인 경우 — reviewDecision이 CHANGES_REQUESTED — 돌아가는 경로는 /respond-to-review입니다: 각 주석을 코드와 비교하고, 인간이 무엇을 수정하고 무엇을 반박할지 결정하며, 수정 사항은 /fix-findings와 /pre-merge 재실행을 거친 후 /closeout이 다시 실행됩니다.
리뷰 통화성 — 승인이 이 diff를 여전히 포함합니까? (비차단)
위의 세 체크박스는 리뷰가 발생했는지 묻습니다. 그 중 어느 것도 그것이 병합될 diff를 포함하는지 묻지 않습니다. 의도된 선형 흐름에서 이들은 동일한 질문이며, 이것이 바로 간격이 보이지 않는 이유입니다; 실제 HITL 세션에서 범위는 리뷰 통과 후 브랜치에 누적되며, /pre-merge가 읽은 diff를 /closeout이 병합하는 diff와 연결하는 것은 아무것도 없습니다. 이것은 피드백 루프가 없는 유입입니다(Meadows — 구조적 수정은 루프를 추가하는 것이지, 열심히 설득하는 것이 아닙니다), 그리고 그것은 "PR이 리뷰되었습니다"를 "PR의 초기 버전이 리뷰되었습니다"로 조용히 저하시킵니다, 저하가 가장 중요한 바로 그 순간에. 지속적 딜리버리는 규칙을 분명히 말합니다: 당신이 리뷰한 아티팩트는 당신이 배송하는 아티팩트여야 합니다.
/pre-merge Phase 4가 남긴 스탬프를 읽고 현재 HEAD와 비교하십시오. backend stamp가 말하는 곳에 있습니다, references/state-backend.md에 따라: PR 본문 또는 사이드카에.
git fetch --quiet
SC="<이 스킬의 디렉토리>/references/sidecar.sh"
case "$(bash "$SC" backend stamp)" in
sidecar)
REVIEWED_SHA=$(bash "$SC" stamp read "$(git branch --show-current)")
HEAD_SHA=$(git rev-parse '@{u}' 2>/dev/null || git rev-parse HEAD) ;;
github)
REVIEWED_SHA=$(gh pr view <number> --json body -q .body \
| sed -n 's/.*<!-- reviewed-at: \([0-9a-f]\{40\}\) -->.*/\1/p' | tail -1)
HEAD_SHA=$(gh pr view <number> --json headRefOid -q .headRefOid) ;;
*) echo "closeout aborted: sidecar.sh backend stamp failed; not guessing the github path" >&2; exit 1 ;;
esac
사이드카 백엔드에서 HEAD는 브랜치의 업스트림이며, 이는 포지가 병합할 것입니다: 위의 첫 번째 전제 조건은 이미 로컬 HEAD와 일치하도록 요구합니다. 브랜치에 업스트림이 없으면 HEAD로 대체됩니다. stamp read는 PR-본문 마커가 전달하는 것과 동일한 전체 40자 OID를 출력하거나 아무것도 출력하지 않으므로, 아래 모든 것은 두 백엔드에서 변경 없이 실행됩니다.
정확히 40개의 16진수 문자, 문자열 동등성으로 비교. 그 문장의 두 부분 모두 하중 지지입니다. 이 마커는 두 스킬에 걸친 계약이기 때문입니다. /pre-merge Phase 4는 전체 40자 OID를 내보내고, headRefOid는 항상 40자이므로, \{40\}만이 동등하게 비교할 수 있는 유일한 너비입니다 — 더 짧은 것을 받아들이면 잘못된 마커(손으로 편집된 본문, 잘못된 절반으로 대체된 템플릿 자리 표시자)가 성공적으로 구문 분석된 다음 영원히 $HEAD_SHA와 다르게 될 수 있습니다. [[ "$REVIEWED_SHA" == "$HEAD_SHA" ]]가 비교입니다: 두 개의 전체 OID에 대한 정확한 문자열 동등성, 접두사 테스트가 아닙니다. 정규식이 거부하는 마커는 빈 $REVIEWED_SHA를 생성하고 아래 "스탬프 없음" 분기로 이동하여 정상적으로 저하됩니다 — "SHA가 다름" 분기가 HEAD가 전혀 움직이지 않은 PR에 대해 거짓 경보를 울리는 것보다 훨씬 낫습니다. Skill Kit 저장소에서 scripts/test-review-currency-marker.sh는 이 라운드 트립을 두 스킬 모두에 대해 고정하여 작성자 형식과 이 파서가 조용히 분리될 수 없도록 합니다.
세 가지 결과, 그 중 하나만 중단합니다:
- SHA가 일치 — 문자열 동등 전체 OID, 따라서 리뷰된 diff 는 병합 후보입니다. 조용히 통과하십시오. 서술하지 마십시오: 이것은 일반적인 경우이며, 매 실행마다 사건이 아닌 것을 발표하는 것은 게이트를 벽지로 만드는 것입니다.
- 스탬프를 찾을 수 없음 (
$REVIEWED_SHA가 비어 있음) — 수동으로 작성된 PR, 외부 기여, 스탬프 이전의 PR, 또는 위 정규식이 거부한 모양의 마커. 한 줄로 기록하십시오 ("이 PR에/pre-merge스탬프 없음 — 리뷰 통화성 알 수 없음")하고 계속하십시오. 스탬프가 없다고 해서 리뷰되지 않은 diff의 증거는 아니며, 스탬프되지 않은 모든 PR에서 중단하는 것은 경고 피로를 유발하여 게이트가 반사적으로 무효화되는 바로 그것입니다(Meadows, 정책 저항). - SHA가 다름 — 문자열 동등하지 않은 두 개의 잘 형성된 40자 OID, 이는 리뷰 후 커밋이 도착했음을 의미합니다. 중단하지 마십시오,
...