docs: define issue-first contribution workflow - #6809
Conversation
📝 WalkthroughWalkthroughThe pull request establishes an issue-first contribution process. It updates issue and pull request templates, adds an Issue Gate evaluator with tests, and wires the evaluator into privileged and test GitHub Actions workflows. ChangesIssue-first contribution flow
Sequence Diagram(s)sequenceDiagram
participant PullRequest
participant IssueGateWorkflow
participant issue_gate_mjs
participant GitHubAPI
PullRequest->>IssueGateWorkflow: trigger pull_request_target or manual dispatch
IssueGateWorkflow->>issue_gate_mjs: run with pull request and gate configuration
issue_gate_mjs->>GitHubAPI: fetch pull request and referenced issue
GitHubAPI-->>issue_gate_mjs: return pull request and issue data
issue_gate_mjs->>issue_gate_mjs: evaluate reference, status, label, and exemptions
issue_gate_mjs->>GitHubAPI: publish status and synchronize labels/comments
issue_gate_mjs-->>IssueGateWorkflow: return gate result and exit status
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 3
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In @.github/PULL_REQUEST_TEMPLATE.md:
- Around line 11-13: Update the Summary prompt in the pull request template to
require authors to explain how the implementation meets the issue’s acceptance
criteria, while retaining the existing requirement to describe the solution and
its alignment with the agreed design.
In @.github/scripts/issue-gate.mjs:
- Around line 30-42: Update the issue-gate evaluation around the reference
parser in .github/scripts/issue-gate.mjs:30-42 to detect Closes, Fixes, and
Resolves references and return a failed evaluation when any are present, while
preserving existing Implements handling. In
.github/scripts/issue-gate.test.mjs:52-60, replace the current “ignores”
assertion with rejection cases covering each prohibited keyword.
- Around line 51-87: Update exemptionReason so cutoff-based legacy pull requests
return a distinct kind from policy:legacy label exemptions, then adjust the
synchronization guard around the label/comment handling near lines 354-364 to
skip synchronization only for the cutoff-specific kind. Preserve the existing
exemption reasons and behavior for policy:legacy, other exemptions, and
non-exempt pull requests.
🪄 Autofix
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro Plus
Run ID: c338e155-18ad-4ec6-bb08-060df5c228f9
📒 Files selected for processing (9)
.github/CONTRIBUTING.md.github/ISSUE_GATE.md.github/ISSUE_TEMPLATE/bug_report.yml.github/ISSUE_TEMPLATE/feature_request.yml.github/PULL_REQUEST_TEMPLATE.md.github/scripts/issue-gate.mjs.github/scripts/issue-gate.test.mjs.github/workflows/issue-gate-tests.yml.github/workflows/issue-gate.yml
| ## Summary | ||
|
|
||
| <!-- Explain the solution and how it follows the design agreed in the issue. --> |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
Prompt for acceptance-criteria coverage.
The template only asks how the solution follows the agreed design. .github/CONTRIBUTING.md Line 141 also requires an explanation of how the implementation meets the issue's acceptance criteria.
Add this requirement to the summary prompt so the template produces a policy-compliant pull request description.
Proposed change
-<!-- Explain the solution and how it follows the design agreed in the issue. -->
+<!-- Explain the solution, how it follows the agreed design, and how it meets each acceptance criterion. -->📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| ## Summary | |
| <!-- Explain the solution and how it follows the design agreed in the issue. --> | |
| ## Summary | |
| <!-- Explain the solution, how it follows the agreed design, and how it meets each acceptance criterion. --> |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In @.github/PULL_REQUEST_TEMPLATE.md around lines 11 - 13, Update the Summary
prompt in the pull request template to require authors to explain how the
implementation meets the issue’s acceptance criteria, while retaining the
existing requirement to describe the solution and its alignment with the agreed
design.
| const pattern = | ||
| /^[\t ]*Implements[\t ]+(?:(?<repository>[A-Za-z0-9_.-]+\/[A-Za-z0-9_.-]+))?#(?<number>\d+)\b/gim; | ||
|
|
||
| for (const match of (body ?? "").matchAll(pattern)) { | ||
| const repository = match.groups.repository ?? defaultRepository; | ||
| const number = Number.parseInt(match.groups.number, 10); | ||
| const key = `${repository.toLowerCase()}#${number}`; | ||
|
|
||
| if (!seen.has(key)) { | ||
| references.push({ repository, number }); | ||
| seen.add(key); | ||
| } | ||
| } |
There was a problem hiding this comment.
🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win
Reject prohibited GitHub closing keywords.
The gate accepts a description that contains both Implements #123 and `Closes `#123. GitHub can then close the referenced issue when the pull request merges. This bypasses the documented state:verification lifecycle.
.github/scripts/issue-gate.mjs#L30-L42: detectCloses,Fixes, andResolvesreferences and return a failed evaluation..github/scripts/issue-gate.test.mjs#L52-L60: replace the “ignores” assertion with rejection cases for each prohibited keyword.
📍 Affects 2 files
.github/scripts/issue-gate.mjs#L30-L42(this comment).github/scripts/issue-gate.test.mjs#L52-L60
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In @.github/scripts/issue-gate.mjs around lines 30 - 42, Update the issue-gate
evaluation around the reference parser in .github/scripts/issue-gate.mjs:30-42
to detect Closes, Fixes, and Resolves references and return a failed evaluation
when any are present, while preserving existing Implements handling. In
.github/scripts/issue-gate.test.mjs:52-60, replace the current “ignores”
assertion with rejection cases covering each prohibited keyword.
| function exemptionReason(pullRequest, cutoff) { | ||
| const labels = labelNames(pullRequest); | ||
| for (const label of EXEMPT_LABELS) { | ||
| if (labels.has(label)) { | ||
| return { | ||
| kind: label === "policy:legacy" ? "legacy" : "override", | ||
| reason: `the pull request has the \`${label}\` exemption label`, | ||
| }; | ||
| } | ||
| } | ||
|
|
||
| const actor = pullRequest.user?.login?.toLowerCase(); | ||
| if (EXEMPT_ACTORS.has(actor)) { | ||
| return { | ||
| kind: "automation", | ||
| reason: `\`${pullRequest.user.login}\` is an exempt automation account`, | ||
| }; | ||
| } | ||
|
|
||
| if (cutoff) { | ||
| const cutoffTime = Date.parse(cutoff); | ||
| if (Number.isNaN(cutoffTime)) { | ||
| throw new Error(`ISSUE_GATE_CUTOFF is not a valid date: ${cutoff}`); | ||
| } | ||
|
|
||
| const createdTime = Date.parse(pullRequest.created_at); | ||
| if (Number.isNaN(createdTime)) { | ||
| throw new Error(`Pull request has an invalid creation date: ${pullRequest.created_at}`); | ||
| } | ||
|
|
||
| if (createdTime < cutoffTime) { | ||
| return { | ||
| kind: "legacy", | ||
| reason: `the pull request predates the pilot cutoff (${cutoff})`, | ||
| }; | ||
| } | ||
| } |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟠 Major | ⚡ Quick win
Distinguish cutoff legacy pull requests from policy:legacy exemptions.
exemptionReason assigns legacy to both cases. Lines 355-364 then skip label and comment synchronization for both cases.
If a failed pull request later receives policy:legacy, the needs-ready-issue label and rejection comment remain visible. Return distinct exemption kinds and skip synchronization only for cutoff-based legacy pull requests.
Also applies to: 354-364
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In @.github/scripts/issue-gate.mjs around lines 51 - 87, Update exemptionReason
so cutoff-based legacy pull requests return a distinct kind from policy:legacy
label exemptions, then adjust the synchronization guard around the label/comment
handling near lines 354-364 to skip synchronization only for the cutoff-specific
kind. Preserve the existing exemption reasons and behavior for policy:legacy,
other exemptions, and non-exempt pull requests.
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes using default effort and found 2 potential issues.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit cf6c32e. Configure here.
| issueNumber: reference.number, | ||
| reason: `issue #${reference.number} does not have the \`${readyLabel}\` label`, | ||
| }; | ||
| } |
There was a problem hiding this comment.
Gate rejects in-progress issues
High Severity
evaluatePullRequest only accepts issues labeled state:ready, but the documented issue lifecycle moves work to state:in-progress once implementation starts. After that transition, later synchronize runs fail valid pull requests that still correctly Implements the issue, causing false failures in observe mode and merge blocks once enforcement is enabled.
Additional Locations (1)
Reviewed by Cursor Bugbot for commit cf6c32e. Configure here.
| # Until a cutoff is configured, every PR is treated as legacy. This | ||
| # keeps the newly merged workflow inert by default. | ||
| ISSUE_GATE_CUTOFF: ${{ vars.ISSUE_GATE_CUTOFF || '9999-12-31T00:00:00Z' }} | ||
| ISSUE_GATE_MODE: ${{ vars.ISSUE_GATE_MODE || 'observe' }} |
There was a problem hiding this comment.
Cutoff safety check bypassed
Medium Severity
The script rejects block/close when ISSUE_GATE_CUTOFF is empty, but the workflow always supplies 9999-12-31T00:00:00Z when the variable is unset. Setting only ISSUE_GATE_MODE to block or close therefore skips the refusal path and treats every PR as legacy-exempt, so enforcement never actually rejects anything.
Additional Locations (2)
Reviewed by Cursor Bugbot for commit cf6c32e. Configure here.
theCyberTech
left a comment
There was a problem hiding this comment.
LGTM
Might be worth revisiting the CodeRabbit reviews in the future as quick wins


Note
Low Risk
Changes are limited to GitHub docs, templates, and Actions; no runtime library code. The gate uses privileged
pull_request_targetbut only runs trusted default-branch script logic and does not execute PR code.Overview
Introduces an issue-first contribution pilot: issues move through lifecycle labels until
state:ready, and new PRs should reference exactly one ready issue viaImplements #123(not closing keywords) so issues stay open for post-merge verification.Docs and templates expand
CONTRIBUTING.md, addISSUE_GATE.md, a PR template, and richer bug/feature issue templates (state:inbox, impact, scope, acceptance criteria, verification plans).Automation adds
issue-gate.mjsplus apull_request_targetworkflow that checks out only the default branch, evaluates PR descriptions against openstate:readyissues, and in default observe mode reports results (status, comment, labels) without blocking;block/closemodes and cutoff-based legacy exemptions are documented for later activation. Unit tests and a small CI workflow cover the evaluator.Reviewed by Cursor Bugbot for commit cf6c32e. Bugbot is set up for automated code reviews on this repo. Configure here.