Skip to content

Gate draft PRs too and rewrite the auto-close comment - #3378

Merged
maxisbey merged 4 commits into
mainfrom
gate-drafts
Aug 26, 2026
Merged

Gate draft PRs too and rewrite the auto-close comment#3378
maxisbey merged 4 commits into
mainfrom
gate-drafts

Conversation

@maxisbey

@maxisbey maxisbey commented Aug 24, 2026

Copy link
Copy Markdown
Contributor

Follow-up to #3291. Two changes to the PR intake gate:

Drafts are gated too. The gate skipped drafts until they were marked ready for review, which meant an unlinked PR could sit open indefinitely as a draft. Drafts now go through the same rule as everything else. The ready_for_review trigger stays so drafts opened before this change are still evaluated when they flip.

The auto-close comment is rewritten. The old text implied the PR would be reopened ("this one will be reopened", "nothing more you need to do") and packed everything into two dense paragraphs. The new one says what happened and why in one sentence, lists what the author can actually do for each situation (already assigned / no issue yet / issue exists but not assigned), and is upfront that review capacity for community PRs is very limited and most auto-closed PRs stay closed. When the PR is a draft, the opener adds one sentence explaining why it's closed before being marked ready (so the author doesn't put more time in only to have it closed then).

Motivation and Context

Drafts were being used to keep unlinked PRs visible past the gate, and the closing comment was setting expectations we can't meet.

How Has This Been Tested?

node --test .github/scripts/pr_intake_gate.test.js — the two draft scenarios now expect a close; 29/29 pass. Both comment variants rendered and read through by hand.

Breaking Changes

None for SDK users. External draft PRs without an assigned, linked issue are now closed on open/edit rather than on ready-for-review.

Types of changes

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to change)
  • Documentation update
  • Repository automation

Checklist

  • I have read the MCP Documentation
  • My code follows the repository's style guidelines
  • New and existing tests pass locally
  • I have added appropriate error handling
  • I have added or updated documentation as needed

Additional context

Already-closed PRs keep the old comment until their next gate event (edit, assignment, label change). Currently-open external drafts are evaluated on their next event, or by hand with gh workflow run require-linked-issue.yml -f pr_number=N.

AI Disclaimer

Drafts were skipped until marked ready for review, which let unlinked PRs
sit open indefinitely as drafts. They now go through the same rule as any
other PR.

The comment the gate leaves is rewritten to be clearer about what happened,
what (if anything) the author can do, and what to expect: it no longer
implies the PR will be reopened, and says plainly that review capacity for
community PRs is limited.
@maxisbey
maxisbey marked this pull request as ready for review August 26, 2026 09:56
Comment thread .github/scripts/pr_intake_gate.js Outdated
Comment thread .github/scripts/pr_intake_gate.js Outdated

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All reported issues were addressed across 4 files

Reply with feedback, questions, or to request a fix.

Re-trigger cubic

Comment thread .github/scripts/pr_intake_gate.js Outdated
Comment thread .github/scripts/pr_intake_gate.js Outdated

