diff --git a/.github/ISSUE_TEMPLATE/03-task.yml b/.github/ISSUE_TEMPLATE/03-task.yml index b5dc9e1fd..5c24b8110 100644 --- a/.github/ISSUE_TEMPLATE/03-task.yml +++ b/.github/ISSUE_TEMPLATE/03-task.yml @@ -1,5 +1,5 @@ name: Task -description: Track maintainer or agent execution work +description: Track narrow execution, audit, spike, migration, or follow-up work title: "[Task] " labels: - task @@ -7,7 +7,13 @@ body: - type: markdown attributes: value: | - Use this for maintainer or agent execution work that is not a user-facing bug report or feature request. + Use this for narrow execution-only, audit, spike, migration, upstream follow-up, or tracking work. + + Do not use Task when another type is clearer: + - Behavior is broken, incorrect, flaky, misleading, or regressed → `bug` + - A user-facing workflow or capability should improve → `enhancement` + - Documentation, templates, policies, or written process should change → `documentation` + - Internal cleanup, maintainability, architecture, test, or quality debt → add `tech-debt` as supplemental context Keep the issue concrete enough that an agent can understand the target, scope, and verification path. - type: textarea diff --git a/.github/ISSUE_TRIAGE.md b/.github/ISSUE_TRIAGE.md new file mode 100644 index 000000000..25884f9cb --- /dev/null +++ b/.github/ISSUE_TRIAGE.md @@ -0,0 +1,12 @@ +# Issue triage labels + +Use one primary type label whenever possible: + +- `bug`: existing behavior is broken, incorrect, flaky, misleading, or regressed. +- `enhancement`: a user-facing workflow or capability should improve. +- `documentation`: docs, templates, policies, or written process should change. +- `task`: narrow execution-only, audit, spike, migration, upstream follow-up, or tracking work without clearer bug, feature, docs, or tech-debt semantics. + +Do not use `task` as the default label for work an agent can do. If `bug`, `enhancement`, or `documentation` describes the work more clearly, use that label instead. + +Area, priority, and context labels such as `app`, `ui`, `platform`, `harness`, `ci`, `P1`, `P2`, `upstream`, and `tech-debt` are supplemental and may be combined with the primary type. Use `tech-debt` for internal cleanup, maintainability, architecture, test, or quality debt; it does not require `task`. diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md index 392b5403d..cf84e4d69 100644 --- a/.github/pull_request_template.md +++ b/.github/pull_request_template.md @@ -48,6 +48,7 @@ Required for visible UI changes. ## Checklist > **How to use this checklist:** +> > - Tick a box by replacing `[ ]` with `[x]`. Do not edit, add, or remove items. > - The bot-applied label items can only be honestly ticked AFTER the PR is opened and the labeler / priority-triage bots have run — return to the PR description and tick them then. > - Most items are required. The few that are conditional are explicitly marked **(conditional)**; for those, leave unticked if they truly do not apply and explain why in Risk Notes. All other items must be ticked before requesting human review. diff --git a/.github/scripts/label-policy-check.js b/.github/scripts/label-policy-check.js index e8c24d507..9ed918651 100644 --- a/.github/scripts/label-policy-check.js +++ b/.github/scripts/label-policy-check.js @@ -37,15 +37,12 @@ export function validateLabelPolicy({ itemType, labels = [] }) { const routing = intersection(labelSet, POLICY.routing) if (routing.length < 1) { - errors.push(error(`${itemType} must have at least one primary routing label: ${labelList(POLICY.routing)}`, routing)) - } - - if (labelSet.has("tech-debt") && !labelSet.has("task")) { - errors.push(error("tech-debt is only allowed with the task type label", ["tech-debt"])) + errors.push( + error(`${itemType} must have at least one primary routing label: ${labelList(POLICY.routing)}`, routing), + ) } - const forbiddenIssueLabels = - itemType === "issue" ? intersection(labelSet, POLICY.issueForbiddenLabels) : [] + const forbiddenIssueLabels = itemType === "issue" ? intersection(labelSet, POLICY.issueForbiddenLabels) : [] if (forbiddenIssueLabels.length > 0) { errors.push( error(`issue must not use PR automation labels: ${labelList(POLICY.issueForbiddenLabels)}`, forbiddenIssueLabels), diff --git a/.github/scripts/label-policy-check.test.js b/.github/scripts/label-policy-check.test.js index 3900497d2..4ea017a00 100644 --- a/.github/scripts/label-policy-check.test.js +++ b/.github/scripts/label-policy-check.test.js @@ -81,7 +81,9 @@ test("rejects multiple type labels", () => { labels: ["bug", "task", "P2", "app"], }) - assert.deepEqual(messages(result), ["issue must have exactly one type label: bug, enhancement, task, or documentation"]) + assert.deepEqual(messages(result), [ + "issue must have exactly one type label: bug, enhancement, task, or documentation", + ]) }) test("rejects missing primary routing labels", () => { @@ -90,16 +92,18 @@ test("rejects missing primary routing labels", () => { labels: ["task", "P2"], }) - assert.deepEqual(messages(result), ["issue must have at least one primary routing label: app, ui, platform, harness, or ci"]) + assert.deepEqual(messages(result), [ + "issue must have at least one primary routing label: app, ui, platform, harness, or ci", + ]) }) -test("rejects tech-debt outside task issues", () => { +test("accepts tech-debt as a supplemental label with any primary type", () => { const result = validateLabelPolicy({ itemType: "issue", labels: ["bug", "P2", "app", "tech-debt"], }) - assert.deepEqual(messages(result), ["tech-debt is only allowed with the task type label"]) + assert.deepEqual(result.errors, []) }) test("rejects dependency automation labels on issues", () => {