Skip to content

ci-status's person hold on a hold-path PR keeps pr-verify from judging the head before approval #10699

Description

@kyle-sexton

Problem

On a pull request that changes a hold path, ci-status fails until a trusted person approves the head ("it changes , a hold path; an approving review of this head by a person on the trusted-actor list lifts it"). pr-verify runs only after ci-status succeeds (.github/workflows/pr-verify.yml:74, github.event.workflow_run.conclusion == 'success'). So the person approves a head that pr-verify has not judged yet. Fail-notes from an earlier head stay open, and the lane stops with feedback-untaken-threads, until the approval comes.

Seen on #10583 at head 4017f44: ci-status failed only on the hold-path reason, so pr-verify never ran and the three superseded fail-notes could not clear.

Wanted

pr-verify judges the head before a person is asked to approve it, so the approval is the last step, not the first.

Constraints

  • ci-status must not go green on a hold-path PR without the approval.
  • pr-verify must not run on a head that fails ci-status for a real defect. That gate is what keeps it from judging broken code.
  • The person hold is a security boundary for lanes App PRs (R2). Do not weaken it.

Options to weigh

  1. ci-status reports the hold-path reason as a separate required-for-merge status, so its own conclusion stays success when the hold is the only failure, and pr-verify triggers on it.
  2. pr-verify also triggers when ci-status fails only for a person-hold reason, read from a machine-readable reason in the check output.
  3. Keep it as is: the person approves first.

