Skip to content

fix(pr-merge): take a cost decision's decided head from the review lane's check-run annotation, not a bot comment #9635

Closed
melodic-software/ci-workflows
#904

Description

@kyle-sexton

Problem

The cost-decision readers take the decided head from the sha= in the newest unedited github-actions[bot] claude-lane-hold ... criteria=cost marker comment. That holds for the merge-side readers once #9569 merges, and for ci-workflows apply-review-hold/hold.cjs carryDecision. Any workflow running on GITHUB_TOKEN posts as github-actions[bot]. Someone with push access and the workflows permission could therefore run a workflow that posts a marker naming a commit they have not pushed yet, then push that commit, and the same-head shortcut would carry an earlier cost decision onto it with no compare.

This widens nothing today. The same permission can already edit .github/workflows/pr-require-checks.yml directly, and the lanes App has no workflows permission. It is hardening, so that the carry does not rest on a comment author login.

Fix

Take the decided head from the review lane's own check-run annotation, the one ci-status already vets against a head that does not change the lane workflows (pr-require-checks.yml, the review-lane notice loop, ~3755-3776), and stop reading a github-actions[bot] comment for it. Do it in all three merge-side readers (babysit_merge_policy.cost_decision, merge-holds.mjs costDecision, the ci-status lift) and in ci-workflows hold.cjs, so the readers stay in agreement.

Refs

Refs: #9436

