Skip to content

pr-merge: re-judge a PR whose pr-merge/unarmed status outlived its cause #12862

Open

Description

@kyle-sexton

Problem

pr-merge stamps a failing pr-merge/unarmed status when it judges a PR and leaves it unarmed. Nothing re-judges that status once the cause clears, and the status itself makes the PR's merge state UNSTABLE.

During the 2026-11-03 review-token outage and the rate limits that followed, pr-merge stamped pr-merge/unarmed on lanes App PRs. One example is run 41621679690 on #12795 at 10:44Z. Their review lanes passed on re-run by about 15:00Z, but the status stayed red. Eleven green PRs (#12604 #12795 #12796 #12812 #12814 #12815 #12817 #12818 #12823 #12824 #12825) sat at 4 to 14 h, and #12604 reached 13.9 h. Every arm path that requires a CLEAN merge state refused them. The red check was the "unarmed" status itself.

They moved only because a local owner sweep was changed to accept UNSTABLE when ci-status, the only required check, is green. The merge lane itself still strands PRs the same way after the next outage.

Expected

When a PR's inputs change (a review lane completes, ci-status re-runs, or a hold label comes off), pr-merge re-judges the PR and either arms it or refreshes pr-merge/unarmed with the current reason. A stale pr-merge/unarmed should not outlive the condition that set it.

Done when

  • A PR whose only blocker was a transient failure (outage, rate limit, kill switch) is re-judged by pr-merge within one scheduled tick after the blocker clears, with no session involved.
  • A test covers it: a PR left unarmed on a failed review gets armed after the review re-run passes.
  • The re-judge records the same telemetry as a first judgment, so stale-unarmed time can be measured.

Refs: #12795, #12604.

