Why this is 2.4.0 and not 2.3.1
Every commit since v2.3.0 is a fix. There is no feat and no !. By convention that is a patch, and it would have been the wrong call: two of those fixes change the negotiated contract in ways a consumer can observe at runtime.
- The abandon maintainer authorization moved from v1 to v2 as a clean break. A stored v1 token is now refused, with the message naming the exact rerun that produces a v2 one.
- Two transitions stopped reporting
kind: stopand now reportkind: collect. Theirreason_codevalues are byte-identical on purpose, so a consumer routing on the code is unaffected; one routing onkindsees something new.
Neither breaks a Go API or a build. Both are behavior changes to a published contract, so they get a minor and a release note instead of a surprise.
Reviews stop being dead ends
The theme of this release is refusals that used to end the conversation and now hand you a command.
A failed verification with an unchanged candidate and budget left reported a lifecycle deadlock. It never was one: rescope had owned that transition since #2298, and nothing said so. Both reset and rescope now name the exits that actually run from the state you are in, including the route to a wider budget, which rescope structurally cannot give you.
A completed objective refused a repeated begin and named no successor, though changing --work-unit was the whole difference. The maintainer-decision block told you to rescope, which is structurally impossible in the one state that printed it. A wrong exit is worse than a missing one: a dead end tells you to stop, advice that cannot work sends you in circles.
Two negotiated transitions that reported stop for a state you can fix by supplying one value now collect that value instead.
Damaged authority stops blocking everything else
One unreadable record used to fail the whole per-repository inventory closed, across every worktree sharing the common dir. Four authority walks now treat it as absent from the graph, so a single bad edge no longer blocks unrelated reviews, recovery or abandonment. The repair surface got the same treatment: a disposition plan is no longer refused because some unrelated entry carries a diagnostic.
review abandon generalizes to any non-terminal lineage under one maintainer authorization, so a wedged review finally has a sanctioned exit.
Installed assets are checked against their content
Reviews now refuse to run against managed assets that disagree with the binary, and the check compares a digest of the assets themselves, not a build identity. A rebuild that changes no asset no longer declares your installation stale.
It refuses only a recorded digest that disagrees. If you never ran gentle-ai install, nothing is stale and nothing is blocked.
Also in this release
Every failure envelope now carries the native cause instead of a constant message, and the SDD binding names which of its twelve integrity conditions failed. Persona resolution stops drifting: gentleman-neutral-artifacts now means neutral, as its name always promised, and migrates once with a notice. Windows NUL config paths in the isolated Git view are fixed. Codex, OpenCode and Claude Code share one advisory reviewer transport.
Install
go install github.com/gentleman-programming/gentle-ai/v2/cmd/gentle-ai@v2.4.0-rc.1Or download a binary below and verify it against SHA256SUMS.txt.
After upgrading, run gentle-ai sync. Managed assets are version-bound to the binary and reviews now refuse a mismatch.
Known open
Two linked-worktree handoff tests fail on Windows (#2783). The lane is green otherwise, and that count is now tracked rather than unknown.