review_now/dispatch report "✓ verdict posted" when the reviewer finished WITHOUT posting one nf-8c6 ← Beads

open priority 2 task unassigned

Twinned from https://github.com/cfsh/ninefold/issues/1048 by tools/beads/import_github.py's reconcile pass.

Seen live on PR #1018 (2026-08-17, log /root/.ninefold-reviewer/logs/pr-1018.20260817-130952.log):

The reviewer session completed its review (drafted CONVERGED at head ecc5096) but every attempt to run the #1032 wrapper — python3 tools/reviewer/post_verdict.py 1018 <<'…', and even … --help — was refused with "This command requires approval", despite dispatch.py passing --allowedTools "Bash(python3 tools/reviewer/post_verdict.py:*)" (verified present in the synced clone at 338fb09 at spawn time). The session ended by *asking its non-existent operator* for approval, exited 0, and:

Two independent problems:

  1. The success signal is a lie since #1032. Before the wrapper, a reviewer that finished had nothing left to fail at; now posting is a separate, deniable step, so "the spawn exited 0" no longer implies "a verdict landed". conclusion()'s own docstring says ok means "a current verdict exists NOW" — the cheap honest implementation is to verify exactly that: after #N: done, read the PR's newest reviewer verdict and compare its sha to the head that was just reviewed; report the mismatch loudly (with the log path) instead of "✓ verdict posted". dispatch.py could equally self-check before printing done.
  1. The permission denial itself is unexplained. Probes from the same clone, the same recreated-worktree cwd, and the full real flag set (--allowedTools/--disallowedTools verbatim, claude 2.1.233) all get the wrapper call ALLOWED — the denial did not reproduce. So either something transient, or some difference in the real spawn (model/effort/prompt-scale?) affects permission evaluation. If it recurs, the fallback worth considering is pre-approving the wrapper in the repo's checked-in .claude/settings.json permissions (safe: authority.newest_verdict filters by the bot author, so a dev session running the wrapper cannot mint a counted verdict) — but that's .claude/*, i.e. a governance change for a human to take.

Cost when it fires: a full review pass (~12 min, ~$5) produces no verdict, the check stays red at the head, and the session either re-buys the pass or misreads "✓ verdict posted" and waits on a verdict that never arrives.

Dependencies

None.

Comments

No comments.

Add a comment