From ff563eef0f53b2aac66e70845895c5f8140c19c8 Mon Sep 17 00:00:00 2001 From: Tak Hoffman <781889+Takhoffman@users.noreply.github.com> Date: Sun, 1 Mar 2026 09:20:57 -0600 Subject: [PATCH] Issues: unify bug form and subtype auto-labeling (openclaw#30733) thanks @Takhoffman Verified: - pnpm build - pnpm check - pnpm test:macmini Co-authored-by: Takhoffman <781889+Takhoffman@users.noreply.github.com> --- .github/ISSUE_TEMPLATE/bug_report.yml | 18 ++- .../ISSUE_TEMPLATE/regression_bug_report.yml | 115 ------------------ .github/workflows/auto-response.yml | 112 +++++++++++++++++ CHANGELOG.md | 1 + 4 files changed, 127 insertions(+), 119 deletions(-) delete mode 100644 .github/ISSUE_TEMPLATE/regression_bug_report.yml diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml index 38771318a80..c45885b48b6 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.yml +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -1,5 +1,5 @@ name: Bug report -description: Report a non-regression defect or unexpected behavior in OpenClaw. +description: Report defects, including regressions, crashes, and behavior bugs. title: "[Bug]: " labels: - bug @@ -8,7 +8,17 @@ body: attributes: value: | Thanks for filing this report. Keep it concise, reproducible, and evidence-based. - If this behavior worked previously and now fails, use the "Regression bug report" template instead. + - type: dropdown + id: bug_type + attributes: + label: Bug type + description: Choose the category that best matches this report. + options: + - Regression (worked before, now fails) + - Crash (process/app exits or hangs) + - Behavior bug (incorrect output/state without crash) + validations: + required: true - type: textarea id: summary attributes: @@ -92,5 +102,5 @@ body: id: additional_information attributes: label: Additional information - description: Add any context that helps triage but does not fit above. - placeholder: Regression started after upgrade from ; temporary workaround is ... + description: Add any context that helps triage but does not fit above. If this is a regression, include the last known good and first known bad versions. + placeholder: Last known good version <...>, first known bad version <...>, temporary workaround is ... diff --git a/.github/ISSUE_TEMPLATE/regression_bug_report.yml b/.github/ISSUE_TEMPLATE/regression_bug_report.yml deleted file mode 100644 index 4b7e73c1c6c..00000000000 --- a/.github/ISSUE_TEMPLATE/regression_bug_report.yml +++ /dev/null @@ -1,115 +0,0 @@ -name: Regression bug report -description: Report behavior that worked previously and now fails in OpenClaw. -title: "[Regression Bug]: " -labels: - - bug - - regression -body: - - type: markdown - attributes: - value: | - Use this form only for regressions: behavior that previously worked and now fails. - Keep reports concise, reproducible, and evidence-based. - - type: textarea - id: summary - attributes: - label: Summary - description: One-sentence statement of what regressed. - placeholder: Replies in Slack threads worked in but fail in . - validations: - required: true - - type: input - id: last_known_good_version - attributes: - label: Last known good version - description: Exact version/build where behavior still worked. - placeholder: - validations: - required: true - - type: input - id: first_bad_version - attributes: - label: First known bad version - description: Exact version/build where behavior first failed. - placeholder: - validations: - required: true - - type: textarea - id: regression_window - attributes: - label: Regression window and trigger - description: Describe when this started and what changed around that time. - placeholder: Started after upgrading from to ; no config changes. - validations: - required: true - - type: textarea - id: repro - attributes: - label: Steps to reproduce - description: Provide the shortest deterministic repro path. - placeholder: | - 1. Configure channel X. - 2. Send message Y. - 3. Run command Z. - validations: - required: true - - type: textarea - id: expected - attributes: - label: Expected behavior - description: What should happen if the regression does not exist. - placeholder: Agent posts a reply in the same thread. - validations: - required: true - - type: textarea - id: actual - attributes: - label: Actual behavior - description: What happens now, including user-visible errors. - placeholder: No reply is posted; gateway logs "reply target not found". - validations: - required: true - - type: input - id: os - attributes: - label: Operating system - description: OS and version where this occurs. - placeholder: macOS 15.4 / Ubuntu 24.04 / Windows 11 - validations: - required: true - - type: input - id: install_method - attributes: - label: Install method - description: How OpenClaw was installed or launched. - placeholder: npm global / pnpm dev / docker / mac app - - type: textarea - id: logs - attributes: - label: Logs, screenshots, and evidence - description: Include redacted logs/screenshots/recordings that prove the regression. - render: shell - - type: textarea - id: impact - attributes: - label: Impact and severity - description: | - Explain who is affected, how severe it is, how often it happens, and the practical consequence. - Include: - - Affected users/systems/channels - - Severity (annoying, blocks workflow, data risk, etc.) - - Frequency (always/intermittent/edge case) - - Consequence (missed messages, failed onboarding, extra cost, etc.) - placeholder: | - Affected: Telegram group users on - Severity: High (blocks replies) - Frequency: 100% repro - Consequence: Agents cannot respond in threads - validations: - required: true - - type: textarea - id: additional_information - attributes: - label: Additional information - description: Add any context that helps triage but does not fit above. - placeholder: Temporary workaround is rolling back to . diff --git a/.github/workflows/auto-response.yml b/.github/workflows/auto-response.yml index d18b0d776ea..4a572db52e6 100644 --- a/.github/workflows/auto-response.yml +++ b/.github/workflows/auto-response.yml @@ -77,6 +77,116 @@ jobs: const mentionRegex = /@([A-Za-z0-9-]+)/g; const maintainerCache = new Map(); const normalizeLogin = (login) => login.toLowerCase(); + const bugSubtypeLabelSpecs = { + regression: { + color: "D93F0B", + description: "Behavior that previously worked and now fails", + }, + "bug:crash": { + color: "B60205", + description: "Process/app exits unexpectedly or hangs", + }, + "bug:behavior": { + color: "D73A4A", + description: "Incorrect behavior without a crash", + }, + }; + const bugTypeToLabel = { + "Regression (worked before, now fails)": "regression", + "Crash (process/app exits or hangs)": "bug:crash", + "Behavior bug (incorrect output/state without crash)": "bug:behavior", + }; + const bugSubtypeLabels = Object.keys(bugSubtypeLabelSpecs); + + const extractIssueFormValue = (body, field) => { + if (!body) { + return ""; + } + const escapedField = field.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"); + const regex = new RegExp( + `(?:^|\\n)###\\s+${escapedField}\\s*\\n([\\s\\S]*?)(?=\\n###\\s+|$)`, + "i", + ); + const match = body.match(regex); + if (!match) { + return ""; + } + for (const line of match[1].split("\n")) { + const trimmed = line.trim(); + if (trimmed) { + return trimmed; + } + } + return ""; + }; + + const ensureLabelExists = async (name, color, description) => { + try { + await github.rest.issues.getLabel({ + owner: context.repo.owner, + repo: context.repo.repo, + name, + }); + } catch (error) { + if (error?.status !== 404) { + throw error; + } + await github.rest.issues.createLabel({ + owner: context.repo.owner, + repo: context.repo.repo, + name, + color, + description, + }); + } + }; + + const syncBugSubtypeLabel = async (issue, labelSet) => { + if (!labelSet.has("bug")) { + return; + } + + const selectedBugType = extractIssueFormValue(issue.body ?? "", "Bug type"); + const targetLabel = bugTypeToLabel[selectedBugType]; + if (!targetLabel) { + return; + } + + const targetSpec = bugSubtypeLabelSpecs[targetLabel]; + await ensureLabelExists(targetLabel, targetSpec.color, targetSpec.description); + + for (const subtypeLabel of bugSubtypeLabels) { + if (subtypeLabel === targetLabel) { + continue; + } + if (!labelSet.has(subtypeLabel)) { + continue; + } + try { + await github.rest.issues.removeLabel({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: issue.number, + name: subtypeLabel, + }); + labelSet.delete(subtypeLabel); + } catch (error) { + if (error?.status !== 404) { + throw error; + } + } + } + + if (!labelSet.has(targetLabel)) { + await github.rest.issues.addLabels({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: issue.number, + labels: [targetLabel], + }); + labelSet.add(targetLabel); + } + }; const isMaintainer = async (login) => { if (!login) { @@ -201,6 +311,8 @@ jobs: body: pingWarningMessage, }); } + + await syncBugSubtypeLabel(issue, labelSet); } } diff --git a/CHANGELOG.md b/CHANGELOG.md index bb2da06a44d..0eb558c814b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -105,6 +105,7 @@ Docs: https://docs.openclaw.ai - Podman/Quadlet setup: fix `sed` escaping and UID mismatch in Podman Quadlet setup. (#26414) Thanks @KnHack and @vincentkoc. - Browser/Navigate: resolve the correct `targetId` in navigate responses after renderer swaps. (#25326) Thanks @stone-jin and @vincentkoc. - Agents/Ollama discovery: skip Ollama discovery when explicit models are configured. (#28827) Thanks @Kansodata and @vincentkoc. +- Issues/triage labeling: consolidate bug intake to a single bug issue form with required bug-type classification (regression/crash/behavior), auto-apply matching subtype labels from issue form content, and retire the separate regression template to reduce misfiled issue types and improve queue filtering. Thanks @vincentkoc. - Android/Onboarding + voice reliability: request per-toggle onboarding permissions, update pairing guidance to `openclaw devices list/approve`, restore assistant speech playback in mic capture flow, cancel superseded in-flight speech (mute + per-reply token rotation), and keep `talk.config` loads retryable after transient failures. (#29796) Thanks @obviyus. - FS/Sandbox workspace boundaries: add a dedicated `outside-workspace` safe-open error code for root-escape checks, and propagate specific outside-workspace messages across edit/browser/media consumers instead of generic not-found/invalid-path fallbacks. (#29715) Thanks @YuzuruS. - Config/Doctor group allowlist diagnostics: align `groupPolicy: "allowlist"` warnings with per-channel runtime semantics by excluding Google Chat sender-list checks and by warning when no-fallback channels (for example iMessage) omit `groupAllowFrom`, with regression coverage. (#28477) Thanks @tonydehnke.