Repository navigation
pr-pipeline: harden the lane-escalation gate for address-feedback #9419
Description
Follow-ups deferred from #9417, which lets address-feedback work a needs-human PR when a lane escalation put the label on. All fail safe or are low severity; the owner chose to harden later.
1. Re-check the gate source before the write runner pushes
select decides the gate once. When fix-requested=true, pr-run-activity-write.yml (the "Read the hold labels from the base" step) drops the human-gated label from its holds, and nothing in that workflow reads claude-lane-hold comments. A review-lane hold posted on the same head during the model turn, or a person removing and re-adding the label, is missed and the patch is pushed. ci-status still blocks the merge while the label is on.
Proposed fix: pass the gate kind (fix-request or lane-escalation) instead of a bare fix-requested flag, and re-run gateSource on a fresh read of comments and label events in the apply-patch hold step when it is lane-escalation.
2. Limit which escalation reasons ungate address-feedback
gateSource (.github/scripts/pr-unblock/gate-source.mjs) never reads the escalation comment's - Reason: line, so every pr-unblock reason ungates, including feedback-disputed, workflow-staged and unexpected-path-staged (report-escalation.sh). Today do-not-merge is the documented human re-gate. Proposed: an allowlist of reasons (for example ci-fix-*, the round cap), with any other reason returning unknown.
3. Let clear-escalations clear after an address-feedback round
clear-escalations.mjs (pr-unblock known set) treats <!-- pr-unblock:address-feedback-round --> and the model-run line as foreign markers, so once a round is recorded the label stays until a person removes it. Proposed: add both lines to its pr-unblock known set, as gateSource already does.
4. Count only trusted humans as lifting a review-lane hold
labelHistory in gate-source.mjs treats any actor's unlabeled event as lifting older holds. ci-status (pr-require-checks.yml, untrusted-lift step) accepts a lift only from trusted-actors.json and also counts a review bot's labeled event as a hold. Proposed: match ci-status on both points.
5. An unparsable hold marker disables the feature on that PR permanently
gateSource checks every hold on the timeline against criteria=[a-z-]+(?:,[a-z-]+)* before it applies the lifted or current-head logic, so one malformed hold, even an old lifted one, returns unknown for good. Confirm the criteria grammar against the producer (ci-workflows pr-review-cli.yml), or check parseability only for holds that are open or name the current head.
6. Confirm the order of GraphQL timelineItems
labelHistory relies on .at(-1) being the newest label event, which assumes timelineItems returns events oldest first. That assumption has not been checked against GitHub's docs. Confirm it, or sort by createdAt.
Activity
github-actions commentedon Oct 23, 2026
Proposed work class: none
Thanks for the report. Automated triage handed this issue to a maintainer.
Unconfirmed model suggestion: work-class: structural
Basis: automated intake triage; a maintainer confirms or changes it.
Automated triage. A maintainer reviews it.