Context
We drive roborev from automated agents as a merge gate — a review must be confirmed clean before a PR
is allowed to land. That use case makes us unusually sensitive to one failure mode: roborev returning a
plausible-looking clean verdict when it did not actually review the requested content. A vacuous
No issues found. is textually identical to a genuine clean pass, so an automated consumer cannot tell them
apart without out-of-band evidence.
This is not hypothetical for us. On one of our changes, two runs reported "No issues found"; re-run correctly
against the right commit, the same diff produced two genuine blocking findings. Accepting the first
verdict would have merged unreviewed code.
We ended up building a defensive wrapper that verifies roborev's output against independently-computed facts.
In doing so we found the following. Everything in §1 I reproduced directly on v0.61.2; §2 is honestly
flagged as older evidence I have not re-verified; §3 is a doc/UX note, not a bug.
Happy to split this into separate issues if you'd prefer — each section is independently actionable. Also
happy to test patches; we exercise this heavily.
Environment: roborev v0.61.2 (static release), Linux x86_64, --agent codex --model gpt-5.6-sol,
daemon healthy, 4 workers. Clean database (roborev repo list was empty at session start), so the job ids
below are a fresh 1 and 2.
1. Confirmed on v0.61.2
1a. --wait returns before the job record is durable
roborev review <sha> --wait returns, but the job record is not yet readable. Immediately after the
command exited, roborev list --json for job 2 had no git_ref, no status, no model, and no
token_usage. Queried again moments later, all four were populated:
id=2 status='done' git_ref='155e12c8e8d1af9f75e47ca854e87f489b818fe6' model='gpt-5.6-sol' token_usage=<present>
Repro: run roborev review <sha> --repo <abs> --agent codex --model gpt-5.6-sol --wait, then immediately
roborev list --json (or roborev show <job> --json) in the same shell. Re-query a few seconds later.
Impact: a consumer that reads the record right after --wait — the natural thing to do — silently gets a
degraded view. In our case four independent verification signals fell back to weaker sources simultaneously,
with no error and no indication anything was missing. We now poll with a bounded retry, but ideally --wait
would not return until the record it produced is readable (or would expose an explicit "record durable"
signal).
1b. token_usage is a JSON-encoded string nested inside JSON
"token_usage": "{\"input_tokens\":67387,\"cached_input_tokens\":43520,\"total_output_tokens\":2232,\"usage_source\":\"job_log_turn_completed\",...}"
It's a string field whose contents are JSON, so every consumer must decode twice:
json.loads(json.loads(record)["token_usage"]).
Impact — this one cost us a real, silent defect. Our first implementation parsed one level and read the
field names we'd inferred from the binary's struct tags. Result: our token-based check reported
UNAVAILABLE on every single run — a verification step that appeared to exist but never once executed.
We only caught it by noticing the field was never populated on a real review. Emitting token_usage as a
nested object would remove this whole class of consumer error.
1c. Asymmetric token field naming
Input is input_tokens and cached_input_tokens, but output is total_output_tokens. Minor on its own,
but it's the specific inconsistency that made 1b's silent failure easy to write and hard to spot — we
guessed output_tokens and got a plausible-looking "no data" result rather than an error.
1d. roborev repo has no add subcommand, so a git worktree cannot be registered
Available subcommands are list, show, rename, move, delete, merge. Registration only happens
implicitly on first use.
We use git worktree extensively (one worktree per in-flight change), and an unregistered worktree appears
to be the root cause of the --branch misresolution in §2a below: with no registered repo matching the cwd,
--branch has no correct repo to resolve against. A roborev repo add <path> would make the worktree case
expressible, and would also let a consumer verify registration rather than hoping first-use did the right
thing.
2. Older evidence, NOT re-verified on v0.61.2
Flagging the verification gap rather than presenting these as current facts — they may already be fixed. I
can re-test and follow up if useful.
2a. --branch from inside a git worktree resolves against the ROOT checkout and reviews the BASE commit
Observed enqueueing 39900e4db (= origin/main, the base) when the worktree branch HEAD was 4e7ab591e.
Five consecutive jobs all enqueued the base commit. The reviewer then receives an empty diff and replies
No issues found. Summary: The provided combined diff contains no code changes to review.
Likely narrower framing: this may be entirely about the absence of an explicit --repo. If --branch
resolves correctly when given --repo <abs-worktree>, then the precise bug is "--branch silently resolves
against a different repo when the cwd is an unregistered worktree" — which would be both clearer and more
tractable. Either way, silently resolving to a different commit than the user asked for seems worth an
error rather than a review.
2b. The two-positional commit-range form enqueued a commit that is neither endpoint
roborev review 89fdbb895 989d7d2c3 enqueued 90a17d376 — neither the start nor the end of the range.
2c. A code-free (docs-only) diff is silently discarded on a correctly-targeted run
roborev review <sha> --repo <abs> --agent codex --model gpt-5.6-sol --wait on a 5-file, +167/−63,
all-markdown diff: correct SHA enqueued, correct repo, and yet
No issues found. Summary: The provided diff contains no code changes to review. Reproducible across two
runs.
Token accounting was the only way to tell: 18,700 input / 0 cached / 53 output / 8s, versus 398k–649k
input with 314k–554k cached and 5.0k–6.3k output over ~2.5 minutes for genuine reviews of comparable diffs.
(A known-empty diff measured 17,333 input / 21 output — i.e. the docs-only run sat right on the empty-diff
baseline.)
This is the most consequential one, because it passes an enqueued-SHA check — right SHA, right repo,
plausible clean verdict — so verifying the reviewed commit cannot catch it. If a code-free diff is
deliberately out of scope, an explicit non-zero refusal would be enormously better than a verdict that is
byte-identical to a clean pass.
3. Doc/UX note (not a bug)
3a. roborev review <sha> reviews one commit, which is easy to misread as "the branch"
Confirmed on v0.61.2: commit 155e12c touches 3 files, while the branch's diff against its base is 27
files / +3603/−74. Only the single commit's diff reached the reviewer (confirmed via the prompt length and
content).
This is presumably intended semantics. But an automated caller told to "review this branch" that reaches for
the single-SHA form gets a partial review reported as a complete one — for any multi-commit branch,
"clean" silently means "the last commit was clean." A line in review --help distinguishing the single-commit
and branch-range forms, and/or echoing the reviewed file count in the output, would make this
self-evident. Echoing the file count would incidentally make 2c self-diagnosing too.
The one change that would matter most
The unifying theme across 1a, 2a, 2b and 2c is that each fails by producing a plausible success rather than
an error:
When roborev does not actually review the requested content — wrong repo, wrong or partial range,
unsupported/code-free diff, or a record that isn't readable yet — it would be far safer to fail loudly and
non-zero than to return a clean verdict.
For interactive use a vacuous "No issues found." is a minor annoyance. For anything gating a merge, it's
indistinguishable from success, and that's the difference between a review tool and a review guarantee.
Thanks for roborev — it's genuinely useful, and the findings it produces when correctly targeted have caught
real bugs for us. These reports are all in service of trusting it more, not less.
Context
We drive
roborevfrom automated agents as a merge gate — a review must be confirmed clean before a PRis allowed to land. That use case makes us unusually sensitive to one failure mode: roborev returning a
plausible-looking clean verdict when it did not actually review the requested content. A vacuous
No issues found.is textually identical to a genuine clean pass, so an automated consumer cannot tell themapart without out-of-band evidence.
This is not hypothetical for us. On one of our changes, two runs reported "No issues found"; re-run correctly
against the right commit, the same diff produced two genuine blocking findings. Accepting the first
verdict would have merged unreviewed code.
We ended up building a defensive wrapper that verifies roborev's output against independently-computed facts.
In doing so we found the following. Everything in §1 I reproduced directly on v0.61.2; §2 is honestly
flagged as older evidence I have not re-verified; §3 is a doc/UX note, not a bug.
Happy to split this into separate issues if you'd prefer — each section is independently actionable. Also
happy to test patches; we exercise this heavily.
Environment: roborev v0.61.2 (static release), Linux x86_64,
--agent codex --model gpt-5.6-sol,daemon healthy, 4 workers. Clean database (
roborev repo listwas empty at session start), so the job idsbelow are a fresh 1 and 2.
1. Confirmed on v0.61.2
1a.
--waitreturns before the job record is durableroborev review <sha> --waitreturns, but the job record is not yet readable. Immediately after thecommand exited,
roborev list --jsonfor job 2 had nogit_ref, nostatus, nomodel, and notoken_usage. Queried again moments later, all four were populated:Repro: run
roborev review <sha> --repo <abs> --agent codex --model gpt-5.6-sol --wait, then immediatelyroborev list --json(orroborev show <job> --json) in the same shell. Re-query a few seconds later.Impact: a consumer that reads the record right after
--wait— the natural thing to do — silently gets adegraded view. In our case four independent verification signals fell back to weaker sources simultaneously,
with no error and no indication anything was missing. We now poll with a bounded retry, but ideally
--waitwould not return until the record it produced is readable (or would expose an explicit "record durable"
signal).
1b.
token_usageis a JSON-encoded string nested inside JSONIt's a string field whose contents are JSON, so every consumer must decode twice:
json.loads(json.loads(record)["token_usage"]).Impact — this one cost us a real, silent defect. Our first implementation parsed one level and read the
field names we'd inferred from the binary's struct tags. Result: our token-based check reported
UNAVAILABLEon every single run — a verification step that appeared to exist but never once executed.We only caught it by noticing the field was never populated on a real review. Emitting
token_usageas anested object would remove this whole class of consumer error.
1c. Asymmetric token field naming
Input is
input_tokensandcached_input_tokens, but output istotal_output_tokens. Minor on its own,but it's the specific inconsistency that made 1b's silent failure easy to write and hard to spot — we
guessed
output_tokensand got a plausible-looking "no data" result rather than an error.1d.
roborev repohas noaddsubcommand, so a git worktree cannot be registeredAvailable subcommands are
list,show,rename,move,delete,merge. Registration only happensimplicitly on first use.
We use
git worktreeextensively (one worktree per in-flight change), and an unregistered worktree appearsto be the root cause of the
--branchmisresolution in §2a below: with no registered repo matching the cwd,--branchhas no correct repo to resolve against. Aroborev repo add <path>would make the worktree caseexpressible, and would also let a consumer verify registration rather than hoping first-use did the right
thing.
2. Older evidence, NOT re-verified on v0.61.2
Flagging the verification gap rather than presenting these as current facts — they may already be fixed. I
can re-test and follow up if useful.
2a.
--branchfrom inside a git worktree resolves against the ROOT checkout and reviews the BASE commitObserved enqueueing
39900e4db(=origin/main, the base) when the worktree branch HEAD was4e7ab591e.Five consecutive jobs all enqueued the base commit. The reviewer then receives an empty diff and replies
No issues found. Summary: The provided combined diff contains no code changes to review.Likely narrower framing: this may be entirely about the absence of an explicit
--repo. If--branchresolves correctly when given
--repo <abs-worktree>, then the precise bug is "--branchsilently resolvesagainst a different repo when the cwd is an unregistered worktree" — which would be both clearer and more
tractable. Either way, silently resolving to a different commit than the user asked for seems worth an
error rather than a review.
2b. The two-positional commit-range form enqueued a commit that is neither endpoint
roborev review 89fdbb895 989d7d2c3enqueued90a17d376— neither the start nor the end of the range.2c. A code-free (docs-only) diff is silently discarded on a correctly-targeted run
roborev review <sha> --repo <abs> --agent codex --model gpt-5.6-sol --waiton a 5-file, +167/−63,all-markdown diff: correct SHA enqueued, correct repo, and yet
No issues found. Summary: The provided diff contains no code changes to review.Reproducible across tworuns.
Token accounting was the only way to tell: 18,700 input / 0 cached / 53 output / 8s, versus 398k–649k
input with 314k–554k cached and 5.0k–6.3k output over ~2.5 minutes for genuine reviews of comparable diffs.
(A known-empty diff measured 17,333 input / 21 output — i.e. the docs-only run sat right on the empty-diff
baseline.)
This is the most consequential one, because it passes an enqueued-SHA check — right SHA, right repo,
plausible clean verdict — so verifying the reviewed commit cannot catch it. If a code-free diff is
deliberately out of scope, an explicit non-zero refusal would be enormously better than a verdict that is
byte-identical to a clean pass.
3. Doc/UX note (not a bug)
3a.
roborev review <sha>reviews one commit, which is easy to misread as "the branch"Confirmed on v0.61.2: commit
155e12ctouches 3 files, while the branch's diff against its base is 27files / +3603/−74. Only the single commit's diff reached the reviewer (confirmed via the prompt length and
content).
This is presumably intended semantics. But an automated caller told to "review this branch" that reaches for
the single-SHA form gets a partial review reported as a complete one — for any multi-commit branch,
"clean" silently means "the last commit was clean." A line in
review --helpdistinguishing the single-commitand branch-range forms, and/or echoing the reviewed file count in the output, would make this
self-evident. Echoing the file count would incidentally make 2c self-diagnosing too.
The one change that would matter most
The unifying theme across 1a, 2a, 2b and 2c is that each fails by producing a plausible success rather than
an error:
For interactive use a vacuous "No issues found." is a minor annoyance. For anything gating a merge, it's
indistinguishable from success, and that's the difference between a review tool and a review guarantee.
Thanks for roborev — it's genuinely useful, and the findings it produces when correctly targeted have caught
real bugs for us. These reports are all in service of trusting it more, not less.