Skip to content

Release v3.25.0 - #130

Merged
atomantic merged 12 commits into
releasefrom
main
Jul 27, 2026
Merged

Release v3.25.0#130
atomantic merged 12 commits into
releasefrom
main

Conversation

@atomantic

Copy link
Copy Markdown
Owner

Release v3.25.0

Released: 2026-07-26

Highlights

  • Per-reviewer iteration caps via a ~max=<n> suffix. Suffix any --review-with slot with ~max=<n>--review-with=claude~max=2,ollama~max=1,codex~max=3 — to give each reviewer its own budget of review → fix → re-review cycles in a single call. This is the per-entry form of --review-iterations, and unlike that flag it reaches every reviewer type: the local agents (codex/claude/agy/grok) and ollama had hardcoded 3-iteration caps with no way to change them, which made a slow local model expensive to include. ollama[qwen3.6:35b]~max=1 now buys exactly one review-and-fix pass.

Added

  • ~max=<n> iteration-cap marker parsed by the multi-reviewer loop and every command that accepts --review-with (/do:pr, /do:release, /do:review, /do:better, /do:better-swift, /do:depfree, /do:rpr, and /do:next via pass-through to /do:pr). <n> is a non-negative integer; 0 means "loop until clean", bounded by each loop's 10-iteration safety guardrail. The suffix is stripped into a per-entry {ENTRY_MAX} before slug/[model]/@login parsing, chains with ~opt in either order (ollama~opt~max=1ollama~max=1~opt), and is not part of the dedup identity (ollama~max=2 and ollama collapse; the first occurrence's cap wins). Like ~opt it is free of shell metacharacters, so a --review-with value stays inert wherever it lands in a command string.
  • {MAX_ITERATIONS} / {MAX_EXPLICIT} inputs on the local-agent and Ollama review loops, replacing their hardcoded MAX_ITERATIONS=3. The multi-reviewer loop resolves each entry's effective cap once — per-entry ~max=<n>--review-iterations (GitHub-side reviewers only, matching that flag's existing scope) → the loop's built-in default — so no inner loop re-implements the precedence.
  • capped status on the local-agent and Ollama loops, matching the copilot and @<login> loops. It means the reviewer spent an explicitly configured budget after applying every fix it surfaced, and is clean-equivalent for the merge gate.
  • Saved-default support. /do:config --review-with=claude~max=2,ollama~opt~max=1 validates the cap and stores both suffixes, re-appended in canonical order (~opt first, then ~max=<n>) so a stored value is byte-stable regardless of how it was typed. The markers ride through .slashdo.json / .slashdo-config.json untouched.
  • Aggregate report Iterations column ({rounds run}/{cap}, rendering for ~max=0) in the Multi-Reviewer Summary, so a capped row shows it stopped on the budget you set rather than running out of findings.

Changed

  • capped vs guardrail is now a distinction about who chose the ceiling. Reaching a user-configured cap (a ~max=<n>, or --review-iterations on a GitHub-side pass) yields capped — clean-equivalent, merge-eligible. Reaching a built-in ceiling (the local-agent / Ollama default of 3, or the 10-iteration guardrail in unlimited mode) still yields guardrail, which stays inconclusive and blocks the merge. Existing runs that never pass ~max are unaffected: their built-in caps behave exactly as before.
  • Ollama's coverage-gap invariant outranks capped. A partially-reviewed diff (REVIEW_ERRORS + TRUNCATED > 0) still reports incomplete, never capped, so a ~max can't turn an unreviewed diff into a merge-eligible pass.
  • ~max is ignored in --review-mode parallel (each reviewer runs exactly one review-only pass there, so there are no per-reviewer cycles to cap). The loop warns rather than aborting, matching how it already handles --reviewer-applies and the stop-mode flags in parallel mode.
  • The Unknown --review-with value abort message now notes each slug may be suffixed ~opt and/or ~max=<n>.

Full Changelog

Full Diff: v3.24.1...v3.25.0

