Skip to content

feat(pr-pipeline): fail ci-status while a pull request carries needs-human - #9312

Merged
kyle-sexton merged 3 commits into
mainfrom
feat/ci-status-needs-human
Oct 23, 2026
Merged

kyle-sexton merged 3 commits into
mainfrom
feat/ci-status-needs-human

Conversation

@kyle-sexton

Copy link
Copy Markdown
Member

Refs: #9276

Summary

ci-status now fails while a pull request carries the human-gated label (needs-human by default), on every pull_request event (contract-only and draft runs included) and in the merge queue. The error names the reason from the newest review-lane hold comment and says that removing the label approves the pull request. This is the first PR of the #9276 plan: it gives the review lanes a hold that the one required check enforces.

Fix

  • New ci-status step, Fail a pull request carrying the human-gated label, for pull_request events. It resolves the label from .work-item-tracker.json role_labels.human-gated at the PR's base SHA through the contents API (a 404 falls back to needs-human; the same jq expression as pr-merge.yml), so a PR cannot rename its own hold. It reads labels live from the API, not the payload, with 3 tries. An unreadable tracker config, invalid JSON, a malformed base SHA or an unreadable label list fails closed. Error: #N carries 'needs-human' (<reason>). Removing the label approves this pull request; ci-status re-runs on the unlabel.
  • The reason comes from the newest comment that has a claude-lane-hold lane= HTML-comment marker line and is authored by claude[bot], or by github-actions[bot] when its last non-blank line is the claude-lane: <lane> footer (the lane-comment rule from feat(pr-pipeline): run the security review on pr-review-cli with key-first funding #9307). The footer and comment lines are stripped, the text is cut to 300 characters, and % is escaped. Comments are read only when the label is present. A failed comment read still fails the step, just without a reason.
  • The merge_group step, renamed Fail a queued pull request carrying a hold label, now fails on the human-gated label (resolved at merge_group.base_sha) as well as do-not-merge.
  • The ci-status timeout comment now counts the added retries (45 s of own-gate retries). The 5-minute cap still holds.
  • Known gap until plan PR 6: a review lane that adds the label with GITHUB_TOKEN starts no new workflow run, so a ci-status that is already green stays green until the planned rerun-ci-status listener lands. Until then the merge_group step is the backstop. A person's unlabel does re-run ci-status, so the error text is accurate.

Verification

  • scripts/ci-hold-human-gated.test.sh (new) runs the step body under bash -e against stub gh and sleep: PASS=24 FAIL=0. It covers the step's condition, its base-SHA read, its position before the aggregate, ci-status having no contract-only gate, the label held and absent, a substring label, the custom tracker label, a 404 fallback, invalid JSON, tracker and label retries, failing closed, reason extraction (newest hold comment, footer stripped, a person's marker ignored, github-actions[bot] without a footer ignored, claude[bot] read, 300-character cut, % escaped), and an unreadable comment list.
  • scripts/ci-hold-merge-group.test.sh (extended): PASS=22 FAIL=0, adding the human-gated label, the custom tracker label, the fallback, invalid or unreadable tracker config, and a bad base SHA.
  • scripts/check-affected.sh --tests: 10 passed, 4 skipped. Also scripts/check-lane-coverage.sh --check, scripts/check-test-tmp-cleanup.sh --check and scripts/check-silent-skips.sh pass, and run-plugin-tests.sh --list includes the new suite.
  • No change needed for fix-ci or the reconciler. fix-ci dispatch already skips PRs carrying either hold label (.github/scripts/pr-unblock/fix-ci-dispatch.mjs:39,137, with the tracker's label added at .github/scripts/pr-unblock/dispatch.mjs:473-478). The reconciler re-runs a failed run once only when a lane job other than ci-status failed (.github/scripts/maintenance-reconcile-lost-runs/infra-failure.mjs:50-56, whose comment names a hold label as the case it skips), and testedRun steps past red contract-only runs (infra-failure.mjs:104-115). A hold red therefore spends no fix-ci run and no reconciler re-run.
  • Left out: a live run of the step against GitHub. It is exercised by this PR's own CI and by the plan's sandbox canaries (PR 5).

Related

🤖 Generated with Claude Code

…human

ci-status now fails on a pull_request event, contract-only runs
included, while the pull request carries the human-gated label, and the
merge_group hold step fails on that label as well as do-not-merge. The
label is the base commit's .work-item-tracker.json
role_labels.human-gated (default needs-human), read through the contents
API at the base SHA; labels are read live with three tries and an
unreadable tracker config or label list fails closed. The PR-event error
names the reason from the newest review-lane hold comment (claude[bot],
or github-actions[bot] ending in a claude-lane footer) and says that
removing the label approves.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@kyle-sexton
kyle-sexton marked this pull request as ready for review October 23, 2026 04:42
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Oct 23, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-10-23T04:43:37.110802Z 1ea1478 Draft marked ready
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@github-actions

github-actions Bot commented Oct 23, 2026 •

Copy link
Copy Markdown
Contributor

claude-security-review reviewed 1b58fe1fc1e4e9ec1f7c226034f3e9697bfe47c2: 0 finding(s), 0 as inline comments.

Security review (incremental, since 1ea1478)

Scope: .github/workflows/pr-require-checks.yml only, per .claude-lane/incremental.diff.

Result: no security issues found.

The change replaces three literal backticks in jq regexes with the escape. jq decodes to a backtick before the regex runs, so each pattern matches the same text as before.

  • The hold-comment trust check is unchanged. The comment must still come from claude[bot], or from github-actions[bot] with a last line of claude-lane: claude-review or claude-lane: claude-security-review. The Bot user-type filter is unchanged, and no new author or label is trusted.
  • The jq program is single-quoted, so the shell leaves the escape alone. The $reason and $PR_NUMBER handling is unchanged.
  • No plugin manifest or instruction-surface file changed, so there are no manifest <field> lines.

critical-findings: 0

@github-actions

github-actions Bot commented Oct 23, 2026 •

Copy link
Copy Markdown
Contributor

claude-review reviewed 1b58fe1fc1e4e9ec1f7c226034f3e9697bfe47c2: 0 finding(s), 0 as inline comments.

Incremental review of .github/workflows/pr-require-checks.yml (changes since 1ea1478): no findings.

The change replaces three literal backticks with the jq string escape in the lane-hold footer matching, at lines 3250 and 3253. Both sit inside bash single-quoted jq programs, so the backslash reaches jq unchanged. is a standard JSON/jq string escape, which both gh --jq (gojq) and jq accept. The regexes are equivalent to the previous ones (optional backtick, then claude-lane: …), so the match behavior is unchanged.

I did not run the filter: the sandbox refused the jq test command. This is a reading-based check, not a tested one.

Manifest items: no plugin manifest changed.

actionlint's shellcheck pass (SC2016) read the literal backtick inside
the single-quoted jq programs as an unexpanded expression and failed
lint-repo. ` is the same character to jq's regex, so behavior is
unchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@kyle-sexton
kyle-sexton added this pull request to the merge queue Oct 23, 2026
Merged via the queue into main with commit 0b59b4c Oct 23, 2026
38 checks passed
@kyle-sexton
kyle-sexton deleted the feat/ci-status-needs-human branch October 23, 2026 05:10
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant