From c7bdd201ac19b835b360ac70309617bf6613f407 Mon Sep 17 00:00:00 2001 From: SSFSKIM Date: Tue, 7 Jul 2026 16:11:52 +0900 Subject: [PATCH] =?UTF-8?q?feat(issue-tracker):=20PR=20=EB=9E=9C=EB=94=A9?= =?UTF-8?q?=20=EC=8B=9C=EC=A0=90=20=EC=9E=94=EC=97=AC=20=EC=9E=91=EC=97=85?= =?UTF-8?q?=EC=9D=98=20=ED=8B=B0=EC=BC=93=ED=99=94=20=EC=A0=95=EC=B1=85=20?= =?UTF-8?q?=E2=80=94=20FOLLOW-UPS=20=ED=95=84=EC=88=98=20=EC=8A=AC?= =?UTF-8?q?=EB=A1=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 부분 해결 PR이 이슈를 닫을 때 잔여/후속 작업이 조용히 증발하는 사각지대를 막는다. 베이스라인 테스트에서 워커 3/3이 후속 작업을 표면화는 했지만 정의된 운반 수단이 없어 각기 다른 즉흥 JSON(proposal 스키마 오용)을 발명했음을 확인. - Worker Protocol: PR을 여는 턴 종료 메시지에 FOLLOW-UPS 섹션 필수 (잔여 작업 각 1줄 + 잘린 이유, 없으면 명시적 "FOLLOW-UPS: none") - Deferral rule: 트리거에 PR 랜딩 시점 추가 + 부분 해결 PR도 티켓을 닫고 (done = landed) 잔여분은 --spawned-by 새 티켓으로 이관함을 명문화 - Dispatch loop 6단계: finalize 시 FOLLOW-UPS 항목 등록 → outcome 코멘트에 후속 티켓 번호 명기 순서 규정 검증: 개정 문안으로 워커 3/3이 동일한 FOLLOW-UPS 형식으로 수렴, 오케스트레이터 2/2가 finalize→등록→코멘트 순서 준수. tests/issue-tracker 전부 통과. --- skills/issue-tracker/SKILL.md | 36 ++++++++++++++++++++++++++++------- 1 file changed, 29 insertions(+), 7 deletions(-) diff --git a/skills/issue-tracker/SKILL.md b/skills/issue-tracker/SKILL.md index 67ebe4c95a..d235c3f06d 100644 --- a/skills/issue-tracker/SKILL.md +++ b/skills/issue-tracker/SKILL.md @@ -125,11 +125,15 @@ pick by repo visibility: (blocked/needs-info notes), wontfix suggestions, and cross-ticket proposals; apply or refuse those with `board-transition.sh`. 6. `done` arrives by landing, not by claim: the worker's PR body says - `Closes #`, so the merge itself auto-closes the ticket. Then finalize — - `board-transition.sh done` strips the stale in-review label and runs - the epic/unblock sweeps (lint's FIX line says the same) — and append an - outcome comment. A manual `done` flip remains for non-PR work; verify it - landed first. + `Closes #`, so the merge itself auto-closes the ticket — even a PR + that leaves residual work behind closes it (the residue gets new tickets, + not a reopened old one). Then finalize: `board-transition.sh done` + strips the stale in-review label and runs the epic/unblock sweeps (lint's + FIX line says the same); register each item of the worker's FOLLOW-UPS + list (`board-register.sh … --spawned-by ` — judging one down is fine, + but the judgment is recorded, never the item silently dropped); append an + outcome comment naming what landed and the follow-up tickets it spawned. + A manual `done` flip remains for non-PR work; verify it landed first. **Reconcile-on-wake:** been away? `board-reconcile.sh` first. It lists what the daemons proposed while you were gone, what needs respawning, and any @@ -164,6 +168,14 @@ in-progress when you start; in-review with --pr when your PR opens; blocked / needs-info (note required) the moment you hit an escalation — set the state yourself, then END YOUR TURN with the question stated crisply. +Opening your PR closes out your scope: that turn-end message MUST carry a +FOLLOW-UPS section — every piece of residual work the PR leaves behind +(non-blocking cleanups, larger work you discovered, success criteria the PR +only partially meets), one line each with why it was cut — or the literal +line "FOLLOW-UPS: none". The orchestrator registers these as new tickets at +finalize; a follow-up not on this list does not exist. The JSON proposal +block below is for state changes, not follow-ups. + You NEVER write a terminal state. done is not claimed, it is landed: your PR body MUST say "Closes #" so the merge itself closes the ticket. wontfix is the orchestrator's call. To suggest either — or any change to ANOTHER @@ -187,8 +199,9 @@ around it, never inside it. ## Scope-outs become tickets (deferral rule) Work deliberately deferred out of scope — during a grill, a brainstorm, an -issue-register session, or a worker's design phase — is registered on the -board THE MOMENT the deferral is decided, with its lineage as edges: +issue-register session, a worker's design phase, or a worker's FOLLOW-UPS +list at PR time — is registered on the board THE MOMENT the deferral is +decided, with its lineage as edges: - `--spawned-by ` — the ticket whose design session produced the cut - `--blocked-by ` — what must land first (often the origin ticket @@ -199,6 +212,15 @@ Deferral without a ticket is silent scope loss: the decision exists only in the design conversation and dies with the session. The ticket's Decision log records *why* it was cut, so nobody re-litigates it later. +PR landing is a deferral point like any other. A PR that addresses its +ticket but leaves work behind — non-blocking follow-ups, discovered larger +work, success criteria only partially met — still closes the ticket +(`Closes #N` stays in the body: done means the PR landed, not that every +idea it surfaced died). The residue rides the worker's FOLLOW-UPS list into +new tickets, `--spawned-by `, registered at finalize before the outcome +comment — and the outcome comment names them, so the closed ticket points +at where its remainder went. + ## Edge cases - A merged PR auto-closed its ticket (`Closes #N`) → the board already reads