atomantic and others added 12 commits July 23, 2026 19:31
gh/glab issue create prints the new issue's URL, not JSON — so appending
-q .number / --jq errors and can abort the create inside a $(…) capture. Add
the URL-parsing idiom (URL=$(gh issue create …); NUM=${URL##*/}) next to the
existing 'capture the issue numbers for the summary' instruction, plus a nudge
toward --body-file for multi-line bodies, so consumers (/do:plan-task,
/do:next, /do:replan) don't reach for an invalid -q flag.
docs(plan-issue-mode): show how to capture a created issue number (avoid invalid -q on gh issue create)
--review-iterations is global and only ever reached the copilot and
@<login> loops; the local agents and ollama had a hardcoded
MAX_ITERATIONS=3 with no way to move it. That made a slow local model
expensive to include in a review list, and made it impossible to budget
reviewers differently in one run.

A per-entry ~max=<n> suffix now caps that one reviewer's
review -> fix -> re-review cycles, so
--review-with claude~max=2,ollama~max=1,codex~max=3 gives each its own
budget. It chains with ~opt in either order, is not part of the dedup
identity (first occurrence's cap wins on collapse), and rides through
/do:config saved defaults.

This needed a second change to be usable: the local-agent and ollama
loops report `guardrail` on cap exhaustion, which is inconclusive and
blocks the merge gate -- so ~max=1 would have blocked nearly every
merge. All four loops now report `capped` (clean-equivalent) when the
cap was user-configured, and keep `guardrail` for a built-in ceiling.
The split is deliberate: a ceiling you chose is a budget, one you
didn't is an unfinished review. Runs that never pass ~max are
unaffected. Ollama's coverage-gap rule still outranks both -- a
partially-reviewed diff reports `incomplete`, never `capped`.

~max is ignored (with a warning) in --review-mode parallel, where each
reviewer runs a single review-only pass.
The ~max=<n> docs landed in #129 but didn't say the suffix only has
meaning in series mode. In parallel mode each reviewer runs a single
review-only pass and the orchestrator applies the union once, so
multi-reviewer-loop.md warns and ignores the cap -- a reader budgeting
reviewers with ~max in parallel mode would otherwise expect it to
apply.
…ewable

The new parse-error accounting added a `REVIEW_ERRORS + PARSE_ERRORS ==
REVIEWABLE` -> cli-error check without the `REVIEWABLE > 0` guard its
sibling total-failure check carries. A diff of nothing but pure
renames/mode changes skips every file as empty-diff, leaving REVIEWABLE=0
with zero errors, so 0 == 0 fired and the pass reported the hard-error
cli-error -- which short-circuits the multi-reviewer wrapper to `dirty`
and blocks the merge on a diff that simply had nothing to review.

Also clamp the Coverage numerator at 0: REVIEW_ERRORS/PARSE_ERRORS and
TRUNCATED can count the same file twice (truncation is decided before
the invocation), which could render a negative count.
Seven fixes from the claude review pass on the release diff, all in the
~max / fail-closed-parsing change:

- The strict verdict contract validated $LOG_FILE, but step 2 captured
  the reviewer with `> "$LOG_FILE" 2>&1` -- so any CLI startup banner,
  deprecation notice, or agy/grok progress line made a clean review parse
  as malformed. Split stderr into $ERR_FILE, as the Ollama loop already
  does, and point the cli-error diagnostics at it.
- An unparseable verdict reported cli-error, which is a hard error: it
  fires the wrapper's short-circuit (skipping every remaining reviewer on
  a branch that is actually fine) and is the one class ~opt explicitly
  does not excuse -- while ~opt's own docs name "no-verdict" as an
  inconclusive status it does excuse. Added `no-verdict` as an
  inconclusive status and threaded it through the wrapper's status set,
  stop-mode table, and inconclusive enumerations.
- Ollama's PARSE_ERRORS double-counted invocation-error files: the
  invocation writes a `===== FILE:` section for every file including
  failed ones, so an errored file's marker-only section was re-counted as
  a parse error. Sum could then exceed REVIEWABLE, leaving both the
  total-failure and partial branches unmatched. Count each file once and
  compare with >=.
- /do:rpr promised to forward {ENTRY_MAX} to the local-agent and Ollama
  loops but its dispatch bullets never listed it (and step 8 still said
  those loops have a fixed cap), so `--review-with claude~max=1` silently
  ran the built-in 3 rounds.
- pr.md, better.md, and better-swift.md still glossed `capped` as
  GitHub-side-only, so a codex/ollama pass that returned capped would be
  treated as not-clean and leave a merge-eligible PR open -- contradicting
  each command's own ~max bullet.
- The dedup tie-break was stated two incompatible ways ("first
  occurrence's cap wins" vs "first occurrence that carried a ~max"); for
  `ollama,ollama~max=1` those give cap 1 vs the built-in 3.
- Changelog was missing the fail-closed parsing change entirely and cited
  the pre-change coverage-gap formula.

Also added contract tests for no-verdict, the stderr split, the
REVIEWABLE > 0 guard, and the ~max threading.
… rules

Both statuses were reachable from an inner loop but stranded in the
wrapper's aggregate evaluation:

- `no-verdict` (added in the previous commit) was missing from the
  optional-inconclusive exclusion and from the aggregate `inconclusive`
  rule, so a `~opt` local reviewer returning it qualified for neither
  `clean` nor `partial` -- exactly the blocking the ~opt contract promises
  to prevent.
- `partial` accepted only `clean` passes. A `~max=1` reviewer that lands
  fixes returns `capped`, which is precisely what trips
  `--review-stop-on-findings` -- and since `clean` excludes
  stop-short-circuited runs, that combination matched NO rule at all and
  blocked a merge that both statuses document as eligible.

Also updated the per-command copies of the same rules (release.md's
inconclusive enumeration, better/better-swift's partial gloss) and added a
contract test pinning both.
…etry loop

The previous commit wired {MAX_ITERATIONS} into rpr's dispatch, which made
rpr's own retry loop the leak: each re-dispatch handed the inner loop a
fresh n, so `--review-with ollama~max=1` could run an unbounded number of
review-and-fix cycles. rpr now tracks rounds spent per entry across the
outer loop and stops re-dispatching an explicitly capped entry once the
budget is spent, forwarding the remaining budget rather than n. Entries on
a built-in cap or ~max=0 keep the historical worthiness-driven behavior.
…t loop

rpr accepts ~max on every slug but its Copilot path is a hand-rolled
request/poll loop, not a dispatch into lib/copilot-review-loop.md, so
nothing enforced the budget there -- and rpr accepts no
--review-iterations, making ~max the only cap available. copilot~max=1 was
therefore accepted and silently ignored. The step-8 cap accounting now
covers every reviewer type explicitly, and an uncapped copilot entry is
documented as worthiness-governed (unchanged from before this release).
@atomantic
atomantic merged commit ef1c807 into release Jul 27, 2026
4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant