From 4a6f2b5ed23407b96ca8dd660d46e8d9112da637 Mon Sep 17 00:00:00 2001 From: Pieter Viljoen Date: Sun, 1 Nov 2026 09:53:01 -0800 Subject: [PATCH 1/2] Fetch origin Before decision-triage's History Check The classifier's overtaken check and the researcher's on-main test both read origin/main, and the check also reads develop for a HELD issue. A stale remote-tracking ref reads an overtaken issue as HELD or as open work, so both now fetch immediately before reading and stop on a failed fetch. Answers promotion #3762's first review round. Co-Authored-By: Claude Opus 5.5 --- .agents/skills/decision-triage/SKILL.md | 6 ++++-- .claude-plugin/fleet-skills/.source-digests/decision-triage | 2 +- .claude-plugin/fleet-skills/skills/decision-triage/SKILL.md | 6 ++++-- .github/skills/decision-triage/SKILL.md | 6 ++++-- 4 files changed, 13 insertions(+), 7 deletions(-) diff --git a/.agents/skills/decision-triage/SKILL.md b/.agents/skills/decision-triage/SKILL.md index 246fa6239..647a5af9a 100644 --- a/.agents/skills/decision-triage/SKILL.md +++ b/.agents/skills/decision-triage/SKILL.md @@ -96,7 +96,9 @@ of its own. 2. **Classify the rest** in batches, one `standard` classifier per batch, at most four running at once. Each applies "Needs the Maintainer" above, which its brief quotes whole. Before that, it checks whether a later change has already overtaken the issue, which is a cheap history check - rather than research. The check reads `git log origin/main` on the files the issue names, the + rather than research. The check fetches `origin` immediately before it reads, and stops and + reports if the fetch fails. A stale `origin/main` or `origin/develop` reads an overtaken issue + as `HELD` or as open work. It reads `git log origin/main` on the files the issue names, the state of any child issues it tracks, and any later comment recording a decision. A fix merged into `develop` and not yet promoted makes the issue `HELD` awaiting promotion rather than `OVERTAKEN`. The queued `decision` issues get the same check and no classification beyond it. @@ -111,7 +113,7 @@ of its own. code. It returns in the form "Return Lines" below, and writes only to the scratch directory its brief names. A queued question a later change has already answered or overtaken comes back as `OVERTAKEN` rather than as options. A fix counts as that change only once it is on - `origin/main`. + `origin/main`, read after a fetch the same way the step 2 check reads it. 4. **Record each question** before asking it, so the question survives an interrupted session. - For an `ASK`, comment the researched question on the issue and add the `decision` label. - For a `SPLIT`, file a new issue holding only the undecided item, carrying `decision`. diff --git a/.claude-plugin/fleet-skills/.source-digests/decision-triage b/.claude-plugin/fleet-skills/.source-digests/decision-triage index 891910731..e35b81fee 100644 --- a/.claude-plugin/fleet-skills/.source-digests/decision-triage +++ b/.claude-plugin/fleet-skills/.source-digests/decision-triage @@ -1 +1 @@ -f5a2fe8201774e01 +d55ce63a9161616a diff --git a/.claude-plugin/fleet-skills/skills/decision-triage/SKILL.md b/.claude-plugin/fleet-skills/skills/decision-triage/SKILL.md index 246fa6239..647a5af9a 100644 --- a/.claude-plugin/fleet-skills/skills/decision-triage/SKILL.md +++ b/.claude-plugin/fleet-skills/skills/decision-triage/SKILL.md @@ -96,7 +96,9 @@ of its own. 2. **Classify the rest** in batches, one `standard` classifier per batch, at most four running at once. Each applies "Needs the Maintainer" above, which its brief quotes whole. Before that, it checks whether a later change has already overtaken the issue, which is a cheap history check - rather than research. The check reads `git log origin/main` on the files the issue names, the + rather than research. The check fetches `origin` immediately before it reads, and stops and + reports if the fetch fails. A stale `origin/main` or `origin/develop` reads an overtaken issue + as `HELD` or as open work. It reads `git log origin/main` on the files the issue names, the state of any child issues it tracks, and any later comment recording a decision. A fix merged into `develop` and not yet promoted makes the issue `HELD` awaiting promotion rather than `OVERTAKEN`. The queued `decision` issues get the same check and no classification beyond it. @@ -111,7 +113,7 @@ of its own. code. It returns in the form "Return Lines" below, and writes only to the scratch directory its brief names. A queued question a later change has already answered or overtaken comes back as `OVERTAKEN` rather than as options. A fix counts as that change only once it is on - `origin/main`. + `origin/main`, read after a fetch the same way the step 2 check reads it. 4. **Record each question** before asking it, so the question survives an interrupted session. - For an `ASK`, comment the researched question on the issue and add the `decision` label. - For a `SPLIT`, file a new issue holding only the undecided item, carrying `decision`. diff --git a/.github/skills/decision-triage/SKILL.md b/.github/skills/decision-triage/SKILL.md index 246fa6239..647a5af9a 100644 --- a/.github/skills/decision-triage/SKILL.md +++ b/.github/skills/decision-triage/SKILL.md @@ -96,7 +96,9 @@ of its own. 2. **Classify the rest** in batches, one `standard` classifier per batch, at most four running at once. Each applies "Needs the Maintainer" above, which its brief quotes whole. Before that, it checks whether a later change has already overtaken the issue, which is a cheap history check - rather than research. The check reads `git log origin/main` on the files the issue names, the + rather than research. The check fetches `origin` immediately before it reads, and stops and + reports if the fetch fails. A stale `origin/main` or `origin/develop` reads an overtaken issue + as `HELD` or as open work. It reads `git log origin/main` on the files the issue names, the state of any child issues it tracks, and any later comment recording a decision. A fix merged into `develop` and not yet promoted makes the issue `HELD` awaiting promotion rather than `OVERTAKEN`. The queued `decision` issues get the same check and no classification beyond it. @@ -111,7 +113,7 @@ of its own. code. It returns in the form "Return Lines" below, and writes only to the scratch directory its brief names. A queued question a later change has already answered or overtaken comes back as `OVERTAKEN` rather than as options. A fix counts as that change only once it is on - `origin/main`. + `origin/main`, read after a fetch the same way the step 2 check reads it. 4. **Record each question** before asking it, so the question survives an interrupted session. - For an `ASK`, comment the researched question on the issue and add the `decision` label. - For a `SPLIT`, file a new issue holding only the undecided item, carrying `decision`. From 252550aef770017ee5899ebdde028f3e7c8bdcea Mon Sep 17 00:00:00 2001 From: Pieter Viljoen Date: Sun, 1 Nov 2026 09:55:05 -0800 Subject: [PATCH 2/2] Fetch Once in the Triaging Session Rather Than in Each Subagent The subagents are read-only and run four at a time, so a fetch in each broke their write bound and raced on the checkout's ref locks. The triaging session now fetches main and develop once before dispatching, and the history check reads the full remote-tracking refs. Co-Authored-By: Claude Opus 5.5 --- .agents/skills/decision-triage/SKILL.md | 18 +++++++++++------- .../.source-digests/decision-triage | 2 +- .../skills/decision-triage/SKILL.md | 18 +++++++++++------- .github/skills/decision-triage/SKILL.md | 18 +++++++++++------- 4 files changed, 34 insertions(+), 22 deletions(-) diff --git a/.agents/skills/decision-triage/SKILL.md b/.agents/skills/decision-triage/SKILL.md index 647a5af9a..cacb10cda 100644 --- a/.agents/skills/decision-triage/SKILL.md +++ b/.agents/skills/decision-triage/SKILL.md @@ -94,12 +94,15 @@ of its own. carrying `handoff`, `canonical-sweep`, or `deferred`, and keep the `deferred` count for the report. Mark the open `decision` issues as questions already queued. 2. **Classify the rest** in batches, one `standard` classifier per batch, at most four running at - once. Each applies "Needs the Maintainer" above, which its brief quotes whole. Before that, it - checks whether a later change has already overtaken the issue, which is a cheap history check - rather than research. The check fetches `origin` immediately before it reads, and stops and - reports if the fetch fails. A stale `origin/main` or `origin/develop` reads an overtaken issue - as `HELD` or as open work. It reads `git log origin/main` on the files the issue names, the - state of any child issues it tracks, and any later comment recording a decision. A fix merged + once. Before dispatching, the triaging session runs `git fetch origin main develop` once, and + stops and reports if it fails. A stale `main` reads an overtaken issue as `HELD`. A stale + `develop` reads a `HELD` one as open work. The subagents read the refs this fetch updated and + fetch nothing. + Each classifier applies "Needs the Maintainer" above, which its brief quotes whole. Before + that, it checks whether a later change has already overtaken the issue, which is a cheap + history check rather than research. The check reads `git log refs/remotes/origin/main` and + `git log refs/remotes/origin/develop` on the files the issue names. It also reads the state of + any child issues the issue tracks, and any later comment recording a decision. A fix merged into `develop` and not yet promoted makes the issue `HELD` awaiting promotion rather than `OVERTAKEN`. The queued `decision` issues get the same check and no classification beyond it. The classifier returns one line per issue in the form "Return Lines" below. @@ -113,7 +116,8 @@ of its own. code. It returns in the form "Return Lines" below, and writes only to the scratch directory its brief names. A queued question a later change has already answered or overtaken comes back as `OVERTAKEN` rather than as options. A fix counts as that change only once it is on - `origin/main`, read after a fetch the same way the step 2 check reads it. + `refs/remotes/origin/main`. The triaging session repeats step 2's fetch before dispatching, + under the same stop. 4. **Record each question** before asking it, so the question survives an interrupted session. - For an `ASK`, comment the researched question on the issue and add the `decision` label. - For a `SPLIT`, file a new issue holding only the undecided item, carrying `decision`. diff --git a/.claude-plugin/fleet-skills/.source-digests/decision-triage b/.claude-plugin/fleet-skills/.source-digests/decision-triage index e35b81fee..1a62b56bf 100644 --- a/.claude-plugin/fleet-skills/.source-digests/decision-triage +++ b/.claude-plugin/fleet-skills/.source-digests/decision-triage @@ -1 +1 @@ -d55ce63a9161616a +442bfb38707552cd diff --git a/.claude-plugin/fleet-skills/skills/decision-triage/SKILL.md b/.claude-plugin/fleet-skills/skills/decision-triage/SKILL.md index 647a5af9a..cacb10cda 100644 --- a/.claude-plugin/fleet-skills/skills/decision-triage/SKILL.md +++ b/.claude-plugin/fleet-skills/skills/decision-triage/SKILL.md @@ -94,12 +94,15 @@ of its own. carrying `handoff`, `canonical-sweep`, or `deferred`, and keep the `deferred` count for the report. Mark the open `decision` issues as questions already queued. 2. **Classify the rest** in batches, one `standard` classifier per batch, at most four running at - once. Each applies "Needs the Maintainer" above, which its brief quotes whole. Before that, it - checks whether a later change has already overtaken the issue, which is a cheap history check - rather than research. The check fetches `origin` immediately before it reads, and stops and - reports if the fetch fails. A stale `origin/main` or `origin/develop` reads an overtaken issue - as `HELD` or as open work. It reads `git log origin/main` on the files the issue names, the - state of any child issues it tracks, and any later comment recording a decision. A fix merged + once. Before dispatching, the triaging session runs `git fetch origin main develop` once, and + stops and reports if it fails. A stale `main` reads an overtaken issue as `HELD`. A stale + `develop` reads a `HELD` one as open work. The subagents read the refs this fetch updated and + fetch nothing. + Each classifier applies "Needs the Maintainer" above, which its brief quotes whole. Before + that, it checks whether a later change has already overtaken the issue, which is a cheap + history check rather than research. The check reads `git log refs/remotes/origin/main` and + `git log refs/remotes/origin/develop` on the files the issue names. It also reads the state of + any child issues the issue tracks, and any later comment recording a decision. A fix merged into `develop` and not yet promoted makes the issue `HELD` awaiting promotion rather than `OVERTAKEN`. The queued `decision` issues get the same check and no classification beyond it. The classifier returns one line per issue in the form "Return Lines" below. @@ -113,7 +116,8 @@ of its own. code. It returns in the form "Return Lines" below, and writes only to the scratch directory its brief names. A queued question a later change has already answered or overtaken comes back as `OVERTAKEN` rather than as options. A fix counts as that change only once it is on - `origin/main`, read after a fetch the same way the step 2 check reads it. + `refs/remotes/origin/main`. The triaging session repeats step 2's fetch before dispatching, + under the same stop. 4. **Record each question** before asking it, so the question survives an interrupted session. - For an `ASK`, comment the researched question on the issue and add the `decision` label. - For a `SPLIT`, file a new issue holding only the undecided item, carrying `decision`. diff --git a/.github/skills/decision-triage/SKILL.md b/.github/skills/decision-triage/SKILL.md index 647a5af9a..cacb10cda 100644 --- a/.github/skills/decision-triage/SKILL.md +++ b/.github/skills/decision-triage/SKILL.md @@ -94,12 +94,15 @@ of its own. carrying `handoff`, `canonical-sweep`, or `deferred`, and keep the `deferred` count for the report. Mark the open `decision` issues as questions already queued. 2. **Classify the rest** in batches, one `standard` classifier per batch, at most four running at - once. Each applies "Needs the Maintainer" above, which its brief quotes whole. Before that, it - checks whether a later change has already overtaken the issue, which is a cheap history check - rather than research. The check fetches `origin` immediately before it reads, and stops and - reports if the fetch fails. A stale `origin/main` or `origin/develop` reads an overtaken issue - as `HELD` or as open work. It reads `git log origin/main` on the files the issue names, the - state of any child issues it tracks, and any later comment recording a decision. A fix merged + once. Before dispatching, the triaging session runs `git fetch origin main develop` once, and + stops and reports if it fails. A stale `main` reads an overtaken issue as `HELD`. A stale + `develop` reads a `HELD` one as open work. The subagents read the refs this fetch updated and + fetch nothing. + Each classifier applies "Needs the Maintainer" above, which its brief quotes whole. Before + that, it checks whether a later change has already overtaken the issue, which is a cheap + history check rather than research. The check reads `git log refs/remotes/origin/main` and + `git log refs/remotes/origin/develop` on the files the issue names. It also reads the state of + any child issues the issue tracks, and any later comment recording a decision. A fix merged into `develop` and not yet promoted makes the issue `HELD` awaiting promotion rather than `OVERTAKEN`. The queued `decision` issues get the same check and no classification beyond it. The classifier returns one line per issue in the form "Return Lines" below. @@ -113,7 +116,8 @@ of its own. code. It returns in the form "Return Lines" below, and writes only to the scratch directory its brief names. A queued question a later change has already answered or overtaken comes back as `OVERTAKEN` rather than as options. A fix counts as that change only once it is on - `origin/main`, read after a fetch the same way the step 2 check reads it. + `refs/remotes/origin/main`. The triaging session repeats step 2's fetch before dispatching, + under the same stop. 4. **Record each question** before asking it, so the question survives an interrupted session. - For an `ASK`, comment the researched question on the issue and add the `decision` label. - For a `SPLIT`, file a new issue holding only the undecided item, carrying `decision`.