Fix #20, #25, #35, #43, #44: consult and porch stop approving what nobody read - #49
Open
pseudoseed wants to merge 1 commit into
Open
Fix #20, #25, #35, #43, #44: consult and porch stop approving what nobody read#49pseudoseed wants to merge 1 commit into
pseudoseed wants to merge 1 commit into
Conversation
…body read Five issues, one class: a system that could not tell, and said something else. #35 A 0-byte PR diff produced a prompt saying `Changed Files (0)`, and three lanes returned APPROVE (HIGH) on nothing. The forge config had failed to resolve, `gh` ran against a Forgejo host, and the empty result reached the reviewers as though it were the change. buildPRQuery now refuses a 0-byte diff and names the three things it could be, because a reviewer cannot tell an empty diff from a failed fetch and neither can the human reading three approvals. #44 The opencode lane auto-rejects reads outside its working directory, and the consult sandbox is an mkdtemp dir the `agy` lane reaches via --add-dir. opencode got no equivalent grant, so it silently reviewed the working tree instead of the PR diff -- and above CLI_PROMPT_INLINE_MAX_CHARS, where the ENTIRE PROMPT is written to that dir, it held nothing but an unreadable path and still produced a verdict. That is the exact failure the lane's own header says it hard-fails to prevent; every guard caught a process that failed, none caught one that exited 0 with a verdict formed from nothing. Both artifacts now go through `opencode run -f`, which attaches content rather than negotiating with the permission system. #43 A bare `--type pr` failed by naming codev/consult-types/pr-review.md -- a path that has never shipped. Five of the six review types live only under protocols/<name>/, so that message asks the reader to create a file when the fix is --protocol. It now lists the protocols that actually provide the template, and falls back to the plain not-found error when it cannot look, so a guess never replaces one wrong remedy with another. #25 The agy skip artifact ended with "install the CLI and sign in" whatever went wrong. For a quota wall that is two wrong instructions at once: the CLI is installed, and signing in does not refill a quota. The remedy is now chosen from the failure, and an unrecognised cause gets agy's raw output instead of an invented fix. #20 was the subtle one. The skip artifact is WELL-FORMED -- it writes a real `VERDICT: COMMENT` -- so checking for a missing verdict does not detect it, and COMMENT counts toward unanimity. My first attempt used findVerdict and was wrong; an existing test caught it by showing "3 of 3 lanes reviewed and approved" for a run with a skipped lane. A lane that did not review has to declare it, so the artifact now carries LANE_DID_NOT_REVIEW and porch reads it. Blocking behaviour is deliberately unchanged: a skipped lane still does not wedge a project. What changed is that porch no longer prints "All reviewers approved!" over a run one reviewer never looked at -- the sentence a human reads immediately before approving a gate. Two existing tests asserted the old strings and were updated with the reason. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #20, closes #25, closes #35, closes #43, closes #44.
Five issues filed separately over two days. They are one class: a system that could not tell, and said something else. Fixed together because they compound — #35 feeds an empty diff to a reviewer, #44 feeds it no diff at all, and #20 counts the resulting silence as approval.
#35 — three APPROVEs on a 0-byte diff
On a Forgejo-hosted repo the forge config failed to resolve,
ghran against a host it could not reach, and the diff came back empty with nothing on stderr. The prompt saidChanged Files (0). Three lanes returned APPROVE (HIGH).buildPRQuerynow refuses a 0-byte diff and names the three things it could be. There is no legitimate caller: an empty PR is not reviewable, and a genuinely empty diff is indistinguishable from a fetch that failed silently — so both stop.#44 — the opencode lane reviewing with no diff, and no prompt
opencode auto-rejects reads outside its working directory. The consult sandbox is an
mkdtempdir theagylane reaches through--add-dir; opencode got no equivalent grant. Observed live:Two artifacts land in that dir. The PR diff — so an opencode PR review silently read the working tree instead of the PR's head→base changes. And, above
CLI_PROMPT_INLINE_MAX_CHARS(100k), the entire prompt: the lane then held nothing but an instruction pointing at an unreadable path, and still produced output and a verdict.That is precisely what this lane's own header says it hard-fails to prevent:
Every one of those guards catches a process that failed. None catch a process that exits 0 with a confident verdict formed from nothing.
Both artifacts now go through
opencode run -f, which attaches content rather than negotiating with the permission system.extractSandboxPathsreads back the paths the prompt actually names, rather than re-deriving them — a second source of truth would drift from the first.#43 — an error naming a file that has never shipped
A bare
--type prfailed withPrompt template not found: codev/consult-types/pr-review.md. That path has never existed in any release; five of the six review types live only underprotocols/<name>/consult-types/. The message reads as "create this file". The fix is--protocol, and nothing said so.It now lists the protocols that actually provide the template, reusing
protocolDirs()so it sees the same four tiers the resolver does. When it cannot look, it falls back to the plain not-found error — a guess here would replace one wrong remedy with another.#25 — the same remedy regardless of cause
The agy skip artifact ended with "install the CLI (https://…) and run
agyonce to sign in" whatever went wrong. For a quota wall that is two wrong instructions at once: the CLI is installed, and signing in does not refill a quota.agyRemedynow picks from the failure — missing CLI, quota/rate limit, auth, timeout — and returns nothing for an unrecognised cause, where the caller shows agy's raw output instead. A guessed remedy costs more than no remedy, because the reader acts on it.#20 — and the mistake I made fixing it
The blocking behaviour is deliberately unchanged. A lane that is unauthenticated or quota-exhausted must not wedge a project; that was the explicit call. What was wrong was the record.
My first attempt used
findVerdict— "did the reviewer state a verdict?" — and it was wrong. An existing test caught it by printing3 of 3 lanes reviewed and approvedfor a run with a skipped lane. The skip artifact is well-formed:agySkipContentwrites a realVERDICT: COMMENT. A missing verdict cannot detect it.So the lane has to declare it. The artifact now carries
LANE_DID_NOT_REVIEW: trueandlaneReviewed()reads it — a contract between codev's own skip writers and its parser, not an inference from prose.The gate message changes from:
to:
That first line is what a human reads immediately before approving a gate.
statedis optional onReviewResult: reviews in existingstatus.yamlfiles predate the field, and absent provenance must not retroactively accuse them.Tests
10 for #20, 10 for #25/#43. Two existing tests asserted the old strings and were updated with the reason recorded inline — one of them is the test that caught my wrong first fix, so it now pins the correct behavior instead.
src/commands/porch+ new consult tests: 534 passed.src/agent-farm+consult+doctor: 3361 passed, 34 skipped.One flake seen once under full-suite load:
renders a realistic large (~4MB) ring WHOLE within a CI-aware budget. It passes in isolation both on a clean tree and with these changes, so it is load-sensitive rather than a regression here.🤖 Generated with Claude Code