Activity

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

    @github-actions
    Contributor

    Proposed work class: none

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

    I understood this as: on a hold-path PR, ci-status fails on the person-hold reason alone, so pr-verify never runs. The trusted person then approves a head that pr-verify hasn't judged, and earlier fail-notes stay open. You want pr-verify to judge first and the approval to come last. The hold must not weaken, and pr-verify must still skip heads with real defects. No duplicate found among open issues.

    The issue lists three options and picks none, so I need the owner's call:

    1. Which option should be built: (1) a separate required hold status, (2) pr-verify also triggering on a hold-only ci-status failure, or (3) keep the current order?
      RECOMMENDED: option 2. It keeps ci-status as the single gate and leaves the hold check unchanged. Option 1 adds a new required status and changes the merge rules, which touches the R2 boundary more.

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

    **Decision recorded.** <your answer>
    

    Automated triage. A maintainer reviews it.

  3. melodic-automation-lanes commented on Oct 28, 2026

    @melodic-automation-lanes
    Contributor

    The triage verdict left this issue at status: needs-decision:

    • flagged: intent
    • held by status: needs-decision
    • no lanes App verdict comment shows whether an earlier verdict was flagged
  4. melodic-automation-lanes commented on Oct 28, 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-verify judges a hold-path PR head before the trusted person approves it, with ci-status still failing without approval and still gating pr-verify on real defects.

    Related work

    Open questions

    1. Which option should be built: (1) a separate required hold status, (2) pr-verify also triggering on a hold-only ci-status failure, or (3) keep the current order?
      RECOMMENDED: Option 2, with the hold-only reason read from a machine-readable marker in ci-status output or run data, and pr-verify still skipping any other failure. Basis: .github/workflows/pr-verify.yml:74 gates on conclusion == 'success'; option 2 leaves ci-status as the one gate and does not add a required status, so branch-protection rules stay unchanged.
    2. If option 2, how should pr-verify know ci-status failed only for the person-hold reason, given that a workflow_run trigger sees only the conclusion and not the reason?
      RECOMMENDED: Have ci-status upload a small artifact or write a job output listing failure reasons, and have pr-verify's gate job fetch it from the upstream run and proceed only when the sole reason is the hold. It must fail closed if the marker is missing or malformed. Basis: judgment
    3. Should a pr-verify pass on a hold-only head have any effect on the hold, or must the lift still come only from a trusted person's approving review of that head?
      RECOMMENDED: No effect. Only the trusted person's approval lifts the hold, so R2 is unchanged, and pr-verify output must never count as approval. Basis: judgment
    4. Is it acceptable that pr-verify's Claude-driven steps run on a head that has not yet been approved by a person, for hold-path PRs from lanes App authors?
      RECOMMENDED: Yes only if pr-verify runs from the default branch with no write power beyond fail-notes and its current permissions. The owner should confirm this against the R2 threat model. Basis: judgment

    Sources read

    • /home/runner/work/claude-code-plugins/claude-code-plugins/.base/.github/workflows/pr-verify.yml:44: workflow_run trigger runs from the default branch, never a PR's copy
    • /home/runner/work/claude-code-plugins/claude-code-plugins/.base/.github/workflows/pr-verify.yml:74: job runs only when the upstream workflow_run conclusion is success; lines 420 and 776 repeat it for the other jobs

    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.**.

  5. kyle-sexton commented on Oct 29, 2026

    @kyle-sexton
    MemberAuthor

    Re-triage. No owner stop applies. The person hold stays exactly as it is. This changes only when pr-verify judges a head, not what lifts the hold. The open questions are decided below on origin/main 1ac46f037a.

    1. Which option?
      Decided: option 2. pr-verify also runs when ci-status failed for the person-hold reason alone. Any other ci-status failure still skips it.

      • Option 1 adds a required status and changes merge rules on the R2 boundary.
      • Option 3 keeps the defect, where a person approves a head pr-verify has not judged.

      Basis: .github/workflows/pr-verify.yml:74 gates every job on conclusion == 'success'.

    2. How does pr-verify know the failure was hold-only?
      Decided: ci-status records its failure reasons in machine-readable form (a job output or a small artifact on its run). pr-verify's gate reads it from the upstream run and proceeds only when the sole reason is the hold path. It fails closed, skipping pr-verify, when the record is missing, unreadable or lists any other reason. The hold reason's text is pinned at scripts/ci-lanes-pr-hold.test.sh:458. The build finds the step that emits it and changes it in that step's own repository.

    3. Does a pr-verify pass touch the hold?
      Decided: no. Only an approving review of the head by a person on the trusted-actor list lifts it, and pr-verify output never counts as approval.

    4. Is it safe for pr-verify to run on an unapproved hold-path head?
      Decided: yes. pr-verify runs from the default branch, never the PR's copy (pr-verify.yml:44), checks out refs/heads/main (:91), and each of its three jobs holds only contents: read, pull-requests: read and actions: read (:78-81, :427-430, :782-785). The review lanes already run Claude on every hold-path head before approval (pr-review-hosted.yml:31, :198-200). So pr-verify adds no new class of exposure.

    Builder: the Automation Lanes session builds this from the owner's machine, because the fix edits .github/workflows/pr-verify.yml, which the lanes App cannot push (.github/actions/resolve-config/patch-rules.json:3). agent-ready stays off.

    Acceptance criteria:

    • On a hold-path PR whose only ci-status failure is the hold-path reason, pr-verify runs on that head and posts its verdict before the approval.
    • On a head where ci-status fails for any other reason, alone or with the hold, pr-verify does not run. A test covers that case and the missing or malformed reason record.
    • ci-status still fails on a hold-path PR until a trusted person approves the head, and a pr-verify pass does not change that. A test covers it.
    • The person-hold path in docs/conventions/pr-pipeline/README.md states the new order: pr-verify judges first, then the person approves.
    • actionlint passes on the changed workflows, and ci-status is green on the PR head.
    • A security-review pass ran at the PR head.
  6. added
    status: confirmedA maintainer confirmed the item is real and in scope; ready to be worked.
    and removed
    status: needs-decisionAwaiting a human or maintainer judgment call.
    on Oct 29, 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.status: confirmedA maintainer confirmed the item is real and in scope; ready to be worked.

    Type

    Fields

    No fields configured for Task.

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions