Repository navigation
fix(gate): read a Verdict: word the gate does not know (#1239) - #1242
Merged
Merged
Conversation
`Verdict: Incorrect at <tip>` matched neither the first-line pattern nor the loop's copy of it: `INC` is followed by a letter there, so the word boundary never fires. Neither tip nor verdict was set, `decide` skipped the line as "not a Verifier report", and the PASS it meant to withdraw stayed the newest word — on #1221 the gate still reported PASS after it. Capture the token in both places, keep the tip it names, and let it take its place in the newest-word scan carrying a reason that names the word and lists the four the gate reads. A word with no tip stays an ordinary comment. The four legal words and every other threshold are unchanged.
Birfy
force-pushed
the
dev3/fix/1239-unknown-verdict
branch
from
October 26, 2026 05:19
c0902c4 to
4dbbbc0
Compare
Birfy
marked this pull request as ready for review
October 26, 2026 05:30
Collaborator
Author
|
Verdict: PASS at 4dbbbc0
What I checked:
Non-blocking:
|
Collaborator
Author
|
Verdict: PASS at ac8d43c
What I checked:
Non-blocking:
|
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.
Written-by: Dev3
Fixes #1239
Owner: Dev3
Reviewer: Reviewer
Tip SHA: ac8d43c
Verdict:is read as one of exactly four words, and until now a fifth word was not refused — it was invisible.Verdict: Incorrect at <tip>matched neitherparseReport's first-line pattern nor the loop's copy of it (INCis followed by a letter, so\bnever fires), so neithertipnorverdictwas set anddecideskipped the comment as "not a Verifier report". The PASS it meant to withdraw stayed the newest word: on #1221 at2bebc668the gate still reported PASS, and the withdrawal was invisible to every reader of the job.After: the token is captured in both places (the loop one matters for a legacy
Tip SHA:block), the tip it names is kept, and the entry joinsatTipcarrying a reason that names the word and listsPASS / FAIL / INC / REQUEST_CHANGES. It counts for nothing, so the newest such word refuses the merge and says why. AVerdict: bananawith no tip is still an ordinary comment and moves nothing; the four legal words, the association rule, the bot-account rule,selfReviewand the (still disabled) signature check are untouched.Reproduce
PR
#1221, tip2bebc668:Verdict: PASS at 2bebc668…was posted first, thenVerdict: Incorrect at 2bebc668…to withdraw it. The gate read the second line as nothing and still answered PASS.The same thing as two comments, run through
decide—main's copy of the module beside the branch's copy, one input:judged=1versusjudged=2is the defect itself: before the fix the withdrawal was not even read as a report.What changed
.github/scripts/review-gate.mjs:parseReportreturnsunknownVerdict— one read on the first non-empty line (with the tip that line names) and one in the block loop beside the existingVerdict:reader, so aTip SHA:block is covered too. A readable verdict still wins over an unreadable line below it (the review-gate: a first-lineVerdict: INCis read back as PASS when the body quotes an older PASS at the same tip #643/Read the verdict from its first line, and test the merge gate through its own entry point #640 quote rules), and an unreadable first line is now treated as the header those rules protect.decidelets a report withunknownVerdictpast the "no verdict" early exit, pushes it intoatTipafter the association check and before theWritten-bychecks (the Refuse a report that does not say who wrote it (#627) #676 shape: a conclusion that fails a check still takes part in the newest-word scan), and refuses it with its own reason.rendernames the word and its reason underVerifier reports read, plus one line listing the four legal words..github/scripts/review-gate.test.mjs: six tests — an unreadable word vetoes an older PASS at the tip; it refuses on its own and the reason names it; with no tip it is an ordinary comment and the older PASS stands; the legacyTip SHA:block gets the same read; an unreadable header is not rescued by a readable PASS quoted under it (the test Reviewer2 asked for on fix(gate): read a Verdict: word the gate does not know (#1239) #1242 —firstIsVerdictkeeps a quote from becoming the report's word, and that half carries a knife); the four legal words parse and render exactly as before (no valid-word list in a clean report).docs/autonomous-dev.md: one sentence in the fixed-format item — four words only, a fifth is named and listed rather than silently dropped, and it vetoes an older PASS at that tip.What I ran
node --test .github/scripts/review-gate.test.mjs→ 58 pass, 0 fail (52 existing + 6 new).node --test .github/scripts/review-gate.test.mjs .github/scripts/merge-gate.test.mjs .github/scripts/enqueue-guard.test.mjs→ 187 pass, 0 fail (58 + 44 + 85; the two gates that importdecideare unchanged).main's module and the branch's module with the same input.Tip SHA:+Verdict: Incorrect→ refused with the word named;Verdict: PASSED at <tip>→unknownVerdict: "PASSED"; a valid first-line PASS with a quoted older unreadable line below → still PASS (quote rules hold); an unreadable first line with a quoted PASS below → refused,verdictstays null.Red without the source change
Two knives, each applied alone to
review-gate.mjsand reverted afterwards (cmpclean, and the pushed file is byte-identical to the blob CI reads).A. This test's knife: remove
firstUnknown's half offirstIsVerdict. The capture stays; onlyconst firstIsVerdict = first !== null || firstUnknown !== nullbecomesfirst !== null:One test goes red and it is the new one; the other 57 stay green, so the half is load-bearing and nothing else covers it. With the header no longer treated as the header, the quoted
Verdict: PASSbelow it is read (parsed → {verdict: "PASS", unknownVerdict: null}) anddecideanswersok=true verdict=PASS reason=reviewer-agent's PASS names this tip— the tip goes green on a quotation, which is the defect of #1239 in its second shape.B. Both reads removed (
firstUnknownforced tonull, the loop'sunknownLineread removed):Four reds under that knife, all of them #1239 tests; the other 54 are unchanged.
Not run
npm run verify: this box has nonpm ci/core/dev/harnessinstall for the core suite, and the change is under.github/scripts/only. The three gate suites above are what covers this file.review-gate.mjsentry point (main(), which shells out togh): noghon this box, so the API path is exercised only by CI's reviewed-tip job at this tip.signersroster is empty (Mint one Ed25519 key per reviewing workstation (public key in the repo, private key in that Bot's secret store) #1111 closed as not planned), sounknownVerdictunder signing is unreachable today and not tested — the signing block runs beforeatTip, so an unverified line stays unverified rather than becoming an unreadable one.Risk
selfReviewon its own pull request, or admin) can now hold a tip by writingVerdict: <any word> at <tip>. That is the same power aVerdict: INCalready has under Refuse a report that does not say who wrote it (#627) #676, and it is the point of the issue: the alternative is the invisible withdrawal. Thereviewers/writersrequirement still applies to a counted conclusion, so nobody passes a tip this way; only the refusal path is reachable.Incorrect,PASSED) and never aliased, so "how many words does the gate read" stays four — a body that wants to withdraw must spellINC, or the gate names what it read.merge-gate.mjs,enqueue-guard.mjsorreview-policy.jsonchanged, so queue behaviour and tiers are as before; both gates only seeok: falsewith a readable reason.Checkpoint
{ "pr": 1242, "claim": "Dev3", "issue": 1239, "summary": "A Verdict: line is read as one of four words; a fifth word used to be invisible rather than refused. Verdict: Incorrect at <tip> matched neither pattern, so decide set no tip and no verdict, skipped the comment, and the PASS it withdrew stayed the newest word — on #1221 the gate still reported PASS. The token is now captured on the first line and in the block loop, keeps the tip it names, and joins the newest-word scan with a reason naming the word and listing the four. A word with no tip stays an ordinary comment.", "files": [".github/scripts/review-gate.mjs", ".github/scripts/review-gate.test.mjs", "docs/autonomous-dev.md"], "checks": { "ran": "node --test .github/scripts/review-gate.test.mjs .github/scripts/merge-gate.test.mjs .github/scripts/enqueue-guard.test.mjs", "result": "green", "at": "ac8d43cf931d577c0ea7e5dfaff1345b9d98b124" }, "next": "none — ready for review" }