Let the criteria review read the repo outside the diff - #264
Conversation
PR #263 failed "the env YAML is gitignored" on three runs even though the root .gitignore's `.env.*` already covered it. The reviewer could not see any file the diff did not touch, and read "no evidence in the diff" as "unmet". - The review pass can now call a read-only `read_repo_file` tool, pinned to the PR head, before it submits its verdict (llm.ts completeStructuredWithLookups). - When a criterion is about ignoring or tracking files, the prompt gets `git check-ignore -v`-style answers for the paths the diff writes to (ignore-rules.ts, repo-state.ts). - A criterion that still can't be checked is `unverifiable` (met: null), including one whose evidence only says "cannot confirm from the provided context". It renders as "could not be verified". - When unverifiable criteria are the only thing open, the review is a neutral COMMENT and the End-goal check run is neutral. The stored status stays changes_requested, so payouts and passed-only Actions are unaffected. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
There was a problem hiding this comment.
DevAsign Code Review
No issues found
✅ Merge score: 100/100
13 of 13 acceptance criteria met.
This PR adds an outside-the-diff repository read capability to the criteria review pass, plus an unverifiable criterion outcome and neutral-review handling. I traced each of the 13 criteria against the implementation in llm.
Tests: 13 passed, 0 unverifiable — see the "Tests by DevAsign" comment.
Tests by DevAsign✅ 13 of 13 criteria verified by tests. Each verdict below links to its evidence. 1 — The review pass can call a read-only tool that reads a file or lists a directory in the repository at the PR head commit before submitting its verdict. (pass)Verdict: pass Lookup loop invokes read_repo_file and directory listing at PR head before the verdict tool. Test: 2 — A tool path that would resolve outside the repository is refused rather than read. (pass)Verdict: pass Paths escaping the repo via ../.. and post-normalisation are refused without reaching the reader, while legitimate paths pass. Test: 3 — The number of lookup turns before the review is forced to submit its verdict is capped (at most 6 lookup turns), after which submit_review_verdict is forced. (pass)Verdict: pass Exactly 6 lookup turns occur before the 7th call is forced to the verdict tool. Test: 4 — For a criterion about ignoring, committing, or tracking files, the prompt includes a repository-state section that resolves, in the manner of git check-ignore -v, the ignore status of the paths the diff writes to, including paths a script constructs at runtime such as path.join(outDir, ".env.cloudrun.yaml"). (pass)Verdict: pass Runtime path.join(outDir, '.env.cloudrun.yaml') is recognized as a write candidate and its ignore status rendered in git-check-ignore-v style; non-ignore criteria trigger no read. Test: 5 — When a criterion mentions .dockerignore or .gcloudignore, those ignore files are consulted for the resolution. (pass)Verdict: pass .dockerignore and .gcloudignore are fetched and applied when mentioned, and neither is fetched otherwise. Test: 6 — When an ignore file cannot be read, the ignore-status answer for the affected paths is reported as unknown, never as "not ignored". (pass)Verdict: pass A throwing ignore-file read reports unknown, never not-ignored, including partial ancestor failures. Test: 7 — For the #263 scenario, the path the diff writes for the Cloud Run env YAML resolves as ignored by the root .gitignore rule .env.* (.gitignore:14) using only the real root .gitignore, and the criterion about that file being gitignored is not marked unmet for lack of in-diff evidence. (pass)Verdict: pass The constructed .env.cloudrun.yaml path resolves as ignored against the real root .gitignore and the hedged verdict is not left as a plain unmet failure. Test: 8 — The reviewer can mark a criterion as unverifiable, and a failure whose evidence only amounts to "cannot confirm from the provided context" is converted to unverifiable. (pass)Verdict: pass Hedged 'cannot confirm from context' failures convert to unverifiable while genuine failures and met:true verdicts are unchanged. Test: 9 — An unverifiable criterion stores met as null and is scored at 5 points rather than 15. (pass)Verdict: pass Unverifiable criteria store met as null and score 5 points rather than 15. Test: 10 — When unverifiable criteria are the only open items, the GitHub review is submitted as a COMMENT and the End-goal check run outcome is neutral; the maintainer-dispute path behaves the same way. (pass)Verdict: pass Only-unverifiable open items resolve to a neutral COMMENT and neutral end-goal check for both fresh and maintainer-dispute shapes, while genuine blockers stay REQUEST_CHANGES. Test: 11 — When only unverifiable criteria are open, the stored status remains changes_requested so that bounty payouts, Actions set to runWhen: passed, and approval stats are unaffected. (pass)Verdict: pass Stored status stays changes_requested while the event softens to COMMENT; a genuine pass still resolves to passed/APPROVE. Test: 12 — Blocked verdicts and security blockers are never converted to a neutral or softened outcome. (pass)Verdict: pass Blocked status and security blockers are never softened to COMMENT even with awaitingConfirmation true. Test: 13 — In offline (mock) runs, review behavior is unchanged, and the mock prompt keeps the # Criteria section first. (pass)Verdict: pass Offline runs never invoke lookups and match completeStructured output, and the Criteria section stays first. Test: |
Why
On #263 the review failed "Variables not classified as secrets are written to a Cloud Run env-vars YAML file that is gitignored" on three runs in a row. The root
.gitignore:14(.env.*) already ignoredbackend/deploy/gcp/.env.cloudrun.yaml, asgit check-ignore -vconfirms. The reviewer said itself: "I cannot confirm from the provided context … there is no positive evidence." The criteria pass had no way to see a file the diff didn't touch, and it treated "no evidence in the diff" as "unmet". The author had to add a redundantbackend/deploy/gcp/.gitignoreto clear it.What changes
read_repo_file, which reads a file or lists a directory at the PR head commit, before it submits its verdict.completeStructuredWithLookups/runLookupLoopinllm.tsallow up to 6 lookup turns, then forcesubmit_review_verdict.review/ignore-rules.ts,review/repo-state.ts).# Repository state outside the diffsection.git check-ignore -vdoes, the paths the diff writes to — including files a script creates at runtime, such aspath.join(outDir, ".env.cloudrun.yaml")..dockerignoreand.gcloudignoreare checked when a criterion mentions them.unverifiablecriteria.unverifiable.met: nulland renders as "🔍 could not be verified — confirm by hand". It costs 5 points instead of 15.neutral("Needs manual confirmation"). The maintainer-dispute path does the same.changes_requested, so bounty payouts, Actions set torunWhen: passed, and approval stats are unaffected.Tests
outside-diff-evidence.test.tsis the Add a script to copy Render's env into GCP #263 regression, built from the real diff lines and the real root.gitignore. It checks that:.gitignore:14;.gitignorethrough the tool and passes the criterion;# Criteriastays first for the mock).ignore-rules.test.tscovers the ignore-rule matching. I also compared it against realgit check-ignoreon 21 paths in this repo, with no mismatches.decisions.test.tscoversawaitsConfirmationand the COMMENT routing.tsc --noEmitis clean.UI (second commit)
?row with a "needs confirmation" badge, and the header reads "N / M met · K to confirm".acceptance-view.ts, which has tests.unverifiedstatus and count, where it used to report these as "pending".splitForCommentno longer reports a previously-met criterion as "regressed" when it has become unverifiable.accountKind: "contributor", and the script prints thedevasign_session_contributorcookie. The contributor app couldn't sign in with the seed since the two-account split.backend-ephemeral. PRs 501–506 render as before.Not in this PR
🤖 Generated with Claude Code