Activity

  1. added
    needs-triageNot yet classified. Floor until a type and one priority tier are set.
    on Oct 24, 2026
  2. github-actions commented on Oct 24, 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: Known
    Flags: none
    Blocked by: none

    Understood: the cost-decision readers (babysit_merge_policy.cost_decision, merge-holds.mjs costDecision, the ci-status lift, and ci-workflows hold.cjs carryDecision) should take the decided head from the review lane's check-run annotation instead of the sha= in a github-actions[bot] marker comment, so the carry doesn't rest on a comment author login. The issue frames this as hardening that widens nothing today. Nothing is missing; the approach is stated. No likely duplicates found among open issues.

    Automated triage, applied by the lanes App.

  3. added
    needs-humanHuman-in-the-loop required; autonomous sessions must not resolve items carrying this.
    on Oct 24, 2026
  4. removed
    needs-triageNot yet classified. Floor until a type and one priority tier are set.
    on Oct 24, 2026
  5. kyle-sexton commented on Oct 26, 2026

    @kyle-sexton
    MemberAuthor

    Builder: the Automation Lanes session builds this from the owner's machine. The fix edits .github/workflows, which the lanes App cannot push (patch-rules.json:3); that boundary stays. Its PR closes this issue. needs-human came off under the owner's 2026-10-26 rule (a person only for an intent or vision change, an implementation finding that alters intent or the primary design, or a HIGH/CRITICAL security issue); none applies. agent-ready stays off so the issue lane does not race the build.

  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.
    needs-humanHuman-in-the-loop required; autonomous sessions must not resolve items carrying this.
    on Oct 26, 2026
  7. kyle-sexton commented on Oct 26, 2026

    @kyle-sexton
    MemberAuthor

    Released for re-triage under the owner's 2026-10-26 rule: a person is involved only for "1. A change in original intent/vision 2. Something comes up during implementation ... that alters intent/vision or the primary design 3. If there is a HIGH/CRITICAL security issue". None applies here, so the hold label came off and intake triage runs again now.

    To hold this issue again, add needs-human (or status: needs-decision) and name which of the three applies.

  8. 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.
    and removed
    status: readyTriaged, unblocked, and fully specified; eligible to pick up.
    on Oct 26, 2026
  9. melodic-automation-lanes commented on Oct 26, 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).

  10. melodic-automation-lanes commented on Oct 26, 2026

    @melodic-automation-lanes
    Contributor

    The latest triage verdict holds nothing: admission moved the issue to status: confirmed; its comment says why.

  11. melodic-automation-lanes commented on Oct 26, 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: The three merge-side readers and ci-workflows hold.cjs take a cost decision's decided head from the sha in the review lane's vetted claude-lane-hold check-run annotation, and no longer read a github-actions[bot] comment for it.

    Dependencies

    • ci-workflows release of the hold.cjs carryDecision change, then a re-pin of the review callers here, so the readers stay in agreement

    Related work

    Open questions

    1. hold.cjs carryDecision lives in the ci-workflows repo, which is not in this checkout, so a run here cannot edit or check it. Should this issue cover only the three in-repo readers, with the hold.cjs change filed in ci-workflows plus a re-pin here?
      RECOMMENDED: Yes. Limit this issue to babysit_merge_policy.cost_decision, merge-holds.mjs costDecision and the ci-status lift, and file hold.cjs in ci-workflows. Basis: judgment; no hold.cjs under the checkout, and pr-require-checks.yml:3783 says the lift mirrors ci-workflows v0.65.4's hold step
    2. The fix edits .github/workflows, which the lanes App cannot push, and the owner's session is building it. Should the issue lane attempt it?
      RECOMMENDED: No. Keep it with the owner's session and keep agent-ready off. Basis: comment by kyle-sexton 2026-10-26T04:01:56Z citing patch-rules.json:3
    3. The annotation has sha and criteria but the readers also need the decision-time ordering the comment gave (costMarker's created_at cutoff, and the edited/deleted checks). Which replaces them: the check-run completed_at, or drop them since the annotation is vetted?
      RECOMMENDED: Use the check-run completed_at for the before-decision cutoff and drop the edit and delete checks, since a vetted annotation cannot be edited as a comment can. Basis: merge-holds.mjs:508 costMarker and merge-holds.mjs:594-602 edit and delete checks; judgment

    Sources read

    • context.json: issue 9635 body and comments
    • /home/runner/work/claude-code-plugins/claude-code-plugins/.base/.github/scripts/pr-merge/merge-holds.mjs:508: costMarker reads the newest github-actions[bot] comment matching the claude-lane-hold marker with criteria containing cost
    • /home/runner/work/claude-code-plugins/claude-code-plugins/.base/.github/scripts/pr-merge/merge-holds.mjs:603: carries uses marker.sha as the decided head and compares against head
    • /home/runner/work/claude-code-plugins/claude-code-plugins/.base/.github/workflows/pr-require-checks.yml:3758: the lift reads holds from the annotation notice but the decided head from the bot comment (3778)

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

  12. kyle-sexton commented on Oct 29, 2026

    @kyle-sexton
    MemberAuthor

    Re-triage. Not an owner stop. This is hardening that narrows what a comment can decide and widens nothing, and the builder was already named on 2026-10-26 (#9635 (comment)). The leftover status: needs-decision label comes off.

    Progress, checked against origin/main at 1ac46f0:

    • Done: PR fix(pr-merge): take a cost decision's decided head from the review lane's check-run annotation #10357 (merge commit 6e004b0) moved all three merge-side readers to the review lanes' vetted check-run notices: babysit_merge_policy.cost_decision, merge-holds.mjs costDecision, and the ci-status lift in pr-require-checks.yml. It dropped the comment read and its edit and delete checks. The PR used Refs:, leaving the ci-workflows half to close this issue.
    • Open: in melodic-software/ci-workflows, carryDecision in .github/actions/apply-review-hold/hold.cjs (about lines 238-259) still takes the decided head from the newest unedited github-actions[bot] marker comment.

    The refinement's questions, settled: (1) the ci-workflows change is built in that repository, then the review callers here are re-pinned; (2) the issue lane does not take it; (3) the before-decision cutoff uses the status job's completion time, and the comment edit and delete checks go, as #10357 did on the merge side.

    Build: the Automation Lanes session. The change lands in another repository, and the re-pin edits .github/workflows here, which the lanes App cannot push (.github/actions/resolve-config/patch-rules.json:3). agent-ready stays off.

    Acceptance criteria:

    • ci-workflows hold.cjs carryDecision reads the decided head with the same rule as fix(pr-merge): take a cost decision's decided head from the review lane's check-run annotation #10357: vetted pull_request runs of both review lanes that started before the decision, status-job notices whose sha= is their run's own head, the newest notice deciding, and nothing carried when two heads were noticed at that time. It reads no github-actions[bot] comment for it, and the change has tests in ci-workflows.
    • A ci-workflows release carries that change, and this repository's review-lane callers pin that release.
    • One case is checked across the four readers: a marker comment naming an unpushed head carries no cost decision in any of them.
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.work-class: scopedA briefed fix or small feature; blast radius bounded by the brief, tests exist.

    Type

    Fields

    No fields configured for Bug.

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions