diff --git a/.github/workflows/duplicate-issues.yml b/.github/workflows/issue-compliance.yml similarity index 82% rename from .github/workflows/duplicate-issues.yml rename to .github/workflows/issue-compliance.yml index 3b49b73..e29cd1e 100644 --- a/.github/workflows/duplicate-issues.yml +++ b/.github/workflows/issue-compliance.yml @@ -1,4 +1,4 @@ -name: Duplicate Issue Check +name: Issue Compliance Check on: issues: @@ -12,7 +12,7 @@ env: MODEL: z-ai/glm-5.1 jobs: - check-duplicates: + check-compliance: if: github.repository == 'zhom/donutbrowser' && github.event.action == 'opened' runs-on: ubuntu-latest steps: @@ -21,29 +21,16 @@ jobs: - name: Gather context env: - GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - ISSUE_NUMBER: ${{ github.event.issue.number }} ISSUE_TITLE: ${{ github.event.issue.title }} ISSUE_BODY: ${{ github.event.issue.body }} run: | printf '%s' "$ISSUE_TITLE" > /tmp/issue-title.txt printf '%s' "${ISSUE_BODY:-}" > /tmp/issue-body.txt - # Pull up to 150 open/closed issues for the LLM to compare against. - # Exclude the issue under inspection and any PRs (gh issue list does - # this naturally). - gh issue list \ - --repo "$GITHUB_REPOSITORY" \ - --state all \ - --limit 150 \ - --json number,title,state,body \ - --jq "[.[] | select(.number != $ISSUE_NUMBER) | {number, title, state, body: (.body[:400] // \"\")}]" \ - > /tmp/existing-issues.json - - name: Build prompt run: | cat > /tmp/system.txt <<'PROMPT' - You are reviewing a new GitHub issue for two things — template compliance and possible duplicates. Return ONLY a single JSON object, no prose, no markdown fences. + You are reviewing a new GitHub issue for template compliance. Return ONLY a single JSON object, no prose, no markdown fences. Project: Donut Browser. There are three valid templates: - Bug Report (Description + Operating System + Donut Browser version + Which browser is affected + Steps to reproduce + Error logs/screenshots fields) @@ -59,22 +46,14 @@ jobs: Do NOT flag for missing optional fields, missing screenshots, short titles, or stylistic issues. Be conservative. - ## Duplicates — flag candidates ONLY when at least one of these is true - - Same error message, exception, or symptom - - Same feature being requested - - Same root cause area (e.g. "proxy disconnects on Camoufox/Windows") - - Prefer false negatives over false positives. Two issues about Wayfern are not duplicates if they are about different features. - ## Output schema { "is_compliant": true | false, - "non_compliance_reasons": ["short bullet", ...], - "duplicates": [{"number": 123, "reason": "short reason"}] + "non_compliance_reasons": ["short bullet", ...] } - Empty arrays are fine. If there is nothing to flag, return: - {"is_compliant": true, "non_compliance_reasons": [], "duplicates": []} + If there is nothing to flag, return: + {"is_compliant": true, "non_compliance_reasons": []} PROMPT - name: Call OpenRouter @@ -86,13 +65,12 @@ jobs: --rawfile system_prompt /tmp/system.txt \ --rawfile title /tmp/issue-title.txt \ --rawfile body /tmp/issue-body.txt \ - --rawfile existing /tmp/existing-issues.json \ '{ model: $model, messages: [ { role: "system", content: $system_prompt }, { role: "user", - content: ("New issue title: " + $title + "\n\nNew issue body:\n" + $body + "\n\nExisting issues (JSON array):\n" + $existing) } + content: ("New issue title: " + $title + "\n\nNew issue body:\n" + $body) } ], response_format: { type: "json_object" } }') @@ -108,9 +86,9 @@ jobs: # to a noop result so the workflow doesn't fail the issue author's run. sed -E 's/^```(json)?$//; s/```$//' /tmp/raw.txt > /tmp/result.json if ! jq -e . /tmp/result.json >/dev/null 2>&1; then - echo "::warning::Model returned non-JSON; treating as no-op" + echo "::warning::Model returned non-JSON; treating as compliant" cat /tmp/raw.txt - echo '{"is_compliant": true, "non_compliance_reasons": [], "duplicates": []}' > /tmp/result.json + echo '{"is_compliant": true, "non_compliance_reasons": []}' > /tmp/result.json fi echo "Result:" cat /tmp/result.json @@ -122,7 +100,6 @@ jobs: r = json.load(open('/tmp/result.json')) compliant = bool(r.get('is_compliant', True)) reasons = r.get('non_compliance_reasons') or [] - dups = r.get('duplicates') or [] parts = [] if not compliant: @@ -134,25 +111,11 @@ jobs: parts.append(f'- {reason}') parts.append('') parts.append('Please edit this issue to address the above within **24 hours**, or it will be automatically closed.') - - if dups: - if parts: - parts.append('') - parts.append('---') - parts.append('This issue might duplicate existing reports. Please check:') - for d in dups: - num = d.get('number') - reason = d.get('reason', '').strip() - if num: - parts.append(f'- #{num}{" — " + reason if reason else ""}') - - if not compliant: parts.append('') parts.append('If you believe this was flagged incorrectly, please let a maintainer know.') comment = '\n'.join(parts).strip() open('/tmp/comment.md', 'w').write(comment) - # Expose flags for downstream steps via GITHUB_OUTPUT-style write. with open(os.environ['GITHUB_OUTPUT'], 'a') as fh: fh.write(f'has_comment={"true" if comment else "false"}\n') fh.write(f'non_compliant={"true" if not compliant else "false"}\n') diff --git a/.github/workflows/issue-validation.yml b/.github/workflows/issue-validation.yml index afcc86a..76aba44 100644 --- a/.github/workflows/issue-validation.yml +++ b/.github/workflows/issue-validation.yml @@ -102,12 +102,14 @@ jobs: its API, MCP server, and the bundled `donut-sync` self-hosted server. - **Wayfern** — a Chromium fork maintained by zhom (the same maintainer). Wayfern bugs are in-scope here unless they are obviously upstream Chromium issues. - - **Camoufox** — a Firefox fork by daijro. The maintainer of THIS repo does NOT - contribute to Camoufox and CANNOT fix bugs in it. + - **Camoufox** — a Firefox fork by daijro, used by Donut but maintained in a + separate repository. Bugs about Camoufox's *internal* behavior are outside + the scope of this project. - Bugs about Camoufox's *internal* behavior (page rendering, JS engine, dropdowns, form widgets, fingerprinting *as Camoufox implements it*, - checkbox/radio quirks) are UPSTREAM ONLY. Redirect to - https://github.com/daijro/camoufox/issues. + checkbox/radio quirks) are out of scope here. Ask the user to first + search https://github.com/daijro/camoufox/issues for a matching report, + and if they don't find one, to open it there themselves. - Bugs about how Donut *launches, configures, or downloads* Camoufox are in-scope here. - **Forks of Wayfern or Camoufox** (e.g. CloverLabsAI, VulpineOS) are NOT @@ -146,7 +148,10 @@ jobs: dismiss as "known issue" / "expected" / "false positive in Tauri apps". Ask which exact version was the last working one and what changed. - **Out-of-scope (upstream Camoufox)**: report is about Camoufox's own - behavior. Redirect, do not collect logs. + behavior. Tell the user it's outside the scope of this project and ask + them to search the Camoufox repo and, if no matching issue exists, file + one there. Do NOT say the maintainer doesn't contribute / can't fix it + — keep it strictly about project scope. Do not collect logs. - **Fork-support request**: asks the maintainer to support an alternative Wayfern/Camoufox fork. Acknowledge in one neutral sentence — do NOT call it "clear", "reasonable", "well-thought-out", etc. @@ -342,7 +347,7 @@ jobs: The triage classification (`triage.classification`) determines the response shape: - `bug-in-scope`: ask for what is missing using the user's reported OS log path. Be concrete about how to obtain logs. - - `bug-upstream-camoufox`: redirect ONLY. One sentence acknowledging, then a sentence saying this is a Camoufox-internal issue and the maintainer of this repo does not contribute to Camoufox; ask the user to file at https://github.com/daijro/camoufox/issues. Do NOT ask for Donut logs. Stop after that. + - `bug-upstream-camoufox`: redirect ONLY. One sentence acknowledging, then say this is outside the scope of this project — ask the user to first search https://github.com/daijro/camoufox/issues for a matching report and, if none exists, to open one there themselves. Do NOT phrase it as "the maintainer does not contribute" or anything personal — keep it strictly about scope. Do NOT ask for Donut logs. Stop after that. - `bug-template-violation` or `ai-generated-junk`: politely ask the user to refile using the bug-report template (the Operating System, Donut Browser version, Which browser, Steps to reproduce, Error logs sections). If they cited "documentation" from any non-`donutbrowser.com`/non-`github.com/zhom` URL (e.g. context7, deepwiki), gently note that those are AI-generated third-party summaries and the only authoritative sources are this repo and donutbrowser.com. - `feature-request`: one neutral sentence acknowledging, then ask only what is genuinely needed (concrete use case, whether a workaround would suffice). Do NOT validate. - `fork-request`: one neutral sentence acknowledging the request. Note that this would substantially increase support burden and the maintainer evaluates such requests on a case-by-case basis. Ask whether the alternative fork supports all platforms the user uses (macOS / Windows / Linux). No "clear enhancement" language.