Activity

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

    @github-actions
    Contributor

    The triage sweep dispatched intake triage for this issue (dispatch 1; 2 runs that reach intake, or 6 dispatches, hand it to a maintainer).

  3. github-actions commented on Nov 3, 2026

    @github-actions
    Contributor

    Proposed work class: work-class: scoped
    Basis: automated intake triage; the lanes App applied this class.

    Size: Medium
    Complexity: Medium
    Uncertainty: Knowable
    Flags: none
    Blocked by: none

    I understood this as a defect: pr-merge leaves a failing pr-merge/unarmed status on a PR after the transient cause clears, such as an outage or rate limit. The stale status makes the merge state UNSTABLE, so CLEAN-only arm paths refuse the PR. You want pr-merge to re-judge the PR within one scheduled tick after the blocker clears. You also want a test covering a PR unarmed on a failed review that gets armed after the re-run passes, and the same telemetry as a first judgment.

    Related, not duplicates: #12445 (wake pr-merge per PR on pr-verify completion, with the cron as a backstop) and #12447. Maintainers may want to coordinate with them.

    Automated triage, applied by the lanes App.

  4. added
    priority: highSignificant impact, or blocks an imminent release; staff this cycle.
    and removed
    needs-triageNot yet classified. Floor until a type and one priority tier are set.
    on Nov 3, 2026
  5. added
    status: readyTriaged, unblocked, and fully specified; eligible to pick up.
    work-class: scopedA briefed fix or small feature; blast radius bounded by the brief, tests exist.
    on Nov 3, 2026
  6. melodic-automation-lanes commented on Nov 3, 2026

    @melodic-automation-lanes
    Contributor

    Not admitted to the issue lane: no trusted-human acceptance criteria: a listed human must put the confirmed - [ ] criteria in the body or post them as their own comment, or, on an issue a listed human filed, intake's newest refinement comment must hold them unedited. Admission takes the issue once each of those is met, when intake triages it again (.github/actions/resolve-config/admission-rules.json).

  7. added
    status: confirmedA maintainer confirmed the item is real and in scope; ready to be worked.
    and removed
    status: readyTriaged, unblocked, and fully specified; eligible to pick up.
    on Nov 3, 2026
  8. added
    status: needs-decisionAwaiting a human or maintainer judgment call.
    and removed
    status: confirmedA maintainer confirmed the item is real and in scope; ready to be worked.
    on Nov 3, 2026
  9. melodic-automation-lanes commented on Nov 3, 2026

    @melodic-automation-lanes
    Contributor

    Refinement. A read-only run explored this repository, searched its issues and pull requests, and read the allowed docs to draft what follows. On an issue a listed human filed, it counts as the issue's spec once posted, while unedited; it is still model text, so check it.

    Intended outcome: pr-merge's readiness gate stops counting its own failing pr-merge/unarmed status against a PR, so the next scheduled run re-judges it and posts a passing status or a refreshed reason.

    Related work

    Open questions

    1. Which fix? (a) The readiness gate ignores a failing pr-merge/unarmed status when it reads merge state, so UNSTABLE caused only by that status counts as ready. (b) The gate accepts UNSTABLE whenever ci-status, the only required check, is green, as the local owner sweep now does. (c) The run clears the stale status before judging.
      RECOMMENDED: (a) Treat UNSTABLE as ready only when pr-merge/unarmed is the sole failing non-required check. Keep CLEAN-or-HAS_HOOKS for every other cause. Basis: plugins/source-control/skills/babysit-prs/scripts/babysit_merge.py:1785
    2. Should the fix also add event triggers (a review lane completing, ci-status re-running, a hold label coming off), or is the existing 11,41 cron enough? The issue's done-when says one scheduled tick, but the Expected section lists input-change events.
      RECOMMENDED: Keep it to the schedule. Wake-per-event is already tracked in #​12445, and the cron at .github/workflows/pr-merge.yml:118-119 gives a tick every 30 minutes. Basis: https:/​/github.com/search?q=12445 (named in the intake triage comment)
    3. The code comments say scheduled runs already judge a lane refusal again and post a passing status on arming (enable-auto-merge.mjs:115-121). Is the loop only the CLEAN-state gate, or does a refusal path elsewhere also keep the PR from being judged? A person should confirm from run 41621679690 on #​12795 before work starts.
      RECOMMENDED: Treat the CLEAN-state gate as the cause, and have the first step of the work reproduce it in a test. Basis: judgment
    4. Should the stale-unarmed time telemetry be a new field or reuse the existing LANE_SINCE marker and lane records?
      RECOMMENDED: Reuse the existing LANE_SINCE marker and pr-merge-lane-records, with no new schema. Basis: .github/scripts/pr-merge/enable-auto-merge.mjs:677

    Sources read

    • .github/scripts/pr-merge/enable-auto-merge.mjs:112-123: a lane refusal is judged again by scheduled runs and, once it has stood for merge.risk-escalation-minutes, posts a failing pr-merge/unarmed status, and a passing one on arming.
    • .github/scripts/pr-merge/enable-auto-merge.mjs:986-1004: unarmedStatus posts a failure only for a lane-clearable refusal that has stood past the threshold.
    • .github/workflows/pr-merge.yml:118-119: the cron runs at 11 and 41 past each hour.
    • .github/workflows/pr-merge.yml:2855-2883: the unarmed-status job posts the statuses.
    • .github/scripts/pr-merge/post-unarmed-status.mjs: posts the status.
    • plugins/source-control/skills/babysit-prs/scripts/babysit_merge.py:285: READY_MERGE_STATES is CLEAN and HAS_HOOKS only.
    • plugins/source-control/skills/babysit-prs/scripts/babysit_merge.py:1785-1791: a mergeStateStatus outside READY_MERGE_STATES refuses the PR, so a PR made UNSTABLE by its own unarmed status is refused.

    To answer, post a comment that starts with this line:

    **Decision recorded.** <answer>
    

    Automated refinement by the lanes App. Answer with a comment whose first line is **Decision recorded.**.

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: highSignificant impact, or blocks an imminent release; staff this cycle.status: needs-decisionAwaiting a human or maintainer judgment call.work-class: scopedA briefed fix or small feature; blast radius bounded by the brief, tests exist.

    Type

    Fields

    Work status

    needs-owner-decision

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions