v1.10.0: a zero exit is not a receipt
Released 2026-08-11. The release where the kit stopped trusting the tools it drives, after a commit landed in somebody else’s pull request and every command involved exited 0.
What we were trying to fix
On 2026-08-10, four agents were working four issues in one shared checkout. The timeline is short enough to quote (#26): at 16:20 implement-issue created a branch for issue 16 and pushed a scaffold commit, correctly. About a minute later a concurrent agent working issue 15 ran git checkout on a different branch in the same working tree. At 16:23 the first agent’s git commit landed on the second agent’s branch, exit 0, no warning, and its git push carried the work into someone else’s PR.
Nothing was lost, but only because a git status afterwards happened to show an unexpected file. The same session produced a second instance with a worse outcome: the code-review sub-skill ran git checkout <ref> -- . in that shared checkout and destroyed an uncommitted delta belonging to a different issue.
The general statement is the one the guards now carry: git commit does not verify you are still on the branch you created, and git push -u prints “branch set up to track” whether or not your commit reached your branch. Both are claims about what git attempted, not about where the work is.
Two other problems were live at the same time. The kit had just started producing follow-up issues automatically, and merge-pr filed one issue per finding with no cap and no arbitration: an unbounded producer feeding a consumer that handles one PR at a time (#108). And the xunit v2 to v3 move inside the migration pipeline was still being decided case by case, in a space where the Microsoft.Testing platform pins several packages that must agree on version.
What we decided
Two layers against the shared-checkout failure, because they do different jobs. Prevent: implement-issue always works in a worktree dedicated to this issue and never commits from the ambient checkout it happened to start in. Detect: guarded helpers assert the branch immediately before committing and compare HEAD against origin/<branch> after pushing (#26, #30). Prevention alone is not enough, since a worktree can still be re-pointed; detection alone leaves the race in place but makes it loud instead of silent.
The merge got the same treatment shortly after (#41), on the reasoning that it is the largest single write in the flow and the one with the widest window, because conflict resolution sits inside it. The branch assertion itself, by then written twice, was given a single home before a third guard could copy it again (#44), and the worktree home learned to prove itself ignored before a worktree is created there (#71) and, later, before an existing one is reused (#86).
Follow-ups got triaged by root cause instead of filed one by one (#108). The evidence came from a consumer repository running this loop: six PRs merged in a day produced 28 new issues and 8 closures, with 13 of them filed in a single 42-second burst. The interesting number is not that 15 of 20 open follow-ups sat in one subsystem, it is that only four would actually be resolved by fixing the root issue that already owned it. Proximity is the easy measure and the wrong one; subsumption is the measure that shipped.
The xunit v3 move became an explicit gate. Rather than migrating whenever it looked possible, it became a phase-5 decision the pipeline records (#12), with the Microsoft.Testing platform and coverage version pairing modelled properly (#18, #38) instead of pinned by hand, and with the Renovate config asserted by what Renovate does with it rather than by what it says (#67).
Underneath all of it, the release plumbing went in: release-please installed, the per-skill version that release-please does not maintain removed (#16), and a CI gate requiring a releasable PR title on any change to a shipped path (#27). Those two are the ones that hardened into architecture decisions: one plugin version and no per-skill version (ADR 0003), and squash-only merges in which the PR title is the release commit (ADR 0004). The second is why every PR title in this repository since reads like a changelog line.
What got cut
The follow-up triage deliberately did not fold on proximity. Most of the 20 open follow-ups in the measured burst were genuinely independent defects that deserved to exist as issues, so folding them by subsystem would have hidden real work. The fold is a sharpener; the arrival budget is the actual brake. That distinction was written into the skill rather than smoothed over, and it is the reason the filing problem was only half solved here and needed #176 two releases later to get a real outlet.
Renovate was blocked from proposing bumps against the frozen legacy fixture, but without hiding that fixture from vulnerability alerts (#40). The one-line version of that change would have used ignorePaths and silenced both, which is worse than doing nothing: a legacy specimen you cannot see the CVEs of is not a specimen, it is a blind spot.
What bit us
The best story in this release is that the guard shipped with a bug in exactly the read-back that justified it. guarded-push parsed git’s warning on stderr rather than ls-remote’s stdout (#47), so the verification step that existed to catch a silent mis-push could itself reach the wrong conclusion. It was found and fixed inside the same release, and it is the reason the guards’ later work went into telling their failure modes apart rather than into adding more of them.
Two smaller ones, both of the same family. A find killed by SIGPIPE silently skipped the checks it was feeding (#48), which is a test suite passing because it stopped running. And a grouped dependency bump (#25) merged with CI already failing, turning main red at its first step, and had to be reverted the same day (#28). That one is worth its line because of what the fix taught: closing a grouped Renovate pull request does not stick, since Renovate reads its configuration from the default branch only and re-forms the group as soon as its version set changes. The prevention was still sitting in draft while the failure it prevents happened.