@claude claude Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Additional findings (outside the current diff — GitHub can't attach inline comments there):

  • 🟡 .github/scripts/pr_intake_gate.js — nit, pre-existing: refs.slice(0, MAX_ISSUES) only fetches the first five closing refs, and the front-loading hint exists solely on the issues assigned path — an edited re-run has no hint. So an author who follows the new closed-comment bullet (line 152: "add Fixes #<n> to the description and the PR will reopen on its own") stays closed if the description already carries five closing refs before the qualifying one; the base failed the same way but never promised reopen-on-edit for already-assigned authors. A fix should evaluate all refs for assignment (only fail-listing is what needs a cap), or prioritize refs the edit added.

    Extended reasoning...

    Path: an outsider's PR body already contains five distinct closing refs to non-qualifying issues (e.g. an AI-written description with "Fixes #1, Fixes #2, ... Fixes #5"). The gate closes it. A maintainer assigns the author to issue #N — but #N wasn't referenced, so the issues: assigned job filter (line 39, closingRefs(i.body).includes(issueNumber)) skips the PR. The author then follows the posted comment's bullet 1 (line 152) and appends Fixes #N. The edited event re-runs evaluate(): hintIssue is null (only the assigned path at line 46 passes one), refs preserves appearance order, line 100's refs.slice(0, MAX_ISSUES) (MAX_ISSUES=5, line 22) drops #N, so lines 104-105 never see the issue the author is assigned to and fail(linked) keeps the PR closed with a comment claiming they "aren't currently assigned to #1, #2...". No later event retries: the assignment already fired before the edit, so the reopen promise the merged comment makes is a dead end until a maintainer overrides. The base branch truncated identically on the edited path (pre-existing mechanism), but its comm

    Verification: nit. .github/scripts/pr_intake_gate.js:100 refs.slice(0, MAX_ISSUES) (MAX_ISSUES=5, line 22) fetches only the first five closing refs, and the front-loading at line 98 only runs when hintIssue is passed — which happens solely on the issues: assigned path (line 46); the edited path (line 62) passes no hint. The issues: assigned path itself skips PRs that don't already reference the assign

@claude claude Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code review found no issues

No high-confidence issues detected in this change.

? [
`${rule}, and you aren't currently assigned to ${issues}.`,
'',
`If a maintainer assigns you to ${issues}, this PR reopens on its own and there's nothing more you need to do here. Assignment is a maintainer call based on capacity; comments that only ask to be assigned don't factor in. What does help is engaging on the issue itself by confirming the repro, explaining why it matters for your use case, or describing the approach you'd take.`,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 nit: now that drafts get gate-closed, a draft with a linked-but-unassigned issue receives the linked-issues comment saying "this PR reopens on its own and there's nothing more you need to do here" — false for drafts, which after reopening are still drafts and need the author to mark them ready before anyone reviews them. Only the opener (line 140) is draft-aware; the situation text isn't. Add a draft-conditional clause to the assigned-path text (e.g. "once reopened, mark it ready for review") so draft authors aren't told they're done.

Extended reasoning...

Before this PR, if (pr.draft) return log(...) meant a draft could never reach fail() and closedComment() was only ever rendered for non-draft PRs, so "nothing more you need to do here" was accurate. After this change, fail() at line 124 passes pr.draft into closedComment(), but only the opener at lines 139-141 varies by draft; the linkedIssues.length branch at line 147 keeps the unconditional "this PR reopens on its own and there's nothing more you need to do here". Trigger: an outsider opens a draft PR with Fixes #N where #N is open but unassigned — the gate closes it with this comment. When a maintainer later assigns them, reopen() at line 240 reopens the PR still in draft state and deleteGateComment removes the comment; the PR then sits as an unreviewed draft because the author was explicitly told there was nothing more to do, when in fact they must click "ready for review" (which fires the ready_for_review event and re-passes). Consequence relative to base: base never showed this comment to draft authors, so the misleading promise is newly reachable. Fix: make the assig

Verification: nit — the described text mismatch is real and newly reachable, but it is only slightly misleading wording; nothing breaks. In .github/scripts/pr_intake_gate.js, fail() at line 124 now passes pr.draft into closedComment(pr.draft, linkedIssues), and drafts reach fail() because the diff removed the base branch's if (pr.draft) return log('draft — skipped until ready for review') guard (old lines

Comment on lines +7 to +8
# and it reopens automatically once the author is assigned. Drafts are gated
# too; bots are skipped. A triage+ user reopening the PR, removing the label,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 nit: the PR description says "CONTRIBUTING.md gets one clause noting drafts are covered" and ticks the Documentation update box, but the diff never touches CONTRIBUTING.md (the last commit, ccd46b7, deliberately reverts that change), so after merge the drafts-are-gated policy is documented only in this workflow header while the file the auto-close comment links contributors to stays silent. Either restore the one-clause CONTRIBUTING.md edit or update the PR description so it matches what merges.

Extended reasoning...

The PR body claims: "CONTRIBUTING.md gets one clause noting drafts are covered", and checks "I have added or updated documentation as needed". git log for the range shows commits b3a5054..ccd46b7, the last titled "Leave CONTRIBUTING.md unchanged" — grep confirms CONTRIBUTING.md contains no mention of drafts at all. The gate's closed comment (pr_intake_gate.js:162) points authors at CONTRIBUTING.md#how-pull-requests-get-in for "the full reasoning", but that section never says drafts are gated; the only place the new draft policy is written down is the header comment at .github/workflows/require-linked-issue.yml:7-8, which contributors do not read. No runtime failure — the blanket rule in CONTRIBUTING.md covers all PRs by silence — but the merged state does not match what the PR description promises, so a reviewer approving based on the description would believe the contributor-facing doc was updated when it was not.

Verification: nit — every factual link in the candidate checks out. (1) The PR description claims "CONTRIBUTING.md gets one clause noting drafts are covered" and ticks "Documentation update", but the net diff git diff 57394b0..HEAD --stat touches only .github/scripts/pr_intake_gate.js, .github/scripts/pr_intake_gate.test.js, and .github/workflows/require-linked-issue.yml — CONTRIBUTING.md is net-unc

@maxisbey
maxisbey merged commit e7284ed into main Aug 26, 2026
37 checks passed
@maxisbey
maxisbey deleted the gate-drafts branch August 26, 2026 11:02
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