Skip to content

v2.4.0-rc.1 — Every refusal names its exit

Pre-release
Pre-release

Choose a tag to compare

@Alan-TheGentleman Alan-TheGentleman released this 08 Aug 21:12
Immutable release. Only release title and notes can be modified.
3d1e673

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: stop and now report kind: collect. Their reason_code values are byte-identical on purpose, so a consumer routing on the code is unaffected; one routing on kind sees 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.1

Or 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.