Skip to content

fix(ci): check-signed-commits reports an unconfirmed PR head as unverified commits with no SHA #8879

Closed

Description

@kyle-sexton

Problem

check-signed-commits escalates a pull request as having unverified commits when it could not check them at all, and names no commit. The lane commits in these runs are signed; nothing was caught unsigned and no fix was discarded.

Seen twice on 2026-10-21:

  • pr-unblock address-feedback on #8870, run 39615724332: the lane moved work-resolve-issue/issue-8734-39613836173-1 from 2a21d0b1 to 45e6f6fd at 14:20:58. 45e6f6fd is GitHub-verified (reason: valid), its parent is the recorded since-sha, and it is still the PR's head. The check ran at 14:21:19 and logged no comparison from the recorded head; checked the PR's commits, then ##[warning]check-signed-commits: unverified commits with an empty list. needs-human was applied at 14:24:04.
  • pr-refine fix-docs on #8844, run 39619999852: ACT_OUTCOME: skipped, so the model never ran and the lane made no commit. The check logged the same two lines, with an empty list again.

Cause

The PR's head as GET /pulls reports it never matched the branch ref, so the check could not confirm the head. It reported that as "unverified commits". It was not a failed read, not a commit-list query error, and not a pre-push check: the commit list was read, and the check runs after the push.

In .github/actions/check-signed-commits/check-signed-commits.mjs:

  1. readPull (:42-54) reads the pull and the branch's git/ref up to HEAD_READS = 5 times, 2 s apart (:17-18), and returns headConfirmed: false when they never agree.
  2. With headConfirmed false the comparison is skipped (:151-153), so sinceIsAncestor is false and :210 logs "no comparison from the recorded head", although the recorded head was an ancestor.
  3. checkable is false (:156). unverified is computed over the PR's commits, which are all verified, so it is []. allVerified is false (:165).
  4. :215 logs unverified commits ${[].join(" ")}, and the escalation comment (:106) opens with "these commits are not GitHub-verified" even when no commit is unverified. The head did not match its branch line (:112) comes second.

Callers: pr-run-activity-write.yml:2290 and pr-run-activity-read.yml:1494.

Cost

A false needs-human hold: no lane continues on the PR until a human looks, and the log and comment send that human after a nonexistent unsigned commit.

Suggested fix

  1. Say "could not verify" (small). When !checkable, log check-signed-commits: could not verify the lane's commits (PR head <pull.head.sha> never matched branch ref <refSha> after 5 reads) instead of unverified commits. Lead the comment with the same reason, and list unverified SHAs only when there are some. Keep all-verified=false, so the run still fails closed. Add a test: head unconfirmed, every commit verified, the log says "could not verify" and never "unverified commits".
  2. Wait longer (optional). The observed /pulls lag was at least 47 s, against a 5 × 2 s window. A backed-off wait of about 60 s would have cleared feat(corrections): add corrections:codify #8870. It would not clear fix(guardrails): anchor the merge guard's backtick refusal to a gh command word #8844.
  3. Check against the ref (design, not small). Compare since...refSha when the head is unconfirmed. Hazard: the later filter against the PR commit list (:95-97) would use a stale list that lacks the lane's new commit (45e6f6fd here) and pass it unchecked. This touches fix(ci): check-signed-commits trusts the PR's current base to drop merged-in commits #8240.

Related

Activity

  1. added
    needs-triageNot yet classified. Floor until a type and one priority tier are set.
    on Oct 21, 2026
  2. github-actions commented on Oct 21, 2026

    @github-actions
    Contributor

    Proposed work class: work-class: scoped
    Basis: automated intake triage; a maintainer confirms or changes it.

    Thanks for the detailed report. I understood it this way: when check-signed-commits can't confirm the PR head against the branch ref, it logs and comments "unverified commits" with an empty list, even though every commit is verified. That leads to a false needs-human hold. Your suggested fix has three parts. Part 1 is to report "could not verify" and keep failing closed. Part 2 is a longer wait. Part 3 is to compare against the ref, which is a design question tied to #8240. Nothing seems to be missing for part 1. Parts 2 and 3 would need a maintainer's decision. I found no likely duplicates among the open issues.

    Automated triage. A maintainer reviews it.

  3. added
    priority: mediumReal value, no hard deadline; normal backlog flow.
    and removed
    needs-triageNot yet classified. Floor until a type and one priority tier are set.
    on Oct 21, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    priority: mediumReal value, no hard deadline; normal backlog flow.

    Type

    Fields

    No fields configured for Bug.

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions