From edf34824b0a9c207707bccc72b312345406ac466 Mon Sep 17 00:00:00 2001 From: Pieter Viljoen Date: Wed, 30 Sep 2026 15:13:24 -0700 Subject: [PATCH 1/6] Close Answered Choices and Narrow Decision Matches in Unattended Loop An adopted lesson issue keeps the options it was filed with after its decision label comes off, so the Auto-Resolvable test now counts a choice as closed once the maintainer's answer is recorded on the issue. The picker's promotion STOP now matches only a decision issue stating that it blocks the open develop -> main pull request, the wording Parking step 2 already requires, rather than any issue naming it. A resuming worker now follows only the decision issue the parking comment names as what the lane waits on, and neither follows nor parks on a lesson issue the same comment names. Closes on promotion: #1812 --- .agents/skills/unattended-handoff/SKILL.md | 15 ++++++++++----- .../.source-digests/unattended-handoff | 2 +- .../skills/unattended-handoff/SKILL.md | 15 ++++++++++----- .github/skills/unattended-handoff/SKILL.md | 15 ++++++++++----- 4 files changed, 31 insertions(+), 16 deletions(-) diff --git a/.agents/skills/unattended-handoff/SKILL.md b/.agents/skills/unattended-handoff/SKILL.md index 7fd62266d..b805d3199 100644 --- a/.agents/skills/unattended-handoff/SKILL.md +++ b/.agents/skills/unattended-handoff/SKILL.md @@ -141,7 +141,9 @@ An issue needs no maintainer decision when every one of these holds. Where any i does not qualify, since skipping one costs nothing and a guess costs a revert and a review round. - **The right outcome is determined** by the issue together with the committed rules, and the issue - leaves no choice open between alternatives it names. + leaves no choice open between alternatives it names. A choice counts as closed once the + maintainer's answer to it is recorded on the issue, which is how an adopted lesson that still + lists its options qualifies. - **Nothing on it waits on the maintainer.** It carries none of `decision`, `blocked`, `handoff`, or `canonical-sweep`, the last being an issue a workflow owns rather than one a pull request closes, and no comment asks the maintainer something still unanswered. @@ -160,8 +162,9 @@ does not qualify, since skipping one costs nothing and a guess costs a revert an ## The Picker -1. **Check the promotion first** under `main` or `release`. Where an open `decision` issue names - the open develop -> main pull request, return `STOP` before picking anything, since every worker +1. **Check the promotion first** under `main` or `release`. Where an open `decision` issue states + that it blocks the open develop -> main pull request, as "Parking" step 2 has it state, return + `STOP` before picking anything, since every worker this run dispatched would meet that same decision after merging its own work to develop. 2. **Read the open handoffs** with labels and update times, `gh issue list --repo "/" --label handoff --state open --limit 100 --json number,title,labels,updatedAt`, since `handoff.py @@ -194,8 +197,10 @@ does not qualify, since skipping one costs nothing and a guess costs a revert an read its comments with `gh issue view "" --repo "/" --comments`, since `resume` prints only the body and a parked lane's state is in its parking comment. A lane handed back by an attended session has a closed predecessor holding that comment, so read the predecessor's - comments too. Where either names a decision issue, read the answer recorded there and follow it, - since it is what unblocked the lane. Re-derive live state rather than trusting any of them, per + comments too. Where the parking comment names the decision issue the lane waits on, read the + answer recorded there and follow it, since it is what unblocked the lane. A lesson issue the + comment also names, per step 6, is its own work rather than this lane's, so the worker neither + follows it nor parks on it. Re-derive live state rather than trusting any of them, per `session-handoff` "Resuming". 2. **Isolate** in a worktree of its own, per `repo-worktree`, on the branch the handoff names or on `feature/`. diff --git a/.claude-plugin/fleet-skills/.source-digests/unattended-handoff b/.claude-plugin/fleet-skills/.source-digests/unattended-handoff index 336cf1363..1afc984ad 100644 --- a/.claude-plugin/fleet-skills/.source-digests/unattended-handoff +++ b/.claude-plugin/fleet-skills/.source-digests/unattended-handoff @@ -1 +1 @@ -1a69a9029eef4d65 +ef8384640ecab031 diff --git a/.claude-plugin/fleet-skills/skills/unattended-handoff/SKILL.md b/.claude-plugin/fleet-skills/skills/unattended-handoff/SKILL.md index 7fd62266d..b805d3199 100644 --- a/.claude-plugin/fleet-skills/skills/unattended-handoff/SKILL.md +++ b/.claude-plugin/fleet-skills/skills/unattended-handoff/SKILL.md @@ -141,7 +141,9 @@ An issue needs no maintainer decision when every one of these holds. Where any i does not qualify, since skipping one costs nothing and a guess costs a revert and a review round. - **The right outcome is determined** by the issue together with the committed rules, and the issue - leaves no choice open between alternatives it names. + leaves no choice open between alternatives it names. A choice counts as closed once the + maintainer's answer to it is recorded on the issue, which is how an adopted lesson that still + lists its options qualifies. - **Nothing on it waits on the maintainer.** It carries none of `decision`, `blocked`, `handoff`, or `canonical-sweep`, the last being an issue a workflow owns rather than one a pull request closes, and no comment asks the maintainer something still unanswered. @@ -160,8 +162,9 @@ does not qualify, since skipping one costs nothing and a guess costs a revert an ## The Picker -1. **Check the promotion first** under `main` or `release`. Where an open `decision` issue names - the open develop -> main pull request, return `STOP` before picking anything, since every worker +1. **Check the promotion first** under `main` or `release`. Where an open `decision` issue states + that it blocks the open develop -> main pull request, as "Parking" step 2 has it state, return + `STOP` before picking anything, since every worker this run dispatched would meet that same decision after merging its own work to develop. 2. **Read the open handoffs** with labels and update times, `gh issue list --repo "/" --label handoff --state open --limit 100 --json number,title,labels,updatedAt`, since `handoff.py @@ -194,8 +197,10 @@ does not qualify, since skipping one costs nothing and a guess costs a revert an read its comments with `gh issue view "" --repo "/" --comments`, since `resume` prints only the body and a parked lane's state is in its parking comment. A lane handed back by an attended session has a closed predecessor holding that comment, so read the predecessor's - comments too. Where either names a decision issue, read the answer recorded there and follow it, - since it is what unblocked the lane. Re-derive live state rather than trusting any of them, per + comments too. Where the parking comment names the decision issue the lane waits on, read the + answer recorded there and follow it, since it is what unblocked the lane. A lesson issue the + comment also names, per step 6, is its own work rather than this lane's, so the worker neither + follows it nor parks on it. Re-derive live state rather than trusting any of them, per `session-handoff` "Resuming". 2. **Isolate** in a worktree of its own, per `repo-worktree`, on the branch the handoff names or on `feature/`. diff --git a/.github/skills/unattended-handoff/SKILL.md b/.github/skills/unattended-handoff/SKILL.md index 7fd62266d..b805d3199 100644 --- a/.github/skills/unattended-handoff/SKILL.md +++ b/.github/skills/unattended-handoff/SKILL.md @@ -141,7 +141,9 @@ An issue needs no maintainer decision when every one of these holds. Where any i does not qualify, since skipping one costs nothing and a guess costs a revert and a review round. - **The right outcome is determined** by the issue together with the committed rules, and the issue - leaves no choice open between alternatives it names. + leaves no choice open between alternatives it names. A choice counts as closed once the + maintainer's answer to it is recorded on the issue, which is how an adopted lesson that still + lists its options qualifies. - **Nothing on it waits on the maintainer.** It carries none of `decision`, `blocked`, `handoff`, or `canonical-sweep`, the last being an issue a workflow owns rather than one a pull request closes, and no comment asks the maintainer something still unanswered. @@ -160,8 +162,9 @@ does not qualify, since skipping one costs nothing and a guess costs a revert an ## The Picker -1. **Check the promotion first** under `main` or `release`. Where an open `decision` issue names - the open develop -> main pull request, return `STOP` before picking anything, since every worker +1. **Check the promotion first** under `main` or `release`. Where an open `decision` issue states + that it blocks the open develop -> main pull request, as "Parking" step 2 has it state, return + `STOP` before picking anything, since every worker this run dispatched would meet that same decision after merging its own work to develop. 2. **Read the open handoffs** with labels and update times, `gh issue list --repo "/" --label handoff --state open --limit 100 --json number,title,labels,updatedAt`, since `handoff.py @@ -194,8 +197,10 @@ does not qualify, since skipping one costs nothing and a guess costs a revert an read its comments with `gh issue view "" --repo "/" --comments`, since `resume` prints only the body and a parked lane's state is in its parking comment. A lane handed back by an attended session has a closed predecessor holding that comment, so read the predecessor's - comments too. Where either names a decision issue, read the answer recorded there and follow it, - since it is what unblocked the lane. Re-derive live state rather than trusting any of them, per + comments too. Where the parking comment names the decision issue the lane waits on, read the + answer recorded there and follow it, since it is what unblocked the lane. A lesson issue the + comment also names, per step 6, is its own work rather than this lane's, so the worker neither + follows it nor parks on it. Re-derive live state rather than trusting any of them, per `session-handoff` "Resuming". 2. **Isolate** in a worktree of its own, per `repo-worktree`, on the branch the handoff names or on `feature/`. From 96f2717a20a43377ffc08b5a322eada7be9ba647 Mon Sep 17 00:00:00 2001 From: Pieter Viljoen Date: Wed, 30 Sep 2026 15:16:36 -0700 Subject: [PATCH 2/6] Cover Comment-Recorded Blocks and Unanswered Waits in Unattended Loop The promotion STOP now also reads comments on a decision issue, since Parking step 2's reuse path records a newly blocked pull request as a comment. A choice overtaken at triage counts as closed like an answered one. The parking comment names the decision it waits on apart from any lesson issue, and a worker resuming a lane whose waited-on decision has no answer finishes parking rather than proceeding. --- .agents/skills/unattended-handoff/SKILL.md | 17 ++++++++++------- .../.source-digests/unattended-handoff | 2 +- .../skills/unattended-handoff/SKILL.md | 17 ++++++++++------- .github/skills/unattended-handoff/SKILL.md | 17 ++++++++++------- 4 files changed, 31 insertions(+), 22 deletions(-) diff --git a/.agents/skills/unattended-handoff/SKILL.md b/.agents/skills/unattended-handoff/SKILL.md index b805d3199..df0b9d03e 100644 --- a/.agents/skills/unattended-handoff/SKILL.md +++ b/.agents/skills/unattended-handoff/SKILL.md @@ -142,8 +142,8 @@ does not qualify, since skipping one costs nothing and a guess costs a revert an - **The right outcome is determined** by the issue together with the committed rules, and the issue leaves no choice open between alternatives it names. A choice counts as closed once the - maintainer's answer to it is recorded on the issue, which is how an adopted lesson that still - lists its options qualifies. + maintainer's answer to it, or the reason a later change overtook it, is recorded on the issue, + which is how an adopted lesson that still lists its options qualifies. - **Nothing on it waits on the maintainer.** It carries none of `decision`, `blocked`, `handoff`, or `canonical-sweep`, the last being an issue a workflow owns rather than one a pull request closes, and no comment asks the maintainer something still unanswered. @@ -162,9 +162,9 @@ does not qualify, since skipping one costs nothing and a guess costs a revert an ## The Picker -1. **Check the promotion first** under `main` or `release`. Where an open `decision` issue states - that it blocks the open develop -> main pull request, as "Parking" step 2 has it state, return - `STOP` before picking anything, since every worker +1. **Check the promotion first** under `main` or `release`. Where an open `decision` issue states, + in its body or in a comment on it, that it blocks the open develop -> main pull request, as + "Parking" step 2 has it state, return `STOP` before picking anything, since every worker this run dispatched would meet that same decision after merging its own work to develop. 2. **Read the open handoffs** with labels and update times, `gh issue list --repo "/" --label handoff --state open --limit 100 --json number,title,labels,updatedAt`, since `handoff.py @@ -200,7 +200,9 @@ does not qualify, since skipping one costs nothing and a guess costs a revert an comments too. Where the parking comment names the decision issue the lane waits on, read the answer recorded there and follow it, since it is what unblocked the lane. A lesson issue the comment also names, per step 6, is its own work rather than this lane's, so the worker neither - follows it nor parks on it. Re-derive live state rather than trusting any of them, per + follows it nor parks on it. Where the decision the lane waits on has no answer recorded, its + worker was interrupted while parking, so finish parking per "Parking" step 4 and return + `PARKED`. Re-derive live state rather than trusting any of them, per `session-handoff` "Resuming". 2. **Isolate** in a worktree of its own, per `repo-worktree`, on the branch the handoff names or on `feature/`. @@ -250,7 +252,8 @@ interruption part way leaves the work findable rather than lost. answered. 3. **Comment the state on the handoff**, filing any lesson first per worker step 6 so the comment can name it: what is done, the branch and pull request, whether the worktree was left standing, - what remains, and the decision issue it now waits on. This comment is what the next session on + what remains, and the decision issue it now waits on, named as that apart from any lesson issue + the comment also names. This comment is what the next session on the lane resumes from, so it is complete enough to continue with no other context. 4. **Label the handoff `blocked`**, per `GOVERNANCE.md` "Durable Knowledge and Self-Improvement". The picker skips it from then on, and the attended session takes it first. diff --git a/.claude-plugin/fleet-skills/.source-digests/unattended-handoff b/.claude-plugin/fleet-skills/.source-digests/unattended-handoff index 1afc984ad..c8ea5037e 100644 --- a/.claude-plugin/fleet-skills/.source-digests/unattended-handoff +++ b/.claude-plugin/fleet-skills/.source-digests/unattended-handoff @@ -1 +1 @@ -ef8384640ecab031 +658eb899bb3c496f diff --git a/.claude-plugin/fleet-skills/skills/unattended-handoff/SKILL.md b/.claude-plugin/fleet-skills/skills/unattended-handoff/SKILL.md index b805d3199..df0b9d03e 100644 --- a/.claude-plugin/fleet-skills/skills/unattended-handoff/SKILL.md +++ b/.claude-plugin/fleet-skills/skills/unattended-handoff/SKILL.md @@ -142,8 +142,8 @@ does not qualify, since skipping one costs nothing and a guess costs a revert an - **The right outcome is determined** by the issue together with the committed rules, and the issue leaves no choice open between alternatives it names. A choice counts as closed once the - maintainer's answer to it is recorded on the issue, which is how an adopted lesson that still - lists its options qualifies. + maintainer's answer to it, or the reason a later change overtook it, is recorded on the issue, + which is how an adopted lesson that still lists its options qualifies. - **Nothing on it waits on the maintainer.** It carries none of `decision`, `blocked`, `handoff`, or `canonical-sweep`, the last being an issue a workflow owns rather than one a pull request closes, and no comment asks the maintainer something still unanswered. @@ -162,9 +162,9 @@ does not qualify, since skipping one costs nothing and a guess costs a revert an ## The Picker -1. **Check the promotion first** under `main` or `release`. Where an open `decision` issue states - that it blocks the open develop -> main pull request, as "Parking" step 2 has it state, return - `STOP` before picking anything, since every worker +1. **Check the promotion first** under `main` or `release`. Where an open `decision` issue states, + in its body or in a comment on it, that it blocks the open develop -> main pull request, as + "Parking" step 2 has it state, return `STOP` before picking anything, since every worker this run dispatched would meet that same decision after merging its own work to develop. 2. **Read the open handoffs** with labels and update times, `gh issue list --repo "/" --label handoff --state open --limit 100 --json number,title,labels,updatedAt`, since `handoff.py @@ -200,7 +200,9 @@ does not qualify, since skipping one costs nothing and a guess costs a revert an comments too. Where the parking comment names the decision issue the lane waits on, read the answer recorded there and follow it, since it is what unblocked the lane. A lesson issue the comment also names, per step 6, is its own work rather than this lane's, so the worker neither - follows it nor parks on it. Re-derive live state rather than trusting any of them, per + follows it nor parks on it. Where the decision the lane waits on has no answer recorded, its + worker was interrupted while parking, so finish parking per "Parking" step 4 and return + `PARKED`. Re-derive live state rather than trusting any of them, per `session-handoff` "Resuming". 2. **Isolate** in a worktree of its own, per `repo-worktree`, on the branch the handoff names or on `feature/`. @@ -250,7 +252,8 @@ interruption part way leaves the work findable rather than lost. answered. 3. **Comment the state on the handoff**, filing any lesson first per worker step 6 so the comment can name it: what is done, the branch and pull request, whether the worktree was left standing, - what remains, and the decision issue it now waits on. This comment is what the next session on + what remains, and the decision issue it now waits on, named as that apart from any lesson issue + the comment also names. This comment is what the next session on the lane resumes from, so it is complete enough to continue with no other context. 4. **Label the handoff `blocked`**, per `GOVERNANCE.md` "Durable Knowledge and Self-Improvement". The picker skips it from then on, and the attended session takes it first. diff --git a/.github/skills/unattended-handoff/SKILL.md b/.github/skills/unattended-handoff/SKILL.md index b805d3199..df0b9d03e 100644 --- a/.github/skills/unattended-handoff/SKILL.md +++ b/.github/skills/unattended-handoff/SKILL.md @@ -142,8 +142,8 @@ does not qualify, since skipping one costs nothing and a guess costs a revert an - **The right outcome is determined** by the issue together with the committed rules, and the issue leaves no choice open between alternatives it names. A choice counts as closed once the - maintainer's answer to it is recorded on the issue, which is how an adopted lesson that still - lists its options qualifies. + maintainer's answer to it, or the reason a later change overtook it, is recorded on the issue, + which is how an adopted lesson that still lists its options qualifies. - **Nothing on it waits on the maintainer.** It carries none of `decision`, `blocked`, `handoff`, or `canonical-sweep`, the last being an issue a workflow owns rather than one a pull request closes, and no comment asks the maintainer something still unanswered. @@ -162,9 +162,9 @@ does not qualify, since skipping one costs nothing and a guess costs a revert an ## The Picker -1. **Check the promotion first** under `main` or `release`. Where an open `decision` issue states - that it blocks the open develop -> main pull request, as "Parking" step 2 has it state, return - `STOP` before picking anything, since every worker +1. **Check the promotion first** under `main` or `release`. Where an open `decision` issue states, + in its body or in a comment on it, that it blocks the open develop -> main pull request, as + "Parking" step 2 has it state, return `STOP` before picking anything, since every worker this run dispatched would meet that same decision after merging its own work to develop. 2. **Read the open handoffs** with labels and update times, `gh issue list --repo "/" --label handoff --state open --limit 100 --json number,title,labels,updatedAt`, since `handoff.py @@ -200,7 +200,9 @@ does not qualify, since skipping one costs nothing and a guess costs a revert an comments too. Where the parking comment names the decision issue the lane waits on, read the answer recorded there and follow it, since it is what unblocked the lane. A lesson issue the comment also names, per step 6, is its own work rather than this lane's, so the worker neither - follows it nor parks on it. Re-derive live state rather than trusting any of them, per + follows it nor parks on it. Where the decision the lane waits on has no answer recorded, its + worker was interrupted while parking, so finish parking per "Parking" step 4 and return + `PARKED`. Re-derive live state rather than trusting any of them, per `session-handoff` "Resuming". 2. **Isolate** in a worktree of its own, per `repo-worktree`, on the branch the handoff names or on `feature/`. @@ -250,7 +252,8 @@ interruption part way leaves the work findable rather than lost. answered. 3. **Comment the state on the handoff**, filing any lesson first per worker step 6 so the comment can name it: what is done, the branch and pull request, whether the worktree was left standing, - what remains, and the decision issue it now waits on. This comment is what the next session on + what remains, and the decision issue it now waits on, named as that apart from any lesson issue + the comment also names. This comment is what the next session on the lane resumes from, so it is complete enough to continue with no other context. 4. **Label the handoff `blocked`**, per `GOVERNANCE.md` "Durable Knowledge and Self-Improvement". The picker skips it from then on, and the attended session takes it first. From 0da943725635e2f58c88874a6687d2e2025ab4c7 Mon Sep 17 00:00:00 2001 From: Pieter Viljoen Date: Wed, 30 Sep 2026 15:19:38 -0700 Subject: [PATCH 3/6] Key Closed Choices and Interrupted Parks on the decision Label A choice now counts as closed only once the issue's decision label has come off with the answer or reason recorded, so a comment from anyone without triage rights cannot close one. A resuming worker treats the lane as interrupted mid-park only where the parking comment is on the current link and its decision still carries the label, and checks that before following the recorded answer or reason. --- .agents/skills/unattended-handoff/SKILL.md | 21 ++++++++++--------- .../.source-digests/unattended-handoff | 2 +- .../skills/unattended-handoff/SKILL.md | 21 ++++++++++--------- .github/skills/unattended-handoff/SKILL.md | 21 ++++++++++--------- 4 files changed, 34 insertions(+), 31 deletions(-) diff --git a/.agents/skills/unattended-handoff/SKILL.md b/.agents/skills/unattended-handoff/SKILL.md index df0b9d03e..2eb158f73 100644 --- a/.agents/skills/unattended-handoff/SKILL.md +++ b/.agents/skills/unattended-handoff/SKILL.md @@ -141,9 +141,10 @@ An issue needs no maintainer decision when every one of these holds. Where any i does not qualify, since skipping one costs nothing and a guess costs a revert and a review round. - **The right outcome is determined** by the issue together with the committed rules, and the issue - leaves no choice open between alternatives it names. A choice counts as closed once the - maintainer's answer to it, or the reason a later change overtook it, is recorded on the issue, - which is how an adopted lesson that still lists its options qualifies. + leaves no choice open between alternatives it names. A choice counts as closed once the issue's + `decision` label has come off with the answer or the reason recorded on it, per `GOVERNANCE.md` + "Communicating with the User", which is how an adopted lesson that still lists its options + qualifies. - **Nothing on it waits on the maintainer.** It carries none of `decision`, `blocked`, `handoff`, or `canonical-sweep`, the last being an issue a workflow owns rather than one a pull request closes, and no comment asks the maintainer something still unanswered. @@ -197,13 +198,13 @@ does not qualify, since skipping one costs nothing and a guess costs a revert an read its comments with `gh issue view "" --repo "/" --comments`, since `resume` prints only the body and a parked lane's state is in its parking comment. A lane handed back by an attended session has a closed predecessor holding that comment, so read the predecessor's - comments too. Where the parking comment names the decision issue the lane waits on, read the - answer recorded there and follow it, since it is what unblocked the lane. A lesson issue the - comment also names, per step 6, is its own work rather than this lane's, so the worker neither - follows it nor parks on it. Where the decision the lane waits on has no answer recorded, its - worker was interrupted while parking, so finish parking per "Parking" step 4 and return - `PARKED`. Re-derive live state rather than trusting any of them, per - `session-handoff` "Resuming". + comments too. Where the parking comment is on the current link and the decision issue it + waits on still carries `decision`, the worker before was interrupted while parking, so finish + parking per "Parking" step 4 and return `PARKED`. Otherwise read the answer or the reason + recorded on that decision issue and follow it, since it is what unblocked the lane. A lesson + issue the comment also names, per step 6, is its own work rather than this lane's, so the + worker neither follows it nor parks on it. Re-derive live state rather than trusting any of + them, per `session-handoff` "Resuming". 2. **Isolate** in a worktree of its own, per `repo-worktree`, on the branch the handoff names or on `feature/`. 3. **Fix and drive.** Run `local-strict-review` before every push, and drive the pull request with diff --git a/.claude-plugin/fleet-skills/.source-digests/unattended-handoff b/.claude-plugin/fleet-skills/.source-digests/unattended-handoff index c8ea5037e..2b9c1c600 100644 --- a/.claude-plugin/fleet-skills/.source-digests/unattended-handoff +++ b/.claude-plugin/fleet-skills/.source-digests/unattended-handoff @@ -1 +1 @@ -658eb899bb3c496f +5b79c57e2442155e diff --git a/.claude-plugin/fleet-skills/skills/unattended-handoff/SKILL.md b/.claude-plugin/fleet-skills/skills/unattended-handoff/SKILL.md index df0b9d03e..2eb158f73 100644 --- a/.claude-plugin/fleet-skills/skills/unattended-handoff/SKILL.md +++ b/.claude-plugin/fleet-skills/skills/unattended-handoff/SKILL.md @@ -141,9 +141,10 @@ An issue needs no maintainer decision when every one of these holds. Where any i does not qualify, since skipping one costs nothing and a guess costs a revert and a review round. - **The right outcome is determined** by the issue together with the committed rules, and the issue - leaves no choice open between alternatives it names. A choice counts as closed once the - maintainer's answer to it, or the reason a later change overtook it, is recorded on the issue, - which is how an adopted lesson that still lists its options qualifies. + leaves no choice open between alternatives it names. A choice counts as closed once the issue's + `decision` label has come off with the answer or the reason recorded on it, per `GOVERNANCE.md` + "Communicating with the User", which is how an adopted lesson that still lists its options + qualifies. - **Nothing on it waits on the maintainer.** It carries none of `decision`, `blocked`, `handoff`, or `canonical-sweep`, the last being an issue a workflow owns rather than one a pull request closes, and no comment asks the maintainer something still unanswered. @@ -197,13 +198,13 @@ does not qualify, since skipping one costs nothing and a guess costs a revert an read its comments with `gh issue view "" --repo "/" --comments`, since `resume` prints only the body and a parked lane's state is in its parking comment. A lane handed back by an attended session has a closed predecessor holding that comment, so read the predecessor's - comments too. Where the parking comment names the decision issue the lane waits on, read the - answer recorded there and follow it, since it is what unblocked the lane. A lesson issue the - comment also names, per step 6, is its own work rather than this lane's, so the worker neither - follows it nor parks on it. Where the decision the lane waits on has no answer recorded, its - worker was interrupted while parking, so finish parking per "Parking" step 4 and return - `PARKED`. Re-derive live state rather than trusting any of them, per - `session-handoff` "Resuming". + comments too. Where the parking comment is on the current link and the decision issue it + waits on still carries `decision`, the worker before was interrupted while parking, so finish + parking per "Parking" step 4 and return `PARKED`. Otherwise read the answer or the reason + recorded on that decision issue and follow it, since it is what unblocked the lane. A lesson + issue the comment also names, per step 6, is its own work rather than this lane's, so the + worker neither follows it nor parks on it. Re-derive live state rather than trusting any of + them, per `session-handoff` "Resuming". 2. **Isolate** in a worktree of its own, per `repo-worktree`, on the branch the handoff names or on `feature/`. 3. **Fix and drive.** Run `local-strict-review` before every push, and drive the pull request with diff --git a/.github/skills/unattended-handoff/SKILL.md b/.github/skills/unattended-handoff/SKILL.md index df0b9d03e..2eb158f73 100644 --- a/.github/skills/unattended-handoff/SKILL.md +++ b/.github/skills/unattended-handoff/SKILL.md @@ -141,9 +141,10 @@ An issue needs no maintainer decision when every one of these holds. Where any i does not qualify, since skipping one costs nothing and a guess costs a revert and a review round. - **The right outcome is determined** by the issue together with the committed rules, and the issue - leaves no choice open between alternatives it names. A choice counts as closed once the - maintainer's answer to it, or the reason a later change overtook it, is recorded on the issue, - which is how an adopted lesson that still lists its options qualifies. + leaves no choice open between alternatives it names. A choice counts as closed once the issue's + `decision` label has come off with the answer or the reason recorded on it, per `GOVERNANCE.md` + "Communicating with the User", which is how an adopted lesson that still lists its options + qualifies. - **Nothing on it waits on the maintainer.** It carries none of `decision`, `blocked`, `handoff`, or `canonical-sweep`, the last being an issue a workflow owns rather than one a pull request closes, and no comment asks the maintainer something still unanswered. @@ -197,13 +198,13 @@ does not qualify, since skipping one costs nothing and a guess costs a revert an read its comments with `gh issue view "" --repo "/" --comments`, since `resume` prints only the body and a parked lane's state is in its parking comment. A lane handed back by an attended session has a closed predecessor holding that comment, so read the predecessor's - comments too. Where the parking comment names the decision issue the lane waits on, read the - answer recorded there and follow it, since it is what unblocked the lane. A lesson issue the - comment also names, per step 6, is its own work rather than this lane's, so the worker neither - follows it nor parks on it. Where the decision the lane waits on has no answer recorded, its - worker was interrupted while parking, so finish parking per "Parking" step 4 and return - `PARKED`. Re-derive live state rather than trusting any of them, per - `session-handoff` "Resuming". + comments too. Where the parking comment is on the current link and the decision issue it + waits on still carries `decision`, the worker before was interrupted while parking, so finish + parking per "Parking" step 4 and return `PARKED`. Otherwise read the answer or the reason + recorded on that decision issue and follow it, since it is what unblocked the lane. A lesson + issue the comment also names, per step 6, is its own work rather than this lane's, so the + worker neither follows it nor parks on it. Re-derive live state rather than trusting any of + them, per `session-handoff` "Resuming". 2. **Isolate** in a worktree of its own, per `repo-worktree`, on the branch the handoff names or on `feature/`. 3. **Fix and drive.** Run `local-strict-review` before every push, and drive the pull request with From 88c0dd803758f39f36d1731c8e1f2078e05c9675 Mon Sep 17 00:00:00 2001 From: Pieter Viljoen Date: Wed, 30 Sep 2026 16:23:08 -0700 Subject: [PATCH 4/6] Drop the Adopted-Lesson Clause and Bound the Promotion Decision Read The Auto-Resolvable test returns to its original wording, since telling an adopted lesson apart from an issue that never carried decision needs a signal the picker can read, which is now its own decision. The promotion check names its read with an explicit limit and the full-page check, and worker step 1 acts on the newest parking comment only where it names a decision issue. --- .agents/skills/unattended-handoff/SKILL.md | 28 +++++++++---------- .../.source-digests/unattended-handoff | 2 +- .../skills/unattended-handoff/SKILL.md | 28 +++++++++---------- .github/skills/unattended-handoff/SKILL.md | 28 +++++++++---------- 4 files changed, 43 insertions(+), 43 deletions(-) diff --git a/.agents/skills/unattended-handoff/SKILL.md b/.agents/skills/unattended-handoff/SKILL.md index 2eb158f73..fb4bee95e 100644 --- a/.agents/skills/unattended-handoff/SKILL.md +++ b/.agents/skills/unattended-handoff/SKILL.md @@ -141,10 +141,7 @@ An issue needs no maintainer decision when every one of these holds. Where any i does not qualify, since skipping one costs nothing and a guess costs a revert and a review round. - **The right outcome is determined** by the issue together with the committed rules, and the issue - leaves no choice open between alternatives it names. A choice counts as closed once the issue's - `decision` label has come off with the answer or the reason recorded on it, per `GOVERNANCE.md` - "Communicating with the User", which is how an adopted lesson that still lists its options - qualifies. + leaves no choice open between alternatives it names. - **Nothing on it waits on the maintainer.** It carries none of `decision`, `blocked`, `handoff`, or `canonical-sweep`, the last being an issue a workflow owns rather than one a pull request closes, and no comment asks the maintainer something still unanswered. @@ -166,7 +163,9 @@ does not qualify, since skipping one costs nothing and a guess costs a revert an 1. **Check the promotion first** under `main` or `release`. Where an open `decision` issue states, in its body or in a comment on it, that it blocks the open develop -> main pull request, as "Parking" step 2 has it state, return `STOP` before picking anything, since every worker - this run dispatched would meet that same decision after merging its own work to develop. + this run dispatched would meet that same decision after merging its own work to develop. Read + them with `gh issue list --repo "/" --label decision --state open --limit 100` + under step 2's full-page check, then each one's comments with `gh issue view --comments`. 2. **Read the open handoffs** with labels and update times, `gh issue list --repo "/" --label handoff --state open --limit 100 --json number,title,labels,updatedAt`, since `handoff.py tracks` prints neither. Where it returns as many rows as the limit, the list may be truncated, so @@ -198,13 +197,14 @@ does not qualify, since skipping one costs nothing and a guess costs a revert an read its comments with `gh issue view "" --repo "/" --comments`, since `resume` prints only the body and a parked lane's state is in its parking comment. A lane handed back by an attended session has a closed predecessor holding that comment, so read the predecessor's - comments too. Where the parking comment is on the current link and the decision issue it - waits on still carries `decision`, the worker before was interrupted while parking, so finish - parking per "Parking" step 4 and return `PARKED`. Otherwise read the answer or the reason - recorded on that decision issue and follow it, since it is what unblocked the lane. A lesson - issue the comment also names, per step 6, is its own work rather than this lane's, so the - worker neither follows it nor parks on it. Re-derive live state rather than trusting any of - them, per `session-handoff` "Resuming". + comments too. Where the newest parking comment names a decision issue the lane waits on, and + that comment is on the current link while the issue still carries `decision`, the worker + before was interrupted while parking, so finish parking per "Parking" step 4 and return + `PARKED`. Where it names one and neither holds, read the answer or the reason recorded on that + issue and follow it, since it is what unblocked the lane. A lesson issue the comment also + names, per step 6, is its own work rather than this lane's, so the worker neither follows it + nor parks on it. Re-derive live state rather than trusting any of them, per `session-handoff` + "Resuming". 2. **Isolate** in a worktree of its own, per `repo-worktree`, on the branch the handoff names or on `feature/`. 3. **Fix and drive.** Run `local-strict-review` before every push, and drive the pull request with @@ -254,8 +254,8 @@ interruption part way leaves the work findable rather than lost. 3. **Comment the state on the handoff**, filing any lesson first per worker step 6 so the comment can name it: what is done, the branch and pull request, whether the worktree was left standing, what remains, and the decision issue it now waits on, named as that apart from any lesson issue - the comment also names. This comment is what the next session on - the lane resumes from, so it is complete enough to continue with no other context. + the comment also names. This comment is what the next session on the lane resumes from, so it + is complete enough to continue with no other context. 4. **Label the handoff `blocked`**, per `GOVERNANCE.md` "Durable Knowledge and Self-Improvement". The picker skips it from then on, and the attended session takes it first. diff --git a/.claude-plugin/fleet-skills/.source-digests/unattended-handoff b/.claude-plugin/fleet-skills/.source-digests/unattended-handoff index 2b9c1c600..56ea81c06 100644 --- a/.claude-plugin/fleet-skills/.source-digests/unattended-handoff +++ b/.claude-plugin/fleet-skills/.source-digests/unattended-handoff @@ -1 +1 @@ -5b79c57e2442155e +b9f07aeaaa33745e diff --git a/.claude-plugin/fleet-skills/skills/unattended-handoff/SKILL.md b/.claude-plugin/fleet-skills/skills/unattended-handoff/SKILL.md index 2eb158f73..fb4bee95e 100644 --- a/.claude-plugin/fleet-skills/skills/unattended-handoff/SKILL.md +++ b/.claude-plugin/fleet-skills/skills/unattended-handoff/SKILL.md @@ -141,10 +141,7 @@ An issue needs no maintainer decision when every one of these holds. Where any i does not qualify, since skipping one costs nothing and a guess costs a revert and a review round. - **The right outcome is determined** by the issue together with the committed rules, and the issue - leaves no choice open between alternatives it names. A choice counts as closed once the issue's - `decision` label has come off with the answer or the reason recorded on it, per `GOVERNANCE.md` - "Communicating with the User", which is how an adopted lesson that still lists its options - qualifies. + leaves no choice open between alternatives it names. - **Nothing on it waits on the maintainer.** It carries none of `decision`, `blocked`, `handoff`, or `canonical-sweep`, the last being an issue a workflow owns rather than one a pull request closes, and no comment asks the maintainer something still unanswered. @@ -166,7 +163,9 @@ does not qualify, since skipping one costs nothing and a guess costs a revert an 1. **Check the promotion first** under `main` or `release`. Where an open `decision` issue states, in its body or in a comment on it, that it blocks the open develop -> main pull request, as "Parking" step 2 has it state, return `STOP` before picking anything, since every worker - this run dispatched would meet that same decision after merging its own work to develop. + this run dispatched would meet that same decision after merging its own work to develop. Read + them with `gh issue list --repo "/" --label decision --state open --limit 100` + under step 2's full-page check, then each one's comments with `gh issue view --comments`. 2. **Read the open handoffs** with labels and update times, `gh issue list --repo "/" --label handoff --state open --limit 100 --json number,title,labels,updatedAt`, since `handoff.py tracks` prints neither. Where it returns as many rows as the limit, the list may be truncated, so @@ -198,13 +197,14 @@ does not qualify, since skipping one costs nothing and a guess costs a revert an read its comments with `gh issue view "" --repo "/" --comments`, since `resume` prints only the body and a parked lane's state is in its parking comment. A lane handed back by an attended session has a closed predecessor holding that comment, so read the predecessor's - comments too. Where the parking comment is on the current link and the decision issue it - waits on still carries `decision`, the worker before was interrupted while parking, so finish - parking per "Parking" step 4 and return `PARKED`. Otherwise read the answer or the reason - recorded on that decision issue and follow it, since it is what unblocked the lane. A lesson - issue the comment also names, per step 6, is its own work rather than this lane's, so the - worker neither follows it nor parks on it. Re-derive live state rather than trusting any of - them, per `session-handoff` "Resuming". + comments too. Where the newest parking comment names a decision issue the lane waits on, and + that comment is on the current link while the issue still carries `decision`, the worker + before was interrupted while parking, so finish parking per "Parking" step 4 and return + `PARKED`. Where it names one and neither holds, read the answer or the reason recorded on that + issue and follow it, since it is what unblocked the lane. A lesson issue the comment also + names, per step 6, is its own work rather than this lane's, so the worker neither follows it + nor parks on it. Re-derive live state rather than trusting any of them, per `session-handoff` + "Resuming". 2. **Isolate** in a worktree of its own, per `repo-worktree`, on the branch the handoff names or on `feature/`. 3. **Fix and drive.** Run `local-strict-review` before every push, and drive the pull request with @@ -254,8 +254,8 @@ interruption part way leaves the work findable rather than lost. 3. **Comment the state on the handoff**, filing any lesson first per worker step 6 so the comment can name it: what is done, the branch and pull request, whether the worktree was left standing, what remains, and the decision issue it now waits on, named as that apart from any lesson issue - the comment also names. This comment is what the next session on - the lane resumes from, so it is complete enough to continue with no other context. + the comment also names. This comment is what the next session on the lane resumes from, so it + is complete enough to continue with no other context. 4. **Label the handoff `blocked`**, per `GOVERNANCE.md` "Durable Knowledge and Self-Improvement". The picker skips it from then on, and the attended session takes it first. diff --git a/.github/skills/unattended-handoff/SKILL.md b/.github/skills/unattended-handoff/SKILL.md index 2eb158f73..fb4bee95e 100644 --- a/.github/skills/unattended-handoff/SKILL.md +++ b/.github/skills/unattended-handoff/SKILL.md @@ -141,10 +141,7 @@ An issue needs no maintainer decision when every one of these holds. Where any i does not qualify, since skipping one costs nothing and a guess costs a revert and a review round. - **The right outcome is determined** by the issue together with the committed rules, and the issue - leaves no choice open between alternatives it names. A choice counts as closed once the issue's - `decision` label has come off with the answer or the reason recorded on it, per `GOVERNANCE.md` - "Communicating with the User", which is how an adopted lesson that still lists its options - qualifies. + leaves no choice open between alternatives it names. - **Nothing on it waits on the maintainer.** It carries none of `decision`, `blocked`, `handoff`, or `canonical-sweep`, the last being an issue a workflow owns rather than one a pull request closes, and no comment asks the maintainer something still unanswered. @@ -166,7 +163,9 @@ does not qualify, since skipping one costs nothing and a guess costs a revert an 1. **Check the promotion first** under `main` or `release`. Where an open `decision` issue states, in its body or in a comment on it, that it blocks the open develop -> main pull request, as "Parking" step 2 has it state, return `STOP` before picking anything, since every worker - this run dispatched would meet that same decision after merging its own work to develop. + this run dispatched would meet that same decision after merging its own work to develop. Read + them with `gh issue list --repo "/" --label decision --state open --limit 100` + under step 2's full-page check, then each one's comments with `gh issue view --comments`. 2. **Read the open handoffs** with labels and update times, `gh issue list --repo "/" --label handoff --state open --limit 100 --json number,title,labels,updatedAt`, since `handoff.py tracks` prints neither. Where it returns as many rows as the limit, the list may be truncated, so @@ -198,13 +197,14 @@ does not qualify, since skipping one costs nothing and a guess costs a revert an read its comments with `gh issue view "" --repo "/" --comments`, since `resume` prints only the body and a parked lane's state is in its parking comment. A lane handed back by an attended session has a closed predecessor holding that comment, so read the predecessor's - comments too. Where the parking comment is on the current link and the decision issue it - waits on still carries `decision`, the worker before was interrupted while parking, so finish - parking per "Parking" step 4 and return `PARKED`. Otherwise read the answer or the reason - recorded on that decision issue and follow it, since it is what unblocked the lane. A lesson - issue the comment also names, per step 6, is its own work rather than this lane's, so the - worker neither follows it nor parks on it. Re-derive live state rather than trusting any of - them, per `session-handoff` "Resuming". + comments too. Where the newest parking comment names a decision issue the lane waits on, and + that comment is on the current link while the issue still carries `decision`, the worker + before was interrupted while parking, so finish parking per "Parking" step 4 and return + `PARKED`. Where it names one and neither holds, read the answer or the reason recorded on that + issue and follow it, since it is what unblocked the lane. A lesson issue the comment also + names, per step 6, is its own work rather than this lane's, so the worker neither follows it + nor parks on it. Re-derive live state rather than trusting any of them, per `session-handoff` + "Resuming". 2. **Isolate** in a worktree of its own, per `repo-worktree`, on the branch the handoff names or on `feature/`. 3. **Fix and drive.** Run `local-strict-review` before every push, and drive the pull request with @@ -254,8 +254,8 @@ interruption part way leaves the work findable rather than lost. 3. **Comment the state on the handoff**, filing any lesson first per worker step 6 so the comment can name it: what is done, the branch and pull request, whether the worktree was left standing, what remains, and the decision issue it now waits on, named as that apart from any lesson issue - the comment also names. This comment is what the next session on - the lane resumes from, so it is complete enough to continue with no other context. + the comment also names. This comment is what the next session on the lane resumes from, so it + is complete enough to continue with no other context. 4. **Label the handoff `blocked`**, per `GOVERNANCE.md` "Durable Knowledge and Self-Improvement". The picker skips it from then on, and the attended session takes it first. From 593cc3dd56a3694908cbdf5a6930a77f8190feeb Mon Sep 17 00:00:00 2001 From: Pieter Viljoen Date: Wed, 30 Sep 2026 16:33:05 -0700 Subject: [PATCH 5/6] Remove the Interrupted-Park Branch and Read decision Bodies as JSON Worker step 1 returns to following the answer on the decision issue the lane waits on, the interrupted-park branch having drawn a finding in every pass without being part of what the change set out to fix. The promotion check reads each open decision issue's body and comments through --json, since gh issue view --comments prints no body when it runs without a terminal. --- .agents/skills/unattended-handoff/SKILL.md | 15 ++++++--------- .../.source-digests/unattended-handoff | 2 +- .../skills/unattended-handoff/SKILL.md | 15 ++++++--------- .github/skills/unattended-handoff/SKILL.md | 15 ++++++--------- 4 files changed, 19 insertions(+), 28 deletions(-) diff --git a/.agents/skills/unattended-handoff/SKILL.md b/.agents/skills/unattended-handoff/SKILL.md index fb4bee95e..ccee6061d 100644 --- a/.agents/skills/unattended-handoff/SKILL.md +++ b/.agents/skills/unattended-handoff/SKILL.md @@ -164,8 +164,8 @@ does not qualify, since skipping one costs nothing and a guess costs a revert an in its body or in a comment on it, that it blocks the open develop -> main pull request, as "Parking" step 2 has it state, return `STOP` before picking anything, since every worker this run dispatched would meet that same decision after merging its own work to develop. Read - them with `gh issue list --repo "/" --label decision --state open --limit 100` - under step 2's full-page check, then each one's comments with `gh issue view --comments`. + them with `gh issue list --repo "/" --label decision --state open --limit 100 + --json number,body,comments` under step 2's full-page check. 2. **Read the open handoffs** with labels and update times, `gh issue list --repo "/" --label handoff --state open --limit 100 --json number,title,labels,updatedAt`, since `handoff.py tracks` prints neither. Where it returns as many rows as the limit, the list may be truncated, so @@ -197,13 +197,10 @@ does not qualify, since skipping one costs nothing and a guess costs a revert an read its comments with `gh issue view "" --repo "/" --comments`, since `resume` prints only the body and a parked lane's state is in its parking comment. A lane handed back by an attended session has a closed predecessor holding that comment, so read the predecessor's - comments too. Where the newest parking comment names a decision issue the lane waits on, and - that comment is on the current link while the issue still carries `decision`, the worker - before was interrupted while parking, so finish parking per "Parking" step 4 and return - `PARKED`. Where it names one and neither holds, read the answer or the reason recorded on that - issue and follow it, since it is what unblocked the lane. A lesson issue the comment also - names, per step 6, is its own work rather than this lane's, so the worker neither follows it - nor parks on it. Re-derive live state rather than trusting any of them, per `session-handoff` + comments too. Where the parking comment names the decision issue the lane waits on, read the + answer recorded there and follow it, since it is what unblocked the lane. A lesson issue the + comment also names, per step 6, is its own work rather than this lane's, so the worker neither + follows it nor parks on it. Re-derive live state rather than trusting any of them, per `session-handoff` "Resuming". 2. **Isolate** in a worktree of its own, per `repo-worktree`, on the branch the handoff names or on `feature/`. diff --git a/.claude-plugin/fleet-skills/.source-digests/unattended-handoff b/.claude-plugin/fleet-skills/.source-digests/unattended-handoff index 56ea81c06..93eae4ea0 100644 --- a/.claude-plugin/fleet-skills/.source-digests/unattended-handoff +++ b/.claude-plugin/fleet-skills/.source-digests/unattended-handoff @@ -1 +1 @@ -b9f07aeaaa33745e +31784baf190feb5b diff --git a/.claude-plugin/fleet-skills/skills/unattended-handoff/SKILL.md b/.claude-plugin/fleet-skills/skills/unattended-handoff/SKILL.md index fb4bee95e..ccee6061d 100644 --- a/.claude-plugin/fleet-skills/skills/unattended-handoff/SKILL.md +++ b/.claude-plugin/fleet-skills/skills/unattended-handoff/SKILL.md @@ -164,8 +164,8 @@ does not qualify, since skipping one costs nothing and a guess costs a revert an in its body or in a comment on it, that it blocks the open develop -> main pull request, as "Parking" step 2 has it state, return `STOP` before picking anything, since every worker this run dispatched would meet that same decision after merging its own work to develop. Read - them with `gh issue list --repo "/" --label decision --state open --limit 100` - under step 2's full-page check, then each one's comments with `gh issue view --comments`. + them with `gh issue list --repo "/" --label decision --state open --limit 100 + --json number,body,comments` under step 2's full-page check. 2. **Read the open handoffs** with labels and update times, `gh issue list --repo "/" --label handoff --state open --limit 100 --json number,title,labels,updatedAt`, since `handoff.py tracks` prints neither. Where it returns as many rows as the limit, the list may be truncated, so @@ -197,13 +197,10 @@ does not qualify, since skipping one costs nothing and a guess costs a revert an read its comments with `gh issue view "" --repo "/" --comments`, since `resume` prints only the body and a parked lane's state is in its parking comment. A lane handed back by an attended session has a closed predecessor holding that comment, so read the predecessor's - comments too. Where the newest parking comment names a decision issue the lane waits on, and - that comment is on the current link while the issue still carries `decision`, the worker - before was interrupted while parking, so finish parking per "Parking" step 4 and return - `PARKED`. Where it names one and neither holds, read the answer or the reason recorded on that - issue and follow it, since it is what unblocked the lane. A lesson issue the comment also - names, per step 6, is its own work rather than this lane's, so the worker neither follows it - nor parks on it. Re-derive live state rather than trusting any of them, per `session-handoff` + comments too. Where the parking comment names the decision issue the lane waits on, read the + answer recorded there and follow it, since it is what unblocked the lane. A lesson issue the + comment also names, per step 6, is its own work rather than this lane's, so the worker neither + follows it nor parks on it. Re-derive live state rather than trusting any of them, per `session-handoff` "Resuming". 2. **Isolate** in a worktree of its own, per `repo-worktree`, on the branch the handoff names or on `feature/`. diff --git a/.github/skills/unattended-handoff/SKILL.md b/.github/skills/unattended-handoff/SKILL.md index fb4bee95e..ccee6061d 100644 --- a/.github/skills/unattended-handoff/SKILL.md +++ b/.github/skills/unattended-handoff/SKILL.md @@ -164,8 +164,8 @@ does not qualify, since skipping one costs nothing and a guess costs a revert an in its body or in a comment on it, that it blocks the open develop -> main pull request, as "Parking" step 2 has it state, return `STOP` before picking anything, since every worker this run dispatched would meet that same decision after merging its own work to develop. Read - them with `gh issue list --repo "/" --label decision --state open --limit 100` - under step 2's full-page check, then each one's comments with `gh issue view --comments`. + them with `gh issue list --repo "/" --label decision --state open --limit 100 + --json number,body,comments` under step 2's full-page check. 2. **Read the open handoffs** with labels and update times, `gh issue list --repo "/" --label handoff --state open --limit 100 --json number,title,labels,updatedAt`, since `handoff.py tracks` prints neither. Where it returns as many rows as the limit, the list may be truncated, so @@ -197,13 +197,10 @@ does not qualify, since skipping one costs nothing and a guess costs a revert an read its comments with `gh issue view "" --repo "/" --comments`, since `resume` prints only the body and a parked lane's state is in its parking comment. A lane handed back by an attended session has a closed predecessor holding that comment, so read the predecessor's - comments too. Where the newest parking comment names a decision issue the lane waits on, and - that comment is on the current link while the issue still carries `decision`, the worker - before was interrupted while parking, so finish parking per "Parking" step 4 and return - `PARKED`. Where it names one and neither holds, read the answer or the reason recorded on that - issue and follow it, since it is what unblocked the lane. A lesson issue the comment also - names, per step 6, is its own work rather than this lane's, so the worker neither follows it - nor parks on it. Re-derive live state rather than trusting any of them, per `session-handoff` + comments too. Where the parking comment names the decision issue the lane waits on, read the + answer recorded there and follow it, since it is what unblocked the lane. A lesson issue the + comment also names, per step 6, is its own work rather than this lane's, so the worker neither + follows it nor parks on it. Re-derive live state rather than trusting any of them, per `session-handoff` "Resuming". 2. **Isolate** in a worktree of its own, per `repo-worktree`, on the branch the handoff names or on `feature/`. From 31261ecbce4a3fdbc95f70287e814ecba3b660c1 Mon Sep 17 00:00:00 2001 From: Pieter Viljoen Date: Wed, 30 Sep 2026 16:42:48 -0700 Subject: [PATCH 6/6] Rewrap the Worker Resume Step to the Tree's Line Width --- .agents/skills/unattended-handoff/SKILL.md | 4 ++-- .../fleet-skills/.source-digests/unattended-handoff | 2 +- .../fleet-skills/skills/unattended-handoff/SKILL.md | 4 ++-- .github/skills/unattended-handoff/SKILL.md | 4 ++-- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/.agents/skills/unattended-handoff/SKILL.md b/.agents/skills/unattended-handoff/SKILL.md index ccee6061d..63ea4f609 100644 --- a/.agents/skills/unattended-handoff/SKILL.md +++ b/.agents/skills/unattended-handoff/SKILL.md @@ -200,8 +200,8 @@ does not qualify, since skipping one costs nothing and a guess costs a revert an comments too. Where the parking comment names the decision issue the lane waits on, read the answer recorded there and follow it, since it is what unblocked the lane. A lesson issue the comment also names, per step 6, is its own work rather than this lane's, so the worker neither - follows it nor parks on it. Re-derive live state rather than trusting any of them, per `session-handoff` - "Resuming". + follows it nor parks on it. Re-derive live state rather than trusting any of them, per + `session-handoff` "Resuming". 2. **Isolate** in a worktree of its own, per `repo-worktree`, on the branch the handoff names or on `feature/`. 3. **Fix and drive.** Run `local-strict-review` before every push, and drive the pull request with diff --git a/.claude-plugin/fleet-skills/.source-digests/unattended-handoff b/.claude-plugin/fleet-skills/.source-digests/unattended-handoff index 93eae4ea0..9a513e9f8 100644 --- a/.claude-plugin/fleet-skills/.source-digests/unattended-handoff +++ b/.claude-plugin/fleet-skills/.source-digests/unattended-handoff @@ -1 +1 @@ -31784baf190feb5b +0429cd90c8d7ea9a diff --git a/.claude-plugin/fleet-skills/skills/unattended-handoff/SKILL.md b/.claude-plugin/fleet-skills/skills/unattended-handoff/SKILL.md index ccee6061d..63ea4f609 100644 --- a/.claude-plugin/fleet-skills/skills/unattended-handoff/SKILL.md +++ b/.claude-plugin/fleet-skills/skills/unattended-handoff/SKILL.md @@ -200,8 +200,8 @@ does not qualify, since skipping one costs nothing and a guess costs a revert an comments too. Where the parking comment names the decision issue the lane waits on, read the answer recorded there and follow it, since it is what unblocked the lane. A lesson issue the comment also names, per step 6, is its own work rather than this lane's, so the worker neither - follows it nor parks on it. Re-derive live state rather than trusting any of them, per `session-handoff` - "Resuming". + follows it nor parks on it. Re-derive live state rather than trusting any of them, per + `session-handoff` "Resuming". 2. **Isolate** in a worktree of its own, per `repo-worktree`, on the branch the handoff names or on `feature/`. 3. **Fix and drive.** Run `local-strict-review` before every push, and drive the pull request with diff --git a/.github/skills/unattended-handoff/SKILL.md b/.github/skills/unattended-handoff/SKILL.md index ccee6061d..63ea4f609 100644 --- a/.github/skills/unattended-handoff/SKILL.md +++ b/.github/skills/unattended-handoff/SKILL.md @@ -200,8 +200,8 @@ does not qualify, since skipping one costs nothing and a guess costs a revert an comments too. Where the parking comment names the decision issue the lane waits on, read the answer recorded there and follow it, since it is what unblocked the lane. A lesson issue the comment also names, per step 6, is its own work rather than this lane's, so the worker neither - follows it nor parks on it. Re-derive live state rather than trusting any of them, per `session-handoff` - "Resuming". + follows it nor parks on it. Re-derive live state rather than trusting any of them, per + `session-handoff` "Resuming". 2. **Isolate** in a worktree of its own, per `repo-worktree`, on the branch the handoff names or on `feature/`. 3. **Fix and drive.** Run `local-strict-review` before every push, and drive the pull request with