From b0b0da85b7289e210a457293c6a7faf1dd018884 Mon Sep 17 00:00:00 2001 From: Yuhan Lei Date: Thu, 21 May 2026 14:26:04 +0800 Subject: [PATCH 1/3] docs(github): clarify issue taxonomy --- .github/ISSUE_TEMPLATE/03-task.yml | 10 ++- .github/ISSUE_TEMPLATE/04-tech-debt.yml | 78 ++++++++++++++++++++++ .github/ISSUE_TRIAGE.md | 13 ++++ .github/pull_request_template.md | 2 +- .github/scripts/label-policy-check.js | 6 +- .github/scripts/label-policy-check.test.js | 22 +++--- 6 files changed, 114 insertions(+), 17 deletions(-) create mode 100644 .github/ISSUE_TEMPLATE/04-tech-debt.yml create mode 100644 .github/ISSUE_TRIAGE.md diff --git a/.github/ISSUE_TEMPLATE/03-task.yml b/.github/ISSUE_TEMPLATE/03-task.yml index b5dc9e1fd..ffa063a13 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 report + - A user-facing workflow or capability should improve → Feature request + - Documentation, templates, policies, or written process should change → Documentation + - Internal cleanup, maintainability, architecture, test, or quality debt → Tech debt Keep the issue concrete enough that an agent can understand the target, scope, and verification path. - type: textarea diff --git a/.github/ISSUE_TEMPLATE/04-tech-debt.yml b/.github/ISSUE_TEMPLATE/04-tech-debt.yml new file mode 100644 index 000000000..bed3a44ce --- /dev/null +++ b/.github/ISSUE_TEMPLATE/04-tech-debt.yml @@ -0,0 +1,78 @@ +name: Tech debt +description: Track internal cleanup, maintainability, architecture, test, or quality debt +title: "[Tech Debt] " +labels: + - tech-debt +body: + - type: markdown + attributes: + value: | + Use this for internal cleanup, maintainability, architecture, test, or quality debt that is not primarily a user-facing bug or feature request. + + If existing behavior is broken or misleading, use Bug report instead. If the main goal is a new user-visible workflow or capability, use Feature request instead. + - type: textarea + id: debt + attributes: + label: What debt should be reduced? + description: Describe the current maintainability, architecture, test, or quality problem. + placeholder: The session timeline has multiple scroll owners, making regressions hard to reason about and test. + validations: + required: true + - type: textarea + id: impact + attributes: + label: Why does it matter? + description: Explain the cost of leaving this debt in place. + placeholder: New timeline changes repeatedly cause scroll regressions, and reviewers cannot easily identify the owning state machine. + validations: + required: true + - type: textarea + id: scope + attributes: + label: Scope + description: What is in scope and what should stay out of scope? + placeholder: | + In scope: + - Consolidate scroll ownership into one helper. + - Preserve current user-visible behavior. + + Out of scope: + - Redesigning the message UI. + - Changing right-panel behavior. + validations: + required: true + - type: textarea + id: pointers + attributes: + label: Relevant files or context + description: Point to likely files, issues, PRs, logs, screenshots, or existing patterns. + placeholder: | + Likely files: + - packages/app/src/... + + Related issues: + - #123 + validations: + required: false + - type: textarea + id: verification + attributes: + label: Verification + description: How should the result be checked? + placeholder: | + - Run the focused tests for ... + - Confirm current user-visible behavior is preserved. + - Confirm no unrelated cleanup was included. + validations: + required: true + - type: dropdown + id: execution_mode + attributes: + label: Execution mode + description: Pick the safest starting mode. Each option defines exactly what the agent must do next on this issue. + options: + - Wait for human approval — the agent must not write code or open a PR until a human leaves an explicit "approved" comment on this issue + - Investigate and propose a plan first — the agent must post the plan as an issue comment and wait for an explicit "approved" comment before writing code or opening a PR + - Implement and open a PR — the agent makes the requested changes on a feature branch and opens a PR following the standard PR template without requiring prior issue-comment approval. The agent must not push directly to dev, and the resulting PR still requires human approval to merge. + validations: + required: true diff --git a/.github/ISSUE_TRIAGE.md b/.github/ISSUE_TRIAGE.md new file mode 100644 index 000000000..14cc3bdff --- /dev/null +++ b/.github/ISSUE_TRIAGE.md @@ -0,0 +1,13 @@ +# 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. +- `tech-debt`: internal cleanup, maintainability, architecture, test, or quality debt. +- `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`, `documentation`, or `tech-debt` describes the work more clearly, use that label instead. + +Area, priority, and context labels such as `app`, `ui`, `platform`, `harness`, `ci`, `P1`, `P2`, and `upstream` are supplemental and may be combined with the primary type. diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md index 392b5403d..5886dbcc8 100644 --- a/.github/pull_request_template.md +++ b/.github/pull_request_template.md @@ -52,7 +52,7 @@ Required for visible UI changes. > - 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. -- [ ] **Type label** — this PR carries exactly one of `bug`, `enhancement`, `task`, `documentation`. Type labels are author-added; the labeler bot does NOT assign them. Add the label in the GitHub UI, then tick this. +- [ ] **Type label** — this PR carries exactly one of `bug`, `enhancement`, `task`, `documentation`, `tech-debt`. Type labels are author-added; the labeler bot does NOT assign them. Add the label in the GitHub UI, then tick this. - [ ] **Routing labels** — this PR carries at least one of `app`, `ui`, `platform`, `harness`, `ci`. The labeler bot assigns these on PR open based on changed paths. Confirm the bot's choice (or override if wrong), then tick this. - [ ] **Priority label** — this PR carries exactly one of `P0`, `P1`, `P2`, `P3`. The priority-triage bot suggests one on PR open. Confirm or override, then tick this. - [ ] Human Review Status above is set to `Pending`, `Approved by @`, or `Not required: ` (default is `Pending`; "not required" is restricted to bot-authored low-risk PRs). diff --git a/.github/scripts/label-policy-check.js b/.github/scripts/label-policy-check.js index e8c24d507..f8c6bdae5 100644 --- a/.github/scripts/label-policy-check.js +++ b/.github/scripts/label-policy-check.js @@ -1,6 +1,6 @@ export const POLICY = { priorities: ["P0", "P1", "P2", "P3"], - types: ["bug", "enhancement", "task", "documentation"], + types: ["bug", "enhancement", "task", "documentation", "tech-debt"], routing: ["app", "ui", "platform", "harness", "ci"], issueForbiddenLabels: ["dependencies", "github_actions", "javascript"], } @@ -40,10 +40,6 @@ export function validateLabelPolicy({ itemType, labels = [] }) { 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"])) - } - const forbiddenIssueLabels = itemType === "issue" ? intersection(labelSet, POLICY.issueForbiddenLabels) : [] if (forbiddenIssueLabels.length > 0) { diff --git a/.github/scripts/label-policy-check.test.js b/.github/scripts/label-policy-check.test.js index 3900497d2..5a2b81d24 100644 --- a/.github/scripts/label-policy-check.test.js +++ b/.github/scripts/label-policy-check.test.js @@ -10,7 +10,7 @@ function messages(result) { test("accepts a valid issue label set", () => { const result = validateLabelPolicy({ itemType: "issue", - labels: ["task", "P2", "app", "tech-debt"], + labels: ["tech-debt", "P2", "app"], }) assert.deepEqual(result.errors, []) @@ -50,7 +50,7 @@ test("treats missing labels input as an empty label set", () => { assert.deepEqual(messages(result), [ "issue must have exactly one priority label: P0, P1, P2, or P3", - "issue must have exactly one type label: bug, enhancement, task, or documentation", + "issue must have exactly one type label: bug, enhancement, task, documentation, or tech-debt", "issue must have at least one primary routing label: app, ui, platform, harness, or ci", ]) }) @@ -71,7 +71,7 @@ test("rejects missing type labels", () => { }) assert.deepEqual(messages(result), [ - "pull_request must have exactly one type label: bug, enhancement, task, or documentation", + "pull_request must have exactly one type label: bug, enhancement, task, documentation, or tech-debt", ]) }) @@ -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, documentation, or tech-debt", + ]) }) 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 primary type label", () => { const result = validateLabelPolicy({ itemType: "issue", - labels: ["bug", "P2", "app", "tech-debt"], + labels: ["tech-debt", "P2", "app"], }) - 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", () => { @@ -121,7 +125,7 @@ test("reports all independent label policy failures", () => { assert.deepEqual(messages(result), [ "issue must have exactly one priority label: P0, P1, P2, or P3", - "issue must have exactly one type label: bug, enhancement, task, or documentation", + "issue must have exactly one type label: bug, enhancement, task, documentation, or tech-debt", "issue must have at least one primary routing label: app, ui, platform, harness, or ci", "issue must not use PR automation labels: dependencies, github_actions, or javascript", ]) From fa9d0e0560d0c94a77e7211bff678247b332c647 Mon Sep 17 00:00:00 2001 From: Yuhan Lei Date: Thu, 21 May 2026 14:33:16 +0800 Subject: [PATCH 2/3] docs(github): keep tech-debt supplemental --- .github/ISSUE_TEMPLATE/04-tech-debt.yml | 78 ---------------------- .github/ISSUE_TRIAGE.md | 5 +- .github/pull_request_template.md | 3 +- .github/scripts/label-policy-check.js | 9 +-- .github/scripts/label-policy-check.test.js | 14 ++-- 5 files changed, 16 insertions(+), 93 deletions(-) delete mode 100644 .github/ISSUE_TEMPLATE/04-tech-debt.yml diff --git a/.github/ISSUE_TEMPLATE/04-tech-debt.yml b/.github/ISSUE_TEMPLATE/04-tech-debt.yml deleted file mode 100644 index bed3a44ce..000000000 --- a/.github/ISSUE_TEMPLATE/04-tech-debt.yml +++ /dev/null @@ -1,78 +0,0 @@ -name: Tech debt -description: Track internal cleanup, maintainability, architecture, test, or quality debt -title: "[Tech Debt] " -labels: - - tech-debt -body: - - type: markdown - attributes: - value: | - Use this for internal cleanup, maintainability, architecture, test, or quality debt that is not primarily a user-facing bug or feature request. - - If existing behavior is broken or misleading, use Bug report instead. If the main goal is a new user-visible workflow or capability, use Feature request instead. - - type: textarea - id: debt - attributes: - label: What debt should be reduced? - description: Describe the current maintainability, architecture, test, or quality problem. - placeholder: The session timeline has multiple scroll owners, making regressions hard to reason about and test. - validations: - required: true - - type: textarea - id: impact - attributes: - label: Why does it matter? - description: Explain the cost of leaving this debt in place. - placeholder: New timeline changes repeatedly cause scroll regressions, and reviewers cannot easily identify the owning state machine. - validations: - required: true - - type: textarea - id: scope - attributes: - label: Scope - description: What is in scope and what should stay out of scope? - placeholder: | - In scope: - - Consolidate scroll ownership into one helper. - - Preserve current user-visible behavior. - - Out of scope: - - Redesigning the message UI. - - Changing right-panel behavior. - validations: - required: true - - type: textarea - id: pointers - attributes: - label: Relevant files or context - description: Point to likely files, issues, PRs, logs, screenshots, or existing patterns. - placeholder: | - Likely files: - - packages/app/src/... - - Related issues: - - #123 - validations: - required: false - - type: textarea - id: verification - attributes: - label: Verification - description: How should the result be checked? - placeholder: | - - Run the focused tests for ... - - Confirm current user-visible behavior is preserved. - - Confirm no unrelated cleanup was included. - validations: - required: true - - type: dropdown - id: execution_mode - attributes: - label: Execution mode - description: Pick the safest starting mode. Each option defines exactly what the agent must do next on this issue. - options: - - Wait for human approval — the agent must not write code or open a PR until a human leaves an explicit "approved" comment on this issue - - Investigate and propose a plan first — the agent must post the plan as an issue comment and wait for an explicit "approved" comment before writing code or opening a PR - - Implement and open a PR — the agent makes the requested changes on a feature branch and opens a PR following the standard PR template without requiring prior issue-comment approval. The agent must not push directly to dev, and the resulting PR still requires human approval to merge. - validations: - required: true diff --git a/.github/ISSUE_TRIAGE.md b/.github/ISSUE_TRIAGE.md index 14cc3bdff..25884f9cb 100644 --- a/.github/ISSUE_TRIAGE.md +++ b/.github/ISSUE_TRIAGE.md @@ -5,9 +5,8 @@ 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. -- `tech-debt`: internal cleanup, maintainability, architecture, test, or quality debt. - `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`, `documentation`, or `tech-debt` describes the work more clearly, use that label instead. +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`, and `upstream` are supplemental and may be combined with the primary type. +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 5886dbcc8..cf84e4d69 100644 --- a/.github/pull_request_template.md +++ b/.github/pull_request_template.md @@ -48,11 +48,12 @@ 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. -- [ ] **Type label** — this PR carries exactly one of `bug`, `enhancement`, `task`, `documentation`, `tech-debt`. Type labels are author-added; the labeler bot does NOT assign them. Add the label in the GitHub UI, then tick this. +- [ ] **Type label** — this PR carries exactly one of `bug`, `enhancement`, `task`, `documentation`. Type labels are author-added; the labeler bot does NOT assign them. Add the label in the GitHub UI, then tick this. - [ ] **Routing labels** — this PR carries at least one of `app`, `ui`, `platform`, `harness`, `ci`. The labeler bot assigns these on PR open based on changed paths. Confirm the bot's choice (or override if wrong), then tick this. - [ ] **Priority label** — this PR carries exactly one of `P0`, `P1`, `P2`, `P3`. The priority-triage bot suggests one on PR open. Confirm or override, then tick this. - [ ] Human Review Status above is set to `Pending`, `Approved by @`, or `Not required: ` (default is `Pending`; "not required" is restricted to bot-authored low-risk PRs). diff --git a/.github/scripts/label-policy-check.js b/.github/scripts/label-policy-check.js index f8c6bdae5..9ed918651 100644 --- a/.github/scripts/label-policy-check.js +++ b/.github/scripts/label-policy-check.js @@ -1,6 +1,6 @@ export const POLICY = { priorities: ["P0", "P1", "P2", "P3"], - types: ["bug", "enhancement", "task", "documentation", "tech-debt"], + types: ["bug", "enhancement", "task", "documentation"], routing: ["app", "ui", "platform", "harness", "ci"], issueForbiddenLabels: ["dependencies", "github_actions", "javascript"], } @@ -37,11 +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)) + 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 5a2b81d24..4ea017a00 100644 --- a/.github/scripts/label-policy-check.test.js +++ b/.github/scripts/label-policy-check.test.js @@ -10,7 +10,7 @@ function messages(result) { test("accepts a valid issue label set", () => { const result = validateLabelPolicy({ itemType: "issue", - labels: ["tech-debt", "P2", "app"], + labels: ["task", "P2", "app", "tech-debt"], }) assert.deepEqual(result.errors, []) @@ -50,7 +50,7 @@ test("treats missing labels input as an empty label set", () => { assert.deepEqual(messages(result), [ "issue must have exactly one priority label: P0, P1, P2, or P3", - "issue must have exactly one type label: bug, enhancement, task, documentation, or tech-debt", + "issue must have exactly one type label: bug, enhancement, task, or documentation", "issue must have at least one primary routing label: app, ui, platform, harness, or ci", ]) }) @@ -71,7 +71,7 @@ test("rejects missing type labels", () => { }) assert.deepEqual(messages(result), [ - "pull_request must have exactly one type label: bug, enhancement, task, documentation, or tech-debt", + "pull_request must have exactly one type label: bug, enhancement, task, or documentation", ]) }) @@ -82,7 +82,7 @@ test("rejects multiple type labels", () => { }) assert.deepEqual(messages(result), [ - "issue must have exactly one type label: bug, enhancement, task, documentation, or tech-debt", + "issue must have exactly one type label: bug, enhancement, task, or documentation", ]) }) @@ -97,10 +97,10 @@ test("rejects missing primary routing labels", () => { ]) }) -test("accepts tech-debt as a primary type label", () => { +test("accepts tech-debt as a supplemental label with any primary type", () => { const result = validateLabelPolicy({ itemType: "issue", - labels: ["tech-debt", "P2", "app"], + labels: ["bug", "P2", "app", "tech-debt"], }) assert.deepEqual(result.errors, []) @@ -125,7 +125,7 @@ test("reports all independent label policy failures", () => { assert.deepEqual(messages(result), [ "issue must have exactly one priority label: P0, P1, P2, or P3", - "issue must have exactly one type label: bug, enhancement, task, documentation, or tech-debt", + "issue must have exactly one type label: bug, enhancement, task, or documentation", "issue must have at least one primary routing label: app, ui, platform, harness, or ci", "issue must not use PR automation labels: dependencies, github_actions, or javascript", ]) From 5fa5573c0302e64bb5e86ae557613d3d782ee8eb Mon Sep 17 00:00:00 2001 From: Yuhan Lei Date: Thu, 21 May 2026 14:34:49 +0800 Subject: [PATCH 3/3] docs(github): use label names in task template --- .github/ISSUE_TEMPLATE/03-task.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/03-task.yml b/.github/ISSUE_TEMPLATE/03-task.yml index ffa063a13..5c24b8110 100644 --- a/.github/ISSUE_TEMPLATE/03-task.yml +++ b/.github/ISSUE_TEMPLATE/03-task.yml @@ -10,10 +10,10 @@ body: 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 report - - A user-facing workflow or capability should improve → Feature request - - Documentation, templates, policies, or written process should change → Documentation - - Internal cleanup, maintainability, architecture, test, or quality debt → Tech debt + - 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