From 5d68293031b78d1fbbfbeea3482396b94c4be810 Mon Sep 17 00:00:00 2001 From: Pieter Viljoen Date: Fri, 9 Oct 2026 11:10:53 -0700 Subject: [PATCH] State When an Issue Belongs in a Platform Handoff Lane (#2668) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Summary `session-handoff` "The Chain" defined a track only as a slug naming a lane of work, so nothing said when an issue belongs in a platform lane. This adds one bullet stating the maintainer's rule from the issue: a platform lane holds only work that needs its platform, an issue a Linux host can fix and verify goes to the ordinary backlog, a mixed issue's platform-only half is filed into the lane while the original is narrowed to the rest, and a platform lane holding no qualifying issue is closed out with no successor. The generated `.claude-plugin/` and `.github/skills/` copies are regenerated with `build_dist.py`. Closes on promotion: #2610 ## Local Review Findings Still Open ### First push (b3ccd27f) The first push's local edit budget ran out after two rounds. The third pass raised three findings, all classed `introduced`. Commits 2a18487e and eefcf897 fix them: - `introduced`: one shared test did not tell platform lanes apart. It is now per platform. - `introduced`: "Systemd user scopes and apt need neither" was categorical. They now take the same WSL or Windows exception a script takes. - `introduced`: the lane-cost clause sat beside "the backlog". It now names the platform lane. The second pass on that push also asked whether a fix verified by CI on a platform runner counts as Linux-verifiable. #2610 does not settle that, so it is filed as decision #2669, which blocks nothing here. ### Second push (eefcf897) The second push's budget also ran out. Its last pass raised four findings, all classed `introduced`. Commits cb9e6688 and 555d85f5 fix them: - `introduced`: a WSL host is both a Linux host and a Windows machine, so "no host lacking it" has no stable meaning there. It can send a Windows PowerShell 5.1 defect to the backlog, or list a WSL defect in both lanes. - `introduced`: the close-out trigger "next steps name no issue that needs its platform" lets a lane whose next steps are unfiled platform work close with that work untracked. - `introduced`: backlog-burndown "Ranking" does not exclude an issue a platform lane has taken, so a Windows-only issue can still be dispatched to a Linux worker. - `introduced`: a split where every part needs some platform leaves the original "narrowed" to nothing and still open in the backlog. ### Third push (555d85f5) This push also adds a paragraph to backlog-burndown "Ranking" and a sentence to unattended-handoff "Auto-Resolvable", so neither seat dispatches a Linux worker on an issue that needs a platform. Its budget also ran out. The last pass raised three findings, all classed `introduced`. Commits 5f55ba4b and b90b9b1e fix them: - `introduced`: the examples say "It is `wsl` work" from the first condition alone. A `/mnt/` translation fix that a plain Linux unit test verifies fails the second condition and belongs in the backlog. - `introduced`: "each remaining step first filed as a backlog issue" files a duplicate for a step that already has an open issue. - `introduced`: the Ranking paragraph asks for a split, which the unattended picker may not write, and Auto-Resolvable excludes a mixed issue whole. The two skills disagree on whether a mixed issue's Linux half gets worked. ### Fourth push (b90b9b1e) Its budget also ran out. The last pass raised two findings, both classed `introduced`. Commits 8c629b0b and 7251c7ab answer them: - `introduced`: "Systemd user scopes, apt, and bash or `pwsh` scripts in a Linux container need a lane only where the defect depends on the platform" widens #2610's exception, which only the `pwsh` case carries, and "the platform" has no antecedent. - `introduced`: nothing names who makes a split, so "which an attended session makes" is unverifiable. Nothing says how a closed platform lane takes a new issue either. ### Fifth push (7251c7ab) Its passes raised these. Two are deferred to #2670 rather than grown into this change, since each needs new machinery outside the rule: - `introduced`, fixed in 7251c7ab: the systemd, apt, and bash exception named only WSL, so a macOS-only defect got two answers. - `introduced`, deferred to #2670: nothing records that an issue belongs to a lane, the close-out test reads next steps rather than membership, and no seat reopens a closed lane for a new issue. - `introduced`, deferred to #2670: an unattended run has no channel to report a platform or mixed issue it skipped. - `pre-existing`, noted on #2670: the attended session's pick has no host check. - `introduced`, fixed in c2bc6e26: the topic carve-outs for systemd, apt, bash, and `pwsh` fell back to where a defect reproduces and dropped the second condition. They are replaced by a sentence saying the two conditions decide those issues like any other. ### Sixth push (bbd75521) - `introduced`, fixed in bbd75521: the bullet did not say what makes a track a platform track. - `introduced`, fixed in bbd75521: "Its last link" bound to the newly filed step issue rather than the lane. - `introduced`, fixed in bbd75521: in unattended-handoff, "a whole one" bound to "platform", and "It" meant the fix rather than the issue. - `pre-existing`, noted on #2670: #2610's own "on that platform alone" test gives a defect failing on two non-Linux platforms no lane. - `introduced`, deferred to #2670: nothing tells a platform lane's session to drop an issue that fails the test from its next steps. This is the reverse direction of that issue's membership gap. ## Verification - `python3 scripts/build_dist.py --check`: current. - `prose_lint.py --diff origin/develop`: no violations. - `docker_lint.py` markdownlint, cspell, editorconfig-checker: success. - `spec/validate.py`: OK. 🤖 Generated with [Claude Code](https://claude.com/claude-code) ## Summary by CodeRabbit * **Documentation** * Updated backlog and handoff guidance to clarify how fully or partly platform-dependent issues are ranked, split, and assigned to platform-specific lanes. * Clarified when platform-specific work qualifies for a separate handoff track and how those lanes are managed. * Round reports now identify held issues, the relevant platform, and whether a split is pending. --------- Co-authored-by: Claude Opus 5.5 --- .agents/skills/backlog-burndown/SKILL.md | 7 +++++++ .agents/skills/session-handoff/SKILL.md | 20 +++++++++++++++++++ .agents/skills/unattended-handoff/SKILL.md | 5 ++++- .../.source-digests/backlog-burndown | 2 +- .../.source-digests/session-handoff | 2 +- .../.source-digests/unattended-handoff | 2 +- .../skills/backlog-burndown/SKILL.md | 7 +++++++ .../skills/session-handoff/SKILL.md | 20 +++++++++++++++++++ .../skills/unattended-handoff/SKILL.md | 5 ++++- .github/skills/backlog-burndown/SKILL.md | 7 +++++++ .github/skills/session-handoff/SKILL.md | 20 +++++++++++++++++++ .github/skills/unattended-handoff/SKILL.md | 5 ++++- 12 files changed, 96 insertions(+), 6 deletions(-) diff --git a/.agents/skills/backlog-burndown/SKILL.md b/.agents/skills/backlog-burndown/SKILL.md index f6dca29f0..6af2eca2d 100644 --- a/.agents/skills/backlog-burndown/SKILL.md +++ b/.agents/skills/backlog-burndown/SKILL.md @@ -130,6 +130,13 @@ stands rather than being assumed cleared. The round's report names every issue i and the blocker each one waits on, since the maintainer reads the report rather than the issue bodies, and a stuck issue nobody names reads as ordinary backlog that simply never moves. +An issue that needs a platform, by the test `session-handoff` "The Chain" states, is counted and +is not ranked. It belongs to that platform's lane, so this run gives it no group, no worker, and no +claim. An issue only part of which needs a platform is held back the same way. It waits on the +split "The Chain" describes, which this run does not make, and the narrowed issue is ranked once +that split lands. The round's report names each issue held back this way, its platform, and +whether it waits on a split, as it names a `blocked` one. + An issue that asks a question rather than states a defect is not ranked and is never guessed at. It has no group, no worker, and no claim, so nothing in "Raising a Blocked Question" applies to it except how the question travels. It goes to the maintainer at the end of ranking, per diff --git a/.agents/skills/session-handoff/SKILL.md b/.agents/skills/session-handoff/SKILL.md index b84ad5f50..55895d2e2 100644 --- a/.agents/skills/session-handoff/SKILL.md +++ b/.agents/skills/session-handoff/SKILL.md @@ -62,6 +62,26 @@ without trusting the parts of it that have gone stale. - **One open handoff issue per track per repository.** A track is a short kebab-case slug naming a lane of work, and a session that names no track uses `default`. Parallel lanes each name their own, so each closes its own predecessor and neither reads the other's state as current. +- **A platform lane is for work that needs its platform.** A platform track is one kept for a single + host platform, such as `wsl` or `windows`. It takes an issue only when its defect reproduces, or + its fix can be verified, on that platform alone. It also needs that no Linux host outside WSL can + both fix the issue and verify the fix. An issue meeting both goes to its platform's lane. Any + other issue goes to the ordinary backlog, since a lane costs a separate chain and a host-bound + session. A defect in WSL interop, the `WSLInterop` binfmt handler, `/mnt/` paths, or + `wslpath` reproduces only inside WSL. So does running a Windows `.exe` from Linux, although WSL + runs on Windows. Behavior that differs under Windows PowerShell 5.1 or `winget`, or in Windows + path and ACL semantics, reproduces only on Windows. Either still goes to the backlog where a Linux + host outside WSL verifies its fix, as a plain unit test of a path translation can. An issue in + systemd user scopes, apt, a bash script, or a `pwsh` script run in a Linux container gets no lane + by its topic. The two conditions decide it like any other issue. Where only part of an issue needs + a platform, the session finding it files each such part as its own issue for its platform's lane. + The original is narrowed to the rest, or closed in favor of those issues where nothing is left. A + session that may not write issues names the unsplit issue in its report or handoff instead. An + issue for a platform whose lane was closed out reopens that lane with `new`, which chains onto the + closed link. A platform lane is closed out with no successor once none of its next steps needs its + platform. Before that, each remaining step with no issue of its own is filed as one. The lane's + last link carries the outcome as a comment, as `AGENTS.md` "Session Scope" closes a track whose + work is complete. - **The title is for humans**, shaped `Session Handoff []: `, which `new` composes from the track and the subject it is given, so what a session writes is the subject alone. Nothing parses the title, so a maintainer is free to rename one. diff --git a/.agents/skills/unattended-handoff/SKILL.md b/.agents/skills/unattended-handoff/SKILL.md index dc6af99c1..4094aecbc 100644 --- a/.agents/skills/unattended-handoff/SKILL.md +++ b/.agents/skills/unattended-handoff/SKILL.md @@ -154,7 +154,10 @@ does not qualify, since skipping one costs nothing and a guess costs a revert an and no comment asks the maintainer something still unanswered. - **The fix stays inside this repository's tree.** It changes no repository setting, ruleset, visibility, secret, or release condition, and needs no credential, account, or host the session - lacks. + lacks. The issue needs no platform, in whole or in part, by the test `session-handoff` "The + Chain" states. An issue that wholly needs a platform belongs to that platform's lane whatever host + the session runs on. One that partly needs it waits on the split that section describes, a write + the picker does not make. - **The fix edits nothing under the hub's `host-setup/agent-safety/`.** That tree is the agent's own guard, and it is worked only in an attended session, so a human approves every change to it. - **It reverses no settled decision** recorded in an issue, a handoff, or the rule text. diff --git a/.claude-plugin/fleet-skills/.source-digests/backlog-burndown b/.claude-plugin/fleet-skills/.source-digests/backlog-burndown index 17c143684..57e5b1905 100644 --- a/.claude-plugin/fleet-skills/.source-digests/backlog-burndown +++ b/.claude-plugin/fleet-skills/.source-digests/backlog-burndown @@ -1 +1 @@ -a44167992b6a50fe +f9045d01bca0c44a diff --git a/.claude-plugin/fleet-skills/.source-digests/session-handoff b/.claude-plugin/fleet-skills/.source-digests/session-handoff index 6d54cf547..8fbedf923 100644 --- a/.claude-plugin/fleet-skills/.source-digests/session-handoff +++ b/.claude-plugin/fleet-skills/.source-digests/session-handoff @@ -1 +1 @@ -71ea890bf0050608 +2c0a84e0767fc97c diff --git a/.claude-plugin/fleet-skills/.source-digests/unattended-handoff b/.claude-plugin/fleet-skills/.source-digests/unattended-handoff index 6efa07914..6512a3832 100644 --- a/.claude-plugin/fleet-skills/.source-digests/unattended-handoff +++ b/.claude-plugin/fleet-skills/.source-digests/unattended-handoff @@ -1 +1 @@ -edad0bee58257e24 +06ef313c4d01b168 diff --git a/.claude-plugin/fleet-skills/skills/backlog-burndown/SKILL.md b/.claude-plugin/fleet-skills/skills/backlog-burndown/SKILL.md index f6dca29f0..6af2eca2d 100644 --- a/.claude-plugin/fleet-skills/skills/backlog-burndown/SKILL.md +++ b/.claude-plugin/fleet-skills/skills/backlog-burndown/SKILL.md @@ -130,6 +130,13 @@ stands rather than being assumed cleared. The round's report names every issue i and the blocker each one waits on, since the maintainer reads the report rather than the issue bodies, and a stuck issue nobody names reads as ordinary backlog that simply never moves. +An issue that needs a platform, by the test `session-handoff` "The Chain" states, is counted and +is not ranked. It belongs to that platform's lane, so this run gives it no group, no worker, and no +claim. An issue only part of which needs a platform is held back the same way. It waits on the +split "The Chain" describes, which this run does not make, and the narrowed issue is ranked once +that split lands. The round's report names each issue held back this way, its platform, and +whether it waits on a split, as it names a `blocked` one. + An issue that asks a question rather than states a defect is not ranked and is never guessed at. It has no group, no worker, and no claim, so nothing in "Raising a Blocked Question" applies to it except how the question travels. It goes to the maintainer at the end of ranking, per diff --git a/.claude-plugin/fleet-skills/skills/session-handoff/SKILL.md b/.claude-plugin/fleet-skills/skills/session-handoff/SKILL.md index b84ad5f50..55895d2e2 100644 --- a/.claude-plugin/fleet-skills/skills/session-handoff/SKILL.md +++ b/.claude-plugin/fleet-skills/skills/session-handoff/SKILL.md @@ -62,6 +62,26 @@ without trusting the parts of it that have gone stale. - **One open handoff issue per track per repository.** A track is a short kebab-case slug naming a lane of work, and a session that names no track uses `default`. Parallel lanes each name their own, so each closes its own predecessor and neither reads the other's state as current. +- **A platform lane is for work that needs its platform.** A platform track is one kept for a single + host platform, such as `wsl` or `windows`. It takes an issue only when its defect reproduces, or + its fix can be verified, on that platform alone. It also needs that no Linux host outside WSL can + both fix the issue and verify the fix. An issue meeting both goes to its platform's lane. Any + other issue goes to the ordinary backlog, since a lane costs a separate chain and a host-bound + session. A defect in WSL interop, the `WSLInterop` binfmt handler, `/mnt/` paths, or + `wslpath` reproduces only inside WSL. So does running a Windows `.exe` from Linux, although WSL + runs on Windows. Behavior that differs under Windows PowerShell 5.1 or `winget`, or in Windows + path and ACL semantics, reproduces only on Windows. Either still goes to the backlog where a Linux + host outside WSL verifies its fix, as a plain unit test of a path translation can. An issue in + systemd user scopes, apt, a bash script, or a `pwsh` script run in a Linux container gets no lane + by its topic. The two conditions decide it like any other issue. Where only part of an issue needs + a platform, the session finding it files each such part as its own issue for its platform's lane. + The original is narrowed to the rest, or closed in favor of those issues where nothing is left. A + session that may not write issues names the unsplit issue in its report or handoff instead. An + issue for a platform whose lane was closed out reopens that lane with `new`, which chains onto the + closed link. A platform lane is closed out with no successor once none of its next steps needs its + platform. Before that, each remaining step with no issue of its own is filed as one. The lane's + last link carries the outcome as a comment, as `AGENTS.md` "Session Scope" closes a track whose + work is complete. - **The title is for humans**, shaped `Session Handoff []: `, which `new` composes from the track and the subject it is given, so what a session writes is the subject alone. Nothing parses the title, so a maintainer is free to rename one. diff --git a/.claude-plugin/fleet-skills/skills/unattended-handoff/SKILL.md b/.claude-plugin/fleet-skills/skills/unattended-handoff/SKILL.md index dc6af99c1..4094aecbc 100644 --- a/.claude-plugin/fleet-skills/skills/unattended-handoff/SKILL.md +++ b/.claude-plugin/fleet-skills/skills/unattended-handoff/SKILL.md @@ -154,7 +154,10 @@ does not qualify, since skipping one costs nothing and a guess costs a revert an and no comment asks the maintainer something still unanswered. - **The fix stays inside this repository's tree.** It changes no repository setting, ruleset, visibility, secret, or release condition, and needs no credential, account, or host the session - lacks. + lacks. The issue needs no platform, in whole or in part, by the test `session-handoff` "The + Chain" states. An issue that wholly needs a platform belongs to that platform's lane whatever host + the session runs on. One that partly needs it waits on the split that section describes, a write + the picker does not make. - **The fix edits nothing under the hub's `host-setup/agent-safety/`.** That tree is the agent's own guard, and it is worked only in an attended session, so a human approves every change to it. - **It reverses no settled decision** recorded in an issue, a handoff, or the rule text. diff --git a/.github/skills/backlog-burndown/SKILL.md b/.github/skills/backlog-burndown/SKILL.md index f6dca29f0..6af2eca2d 100644 --- a/.github/skills/backlog-burndown/SKILL.md +++ b/.github/skills/backlog-burndown/SKILL.md @@ -130,6 +130,13 @@ stands rather than being assumed cleared. The round's report names every issue i and the blocker each one waits on, since the maintainer reads the report rather than the issue bodies, and a stuck issue nobody names reads as ordinary backlog that simply never moves. +An issue that needs a platform, by the test `session-handoff` "The Chain" states, is counted and +is not ranked. It belongs to that platform's lane, so this run gives it no group, no worker, and no +claim. An issue only part of which needs a platform is held back the same way. It waits on the +split "The Chain" describes, which this run does not make, and the narrowed issue is ranked once +that split lands. The round's report names each issue held back this way, its platform, and +whether it waits on a split, as it names a `blocked` one. + An issue that asks a question rather than states a defect is not ranked and is never guessed at. It has no group, no worker, and no claim, so nothing in "Raising a Blocked Question" applies to it except how the question travels. It goes to the maintainer at the end of ranking, per diff --git a/.github/skills/session-handoff/SKILL.md b/.github/skills/session-handoff/SKILL.md index b84ad5f50..55895d2e2 100644 --- a/.github/skills/session-handoff/SKILL.md +++ b/.github/skills/session-handoff/SKILL.md @@ -62,6 +62,26 @@ without trusting the parts of it that have gone stale. - **One open handoff issue per track per repository.** A track is a short kebab-case slug naming a lane of work, and a session that names no track uses `default`. Parallel lanes each name their own, so each closes its own predecessor and neither reads the other's state as current. +- **A platform lane is for work that needs its platform.** A platform track is one kept for a single + host platform, such as `wsl` or `windows`. It takes an issue only when its defect reproduces, or + its fix can be verified, on that platform alone. It also needs that no Linux host outside WSL can + both fix the issue and verify the fix. An issue meeting both goes to its platform's lane. Any + other issue goes to the ordinary backlog, since a lane costs a separate chain and a host-bound + session. A defect in WSL interop, the `WSLInterop` binfmt handler, `/mnt/` paths, or + `wslpath` reproduces only inside WSL. So does running a Windows `.exe` from Linux, although WSL + runs on Windows. Behavior that differs under Windows PowerShell 5.1 or `winget`, or in Windows + path and ACL semantics, reproduces only on Windows. Either still goes to the backlog where a Linux + host outside WSL verifies its fix, as a plain unit test of a path translation can. An issue in + systemd user scopes, apt, a bash script, or a `pwsh` script run in a Linux container gets no lane + by its topic. The two conditions decide it like any other issue. Where only part of an issue needs + a platform, the session finding it files each such part as its own issue for its platform's lane. + The original is narrowed to the rest, or closed in favor of those issues where nothing is left. A + session that may not write issues names the unsplit issue in its report or handoff instead. An + issue for a platform whose lane was closed out reopens that lane with `new`, which chains onto the + closed link. A platform lane is closed out with no successor once none of its next steps needs its + platform. Before that, each remaining step with no issue of its own is filed as one. The lane's + last link carries the outcome as a comment, as `AGENTS.md` "Session Scope" closes a track whose + work is complete. - **The title is for humans**, shaped `Session Handoff []: `, which `new` composes from the track and the subject it is given, so what a session writes is the subject alone. Nothing parses the title, so a maintainer is free to rename one. diff --git a/.github/skills/unattended-handoff/SKILL.md b/.github/skills/unattended-handoff/SKILL.md index dc6af99c1..4094aecbc 100644 --- a/.github/skills/unattended-handoff/SKILL.md +++ b/.github/skills/unattended-handoff/SKILL.md @@ -154,7 +154,10 @@ does not qualify, since skipping one costs nothing and a guess costs a revert an and no comment asks the maintainer something still unanswered. - **The fix stays inside this repository's tree.** It changes no repository setting, ruleset, visibility, secret, or release condition, and needs no credential, account, or host the session - lacks. + lacks. The issue needs no platform, in whole or in part, by the test `session-handoff` "The + Chain" states. An issue that wholly needs a platform belongs to that platform's lane whatever host + the session runs on. One that partly needs it waits on the split that section describes, a write + the picker does not make. - **The fix edits nothing under the hub's `host-setup/agent-safety/`.** That tree is the agent's own guard, and it is worked only in an attended session, so a human approves every change to it. - **It reverses no settled decision** recorded in an issue, a handoff, or the rule text.