feat(review): escalating effort ladder -- reviewer flat->max, worker climbs (Closes #308) #312
No reviewers
Labels
No labels
Agent
Compat/Breaking
Kind/Bug
Kind/Documentation
Kind/Enhancement
Kind/Feature
Kind/Security
Kind/Testing
Priority
Critical
Priority
High
Priority
Low
Priority
Medium
Reviewed
Confirmed
Reviewed
Duplicate
Reviewed
Invalid
Reviewed
Won't Fix
Status
Abandoned
Status
Blocked
Status
Need More Info
No milestone
No assignees
2 participants
Notifications
Total time spent: 7 minutes 53 seconds
Due date
igor
7 minutes 53 seconds
No due date set.
Dependencies
No dependencies set
Reference
joshtronic/igor!312
Loading…
Reference in a new issue
No description provided.
Delete branch "agent/308-review-effort-ladder"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
What this does
Implements the RFC (#308): reasoning effort now escalates through the review + rework flow. The harness set no effort before; the model stays Opus, escalation is pure effort.
Reviewer axis (the "final boss")
reviewer_effort(rework_rounds): flathighduring the loop -- a stable bar the worker can converge on (a reviewer that got pickier every round would move the goalposts and the PR would never land) -- thenmaxfor the last review before it escalates to the human (rounds >= 3). Rare, and the alternative is your time, so max is the cheap bet.Worker axis
worker_effort(rework_rounds): the bot`s PR rework climbs each round -- high -> xhigh -> max -- trying harder as the problem proves hard.Plumbing
claude_calllearns an optionalmodel:effortsuffix (claude-opus-4-8:high->--effort high). Model ids carry no colon, so every existing bare-model caller is unchanged. The reworkclaude_run_with_costpasses--effortdirectly.Audit-trail seed (for #310)
The shadow-review comment now records
(effort: <level>)-- the first thread of the per-ticket audit trail #310 will build on. This PR is the one we dogfood #310 through.Safety
claude -p --effortis accepted (not just interactive) and a realclaude_callwith amodel:effortmodel returned cleanly -- so the critical review path (which gates every merge) is proven before wiring.reviewer_effort/worker_effortare hardcoded thresholds (opinionated, not knobs). Bare-model callers unaffected.check-syncgreen,bash -nclean.Test plan
claude -p --effort lowreturns a clean result (no unknown-option error)claude_call "claude-opus-4-8:low" ...->ok(full path works)reviewer_effort: 0/1/2 -> high, 3+ -> max ;worker_effort: 0/1 -> high, 2 -> xhigh, 3+ -> maxbin/check-sync.shgreenCloses #308.
Wire reasoning effort into the review + rework flow (the harness set none before). Verdict model stays Opus; escalation is pure effort, per the RFC: - claude_call learns an optional `model:effort` suffix (e.g. "claude-opus-4-8:high") -> `--effort`. Model ids carry no colon, so a bare model is unchanged. - Reviewer effort is FLAT ("high") during the rework loop -- a stable bar the worker can converge on -- then "max" for the final look before the reviewer escalates to the human (the "final boss": rare, and the alternative is Josh's time). - Worker rework effort CLIMBS each round: high -> xhigh -> max. Try harder as the problem proves hard. - The review comment now records the effort used (seed for the #310 audit trail we dogfood next). Verified `claude -p --effort` is accepted and a real claude_call with a `model:effort` model returns cleanly, so the critical review path is safe. reviewer_effort / worker_effort are hardcoded thresholds -- opinionated, not knobs. Closes #308. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011KXPafSYJPY6XkWHHk1Lfs🤖 Review —
REQUEST_CHANGES(automated)CI for
288333d4: successSummary: Adds an escalating reasoning-effort ladder — reviewer flat
high→max, workerhigh→xhigh→max— via a newmodel:effortsuffix inclaude_calland a direct--efforton the rework path. Small, focused (~60 lines), in scope, no CI-config touches, no security concerns. The code and the description's threshold claims match the diff. One concrete gap blocks it.Blocking
The effort tokens actually shipped were never verified to be accepted values. The test plan proves only
claude -p --effort lowandclaude_call "...:low"— butlowis never used in production. The values that are deployed arehigh(every normal shadow review),xhigh(worker rework round 2), andmax(final review + rework round ≥3). None of these three were verified. If the CLI validates--effortagainst an enum and any of these tokens is rejected:highfailing breaks every shadow review (bin/tick.sh~L2632,${AGENT_MODEL_REVIEW}:${rev_effort}) — i.e. the merge gate silently stops producing reviews after both retry attempts fail.xhighfailing breaks worker rework at round 2 (bin/tick.shL3361,--effort "$PR_REWORK_EFFORT").maxfailing breaks the final escalation review.Testing
lowproves the flag parses, not that the tokens you ship are valid — and choosinglowfor the test while deployinghigh/xhigh/maxis exactly the mismatch worth closing. CI (check-sync+bash -n) does not exercise a liveclaudecall, sosuccessdoesn't cover this. Fix: run each of--effort high,--effort xhigh,--effort maxonce and confirm a clean result (no unknown-value error), and add them to the test plan. Cheap to do; if they all pass this is a one-line re-check.Non-blocking nits
bin/tick.shL3359–L3360:review_rework_rounds "$REVIEW_KEY"is computed three times (once forPR_REWORK_EFFORT, twice in the log line). Harmless but worth caching in a local, since the round can in principle move between calls.Notes (looks correct)
claude.shcolon-split (${model##*:}/${model%:*}) is unambiguous given colon-free model ids; thecase *:*guard leaves all bare-model callers untouched. Good.reviewer_effort(≥3→max, elsehigh) andworker_effort(0|1→high, 2→xhigh, *→max) match the described thresholds exactly.(effort: ${rev_effort})addition to the review comment is a benign one-liner.Once the three deployed effort tokens are confirmed accepted, I'd have no further reservations.
Independent review by the harness on
claude-opus-4-8. The human reviewer is requested once Igor has reviewed; a human still merges.🤖 Review —
COMMENT(automated)CI for
bea4d132: successSmall, well-scoped change: adds two pure effort-ladder helpers (
reviewer_effort,worker_effort), teachesclaude_callan optionalmodel:effortsuffix, and threads effort into the shadow review + PR-rework calls. Logic reads correctly and the checklist matches the code. CI is green. A few things I'd want a human to weigh before merge, hence COMMENT rather than APPROVE.Verified against the diff (positive)
reviewer_effort→highfor rounds 0/1/2,maxfor ≥3 (tick.sh:1013);worker_effort→high(0/1),xhigh(2),max(≥3) (tick.sh:1024). Checklist item is honest.model:effortsplit is unambiguous:${model%:*}/${model##*:}handles a single colon correctly; bare model (no colon) falls through thecaseuntouched, so the "bare callers unaffected" claim holds structurally (claude.sh:283).Things to weigh
set -u(claude.sh:288)."${effort_args[@]}"when the array is empty (the bare-model path — i.e. every other caller ofclaude_call) errors with "unbound variable" on bash < 4.4 (notably macOS's default 3.2). The:-defaults sprinkled through the new code suggestset -umay be active. On modern Linux bash (4.4+/5.x) this is a non-issue, and the author's manual verification exercised the effort path — but the empty-array path (the critical bare-model review/other calls) is the one that would break, and neitherbash -nnorcheck-synccatches a runtime unbound-variable error. Worth a one-line confirmation of the runtime bash version, or defensively guard with${effort_args[@]+"${effort_args[@]}"}.reviewer_effort/worker_effortare trivially unit-testable pure functions, but the contract's "add/adjust tests" is satisfied only by manual test-plan bullets here. If the repo has a bash test suite, these belong in it; if it doesn't, that's understandable but worth stating.claude -p --effortaccepted (not just interactive)" and the livemodel:effortcall returningokcan't be confirmed from the diff — CI green is consistent but doesn't exercise a realclaudeinvocation. Also, the reviewer-maxes-at-round-3 design depends onreview_rework_roundsand the REQUEST_CHANGES/escalation handler, neither of which is in the diff; the shown logic is internally consistent but I can't confirm the review at round ≥3 actually fires before escalation.None of these are hard blockers, but the empty-array edge case on the bare-model path is the one I'd want eyes on before merge, since it touches the merge-gating review path for all existing callers.
Independent review by the harness on
claude-opus-4-8. The human reviewer is requested once Igor has reviewed; a human still merges.