Skip to content

fix(pr-pipeline): hold a stale pr-verify pass in the queue and name pass refusals in the hold - #13342

Merged
kyle-sexton merged 3 commits into
mainfrom
ccp-refused-pass-text
Nov 4, 2026
Merged

kyle-sexton merged 3 commits into
mainfrom
ccp-refused-pass-text

Conversation

@kyle-sexton

@kyle-sexton kyle-sexton commented Nov 4, 2026 •

Copy link
Copy Markdown
Member

No related issue: hub ledger L300. The merge gate held lanes App PR #13333 with "pr-verify has not passed this head" when it had passed, and that ejected the queue behind it.

Summary

#13333's pass at 5d74488 is valid (artifact pr-verify-13333-5d744886…-pass-notes, pr-verify run 41893841490). The gate's reader refused it with verify:spec-changed: a trusted comment landed on #13191 at 19:07:47Z, 31 s after that pr-verify run started (babysit_verify_evidence.py _pass_refusal). In FAIL index mode the reader saves no artifact listing, so the step at pr-require-checks.yml:6580-6585 treats every refusal as one returned before any listing and reads no pass names. merge-holds.mjs then saw no pass record and reported "pr-verify has not passed this head" (merge-group runs 41895300192 and 41895674384). PR Lane's host check read the pass and disagreed, and PR Lane has since moved verify-pass.sh onto the gate's own reader.

Fix

  • Owner decision, 2026-11-04, "Hold until re-judged" (recorded on this PR): a verify:spec-changed refusal now holds in the queue whether or not the pass was read. Before, a read pass let a stale head merge, and index mode held it only by accident. The hold reads pr-verify's pass on this head is stale (verify:spec-changed): its linked issue changed after pr-verify judged it; wait for pr-verify to pass it, …. The lost-run reconciler re-runs pr-verify after a spec change, and an approval of the head by a listed person lifts the hold.
  • When no pass names were read and the reader refused the pass (verify:missing or verify:untrusted-spec), the hold names that refusal instead of "has not passed this head". passRefusalOf returns only PASS_REFUSALS, so a FAIL class stays evidenceHold's and is never called a pass refusal.

Verification

  • node --test .github/scripts/pr-merge/merge-holds.test.mjs: 66 pass, 0 fail. The tests cover the stale hold with a read pass, a pass refusal with no pass read, the missing-pass text for no refusal, another head or a FAIL class, and that verify:missing and verify:untrusted-spec still leave a read pass standing.
  • scripts/check-affected.sh --base origin/main --no-fetch: 9 passed, 7 skipped.

Related

🤖 Generated with Claude Code

…ing pass

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@kyle-sexton
kyle-sexton marked this pull request as ready for review November 4, 2026 19:42
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Nov 4, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-11-04T19:43:31.603343Z 61a3fd9 Draft marked ready
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@github-actions

github-actions Bot commented Nov 4, 2026 •

Copy link
Copy Markdown
Contributor

claude-security-review reviewed dc7e0c86b89d2899eefc9b05aa6315cc6379a06c: read 1 of 1 changed file(s); 0 finding(s), 0 as inline comments.

Security review: PR #13342 (incremental, 12d59ec → dc7e0c8)

I found no security issues in this push. The lane had already reviewed an earlier head, so this review was blocking only: it would report only CRITICAL or IMPORTANT findings.

What I checked. One file changed since the last review, scripts/ci-lanes-pr-hold.test.sh, and I read its whole hunk. It matches none of the trusted-path globs, and the change is to tests only:

  • The old assertion said a verify:spec-changed refusal in the merge queue does not hold (exit 0). It now says that refusal holds (exit 1) with the "pass on this head is stale" text. This pins the stricter hold that merge-holds.mjs added in the head reviewed earlier.
  • A new assertion checks that a different pass refusal (verify:untrusted-spec) is still left to the pass checks (exit 0).

The push changes no gate, hold script, workflow, token, or trust control. It only makes the shell suite expect the stricter behaviour reviewed last round. Nothing in it is a path for an attacker.

Earlier findings. My earlier summary on this PR reported 0 findings, so there is nothing to restate.

PR context. The description has no instructions aimed at this lane. It now matches the stale-pass hold.

critical-findings: 0

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

claude-review: 1 inline finding(s) on 61a3fd9471c1d3f0b9be4570990a1e3e0f67d77d; the summary is in this lane's pull request comment.

claude-lane: claude-review

@github-actions

github-actions Bot commented Nov 4, 2026 •

Copy link
Copy Markdown
Contributor

claude-review reviewed dc7e0c86b89d2899eefc9b05aa6315cc6379a06c: read 1 of 1 changed file(s); 0 finding(s), 0 as inline comments.

Code review: #13342, incremental 12d59ec..dc7e0c8 (blocking only)

This lane already reviewed an earlier head (blocking only: yes), so this review reports only blocking findings. I read the whole change to the one file in scope, scripts/ci-lanes-pr-hold.test.sh. For context I also read the verifier block of main in merge-holds.mjs at head (L1690-L1730).

No blocking findings.

What changed:

  • The shell-suite case that used to expect a read verify:spec-changed pass to clear the merge queue (exit 0) now expects exit 1 and the text #7: pr-verify's pass on this head is stale (verify:spec-changed) (ci-lanes-pr-hold.test.sh#L882). This matches the code: refused === STALE sets unverified (merge-holds.mjs#L1702-L1703). With no approval, that hold is pushed with the "wait for pr-verify to pass it" remedy (L1718-L1720). It also matches the owner decision recorded in the PR description.
  • The exit-0 "left to the pass checks" case now uses verify:untrusted-spec (L883). With a read pass, records is non-empty, so unverified stays null and the L1704 branch does not fire. evidenceOf returns no FAIL, so L1725 logs the expected the reader refuses this head only on its pass (verify:untrusted-spec). text. The case keeps covering the path the old assertion covered.

The test results in the PR description were claimed by the author. I did not verify them, because this lane has no shell.

The earlier thread on passRefusalOf is resolved and stays settled. No closing issue: the PR cites hub ledger L300, so there are no acceptance criteria to check.

No hold: this change is test-only and touches no billing.

…ges the head again

A verify:spec-changed refusal now holds whether or not the pass was read
(owner decision 2026-11-04, "Hold until re-judged"). passRefusalOf returns
only PASS_REFUSALS, so a FAIL class is never named a pass refusal.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@kyle-sexton

Copy link
Copy Markdown
Member Author

Owner decision, 2026-11-04 (AskUserQuestion in the Automation Lanes session 24905f8a).

Asked: when the linked issue is commented on or edited after pr-verify passed a PR, the pass is stale (verify:spec-changed). Until now the merge queue let a stale pass merge when it read the pass record (merge-holds.test.mjs, "a reader that refuses only on the pass leaves that to verdictHold"), and held it only by accident in FAIL index mode (#13333). Options: hold until re-judged, let it merge, or hold only on body edits.

Owner's pick, verbatim: "Hold until re-judged (Recommended)".

Built in this PR: a verify:spec-changed refusal holds in the queue whether or not the pass was read, until pr-verify judges the head again (the lost-run reconciler re-runs it) or an approval of the head by a listed person lifts it.

Posted by the Automation Lanes session. This was generated by AI.

@kyle-sexton kyle-sexton changed the title fix(pr-pipeline): name the reader's pass refusal in the merge hold, not a missing pass fix(pr-pipeline): hold a stale pr-verify pass in the queue and name pass refusals in the hold Nov 4, 2026
… suite

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@kyle-sexton
kyle-sexton added this pull request to the merge queue Nov 4, 2026
Merged via the queue into main with commit 1627d7f Nov 4, 2026
42 checks passed
@kyle-sexton
kyle-sexton deleted the ccp-refused-pass-text branch November 4, 2026 20:39
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant