feat(tools): agent-callable verify/critique tool (#4196)#4199
Conversation
Add `verify`, a tool the agent can CHOOSE to call to run an adversarial self-review of its own recent work before claiming a non-trivial change done. It spends extra test-time compute on the model's own judgment: the agent states a claim plus optional scope (recent git diff / staged diff / named files / the requirement), and an independent critic runs at elevated reasoning (default Max, independent of the session tier) tasked to REFUTE it, returning structured findings (issue, severity, evidence, suggested fix) plus a verdict and an unresolved-risk flag. Design: - Critic mechanism: a single-shot adversarial model call (mirrors the `review` tool) with reasoning_effort set explicitly, so elevated reasoning — the test-time-compute lever — never inherits a low tier. - Bounded / no runaway (hard requirement): the critic request carries `tools: None`, so the critic literally cannot invoke `verify` (or any tool) — recursion is impossible by construction rather than by a denylist. A task-local re-entry guard adds defense in depth. - Fail-safe parsing: unstructured or "upheld-but-has-serious-findings" critic output is treated as unresolved risk, guarding the green-CI-but-wrong trap. - Disjoint from subagent/mod.rs (parallel #4193 change) — calls no sub-agent internals; evidence is gathered deterministically by the tool. - Opt-out: `Feature::Verify` (`[features] verify_tool`, default on) gates registration in the agent runtime surface. Tests: tool contract (name/schema/registered/model-visible), a critic-finds-a-planted-bug test via MockLlmClient (also asserting the outgoing request is elevated + toolless), the recursion re-entry guard, fail-safe verdict normalization, and the feature-gated registration.
|
Claude finished @Hmbown's task in 3m 30s —— View job Review:
|
) Address two correctness gaps from review of PR #4199 (design-agnostic; the direct-call-vs-sub-agent decision is unchanged, still pending maintainer review). (1) normalize() only forced unresolved_risk on critical/high findings, so verdict=upheld + a MEDIUM finding + critic-set unresolved_risk=false reported "no unresolved risk" — the exact green-but-wrong case this tool exists to catch. Now any finding at MEDIUM severity or above forces unresolved_risk=true and forbids an `upheld` verdict (downgraded to `uncertain`; critical/high still downgrade to `refuted`). `low` nits remain exempt so they don't block a claim. (2) gather_git_diff() built `git diff {base}...HEAD`, which captures branch commits but OMITS the uncommitted working-tree changes the agent usually wants to verify before claiming done. Replaced with gather_diff_evidence(): for the working-tree scope with a base it now emits BOTH the committed-since-base diff (`git diff base...HEAD`) AND the uncommitted diff (`git diff HEAD`, with a plain-worktree fallback on an unborn HEAD), as two labelled evidence blocks. Tests: - upheld_with_medium_finding_flags_unresolved_risk: medium finding => unresolved_risk true and verdict uncertain (not upheld). - upheld_with_only_low_finding_stays_upheld: low-only nit stays upheld, no unresolved risk (documents the carve-out). - diff_scope_with_base_includes_uncommitted_worktree_changes: real dirty repo + base ref => evidence contains both the committed-since-base and the uncommitted marker, in two distinct labelled blocks.
|
Claude finished @Hmbown's task in 59s —— View job Re-review after push (8666e4c)
New commit 8666e4c ("verify — flag medium findings + include worktree diff") addresses two correctness gaps and is a clean improvement:
This also fixes my prior finding #1 (staged+base invalid git invocation): the staged branch now runs Still open from the original review (not touched by this commit, still worth addressing before merge):
Not blocking, unchanged from before: Net: the pushed fix is correct and well-tested for what it targets. Recommend addressing #2/#3 (small, low-risk) before merge, but neither blocks on correctness grounds. |
Approved TTC design: one shared CriticEngine behind three triggers — the agent-invoked verify tool (Hmbown#4196, MVP Hmbown#4199), advisor watcher (Hmbown#3982), and post-turn verification gates (Hmbown#4013) — plus clamp->floor sub-agent reasoning (Hmbown#4137). Synthesized from three independent reviews (verify-tool contributor, GLM 5.2, internal analysis). Design only, no code; v0.8.69, behind stopship. Drafted with agent assistance.
Fixes #4196
What
Adds
verify— a tool the agent can choose to call to run an adversarial self-review of its own recent work before claiming a non-trivial change done. It spends extra test-time compute on the model's own judgment (elevated reasoning + an independent critic), on demand, not as an always-on watcher.The agent states a claim plus optional scope (recent git diff / staged diff / named
files/ the originalrequirement/ afocusrisk). An independent critic then runs at elevated reasoning (defaultMax, independent of the session tier), tasked to REFUTE the claim, and returns structured findings.Design (for maintainer review before merge)
verify(distinct fromreview= code review of a target, andrun_verifiers= external test/build gates).claim(required); optionalrequirement,scope(diff|staged|none),base,files[],focus.reviewtool) withreasoning_effortset explicitly on the outgoing request, so the test-time-compute lever never inherits a Low session tier. The tool gathers evidence deterministically (git diff by scope + named file contents) and hands it to the critic — it does not touchsubagent/mod.rs(parallel fix(fleet): interactive TUI in-process spawn ignores profile provider pin (#4093 TUI follow-up) #4193), keeping the change additive and disjoint.{ verdict: refuted|upheld|uncertain, summary, findings: [{severity, issue, evidence, suggested_fix}], unresolved_risk }+ usage metadata.Bounded / no runaway (hard requirement)
tools: None, so the critic literally cannot invokeverify(or any tool) — recursion is impossible by construction, not by a denylist that could be forgotten.verifyrefuse if entered while a critique is already in progress.Opt-out
Feature::Verify([features] verify_tool, default on) gates registration in the agent runtime surface; cost is only incurred when the agent chooses to call it.Tests
MockLlmClient(also asserts the outgoing request is elevated + toolless, and threads the claim/requirement/evidence).Verification gate
cargo fmt --all --check— cleancargo clippy --workspace --all-features --locked -D warnings …— cleancargo test --workspace --locked— 6004 passed; only the 2 known pre-existing unrelated failures (git_repo_root_reports_attempted_paths_when_no_repo_found,skill_hotbar_action_activates_skill_through_dollar_alias), confirmed failing identically on pristineorigin/main.cargo build --release -p codewhale-tui— successNote
Do not merge yet — this is a new product capability; the DESIGN should be reviewed with the maintainer first. A follow-up could swap the critic mechanism to a spawned sub-agent (autonomous exploration) behind the same tool contract once #4193 settles; the recursion guard would then also need to exclude
verifyfrom that sub-agent's tool allowlist.