From fecae3241faf5df44af7c0f696ae9149ca0bc12c Mon Sep 17 00:00:00 2001 From: alexbelgium Date: Thu, 23 Jul 2026 14:52:42 +0200 Subject: [PATCH] chore: relabel handled issues so daily sweeps don't re-treat them MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Now that tier 2 runs daily instead of weekly, an issue left carrying ai-triage after a sweep would be re-selected and fully re-analysed the very next morning, before there's been a working day to review the first PR. Nothing previously dropped issues out of the ai-triage backlog once handled. - issue-fix.md: new hard limit 6 — relabel every issue as the last action before moving to the next one. ai:fixed / ai:upstream / ai:needs-human replace ai-triage depending on outcome. - daily_ai_fix.yaml: pre-create the three replacement labels once, up front (Claude never has to improvise a color or retry a missing-label error — wasted turns multiplied by batch size). Add a "Guard against repeat processing" step, same belt-and-braces pattern as the existing forbidden- paths guard: force-relabel to ai:needs-human anything the batch still finds carrying ai-triage after the run, independent of whether Claude's own relabeling succeeded. Co-Authored-By: Claude Opus 4.8 --- .github/prompts/issue-fix.md | 28 ++++++++++++++++---- .github/workflows/daily_ai_fix.yaml | 40 +++++++++++++++++++++++++++++ 2 files changed, 63 insertions(+), 5 deletions(-) diff --git a/.github/prompts/issue-fix.md b/.github/prompts/issue-fix.md index 1fc0609fdb..fb16793984 100644 --- a/.github/prompts/issue-fix.md +++ b/.github/prompts/issue-fix.md @@ -24,6 +24,22 @@ anything that violates them gets blocked and flagged. 5. If the fix requires changing more than roughly 60 lines, or touching more than three files, stop. Post the analysis, open no pull request, and say plainly that the change is too large for an unattended fix. +6. **Relabel every issue before moving to the next one.** This sweep runs + daily over the same `ai-triage`-labelled backlog. An issue you have + already finished with must drop that label immediately — otherwise + tomorrow's sweep re-selects it, opens a second competing branch, and + burns another full read-the-source-and-fix pass on work that is already + done. Do this as your last action on the issue, right after commenting, + not batched at the end: `gh issue edit --remove-label ai-triage + --add-label `, where `` is exactly one of: + - `ai:fixed` — you opened a draft pull request for it. + - `ai:upstream` — you reversed tier 1's call and the fault is upstream, + so no pull request. + - `ai:needs-human` — too large for an unattended fix (rule 5), or you + found no fix and are reporting what you ruled out. + A workflow step checks this after you finish and force-corrects to + `ai:needs-human` for anything still carrying `ai-triage` — treat that as + a bug in your run, not a safety net to lean on. ## Per add-on, do this in order @@ -52,11 +68,13 @@ change. Add a `CHANGELOG.md` entry in the add-on's existing format. and line, what the change does, how you verified it (or an explicit statement that you could not verify it), and `Closes #`. -**6. Comment on the issue.** Root cause, the fix in one or two sentences, and -the pull request link. Plain language — the reader is a Home Assistant user, -not a Go developer. If you found no fix, say what you ruled out and what you -would need to go further. Close with a note that this is automated analysis -pending Alex's review. +**6. Comment on the issue, then relabel it (hard limit 6).** Root cause, the +fix in one or two sentences, and the pull request link. Plain language — the +reader is a Home Assistant user, not a Go developer. If you found no fix, say +what you ruled out and what you would need to go further. Close with a note +that this is automated analysis pending Alex's review. Then remove +`ai-triage` and add the one replacement label that matches the outcome, +before starting the next issue. ## Meta-findings diff --git a/.github/workflows/daily_ai_fix.yaml b/.github/workflows/daily_ai_fix.yaml index cde49ea6a9..3a47b3ab4e 100644 --- a/.github/workflows/daily_ai_fix.yaml +++ b/.github/workflows/daily_ai_fix.yaml @@ -77,6 +77,20 @@ jobs: git config user.name "claude-ai-fix[bot]" git config user.email "claude-ai-fix[bot]@users.noreply.github.com" + # Created up front so issue-fix.md's per-issue relabel never has to + # improvise a color or retry a "label does not exist" error — that's a + # wasted turn multiplied by every issue in the batch. + - name: Ensure relabel targets exist + if: steps.batch.outputs.count != '0' + env: + GH_TOKEN: ${{ secrets.AI_PR_TOKEN }} + REPO: ${{ github.repository }} + run: | + set -euo pipefail + for l in ai:fixed ai:upstream ai:needs-human; do + gh label create "$l" --repo "$REPO" --color ededed --force >/dev/null 2>&1 || true + done + - name: Analyse and fix if: steps.batch.outputs.count != '0' uses: anthropics/claude-code-action@v1 @@ -94,6 +108,32 @@ jobs: env: GH_TOKEN: ${{ secrets.AI_PR_TOKEN }} + # Belt and braces. issue-fix.md instructs Claude to drop the ai-triage + # label off every issue it finishes with (hard limit 6), so tomorrow's + # sweep never re-selects and re-spends a full read-and-fix pass on + # work that's already done. Enforce it here in case a turn or timeout + # budget runs out before the relabel step of the last issue or two. + - name: Guard against repeat processing + if: always() && steps.batch.outputs.count != '0' + env: + GH_TOKEN: ${{ secrets.AI_PR_TOKEN }} + REPO: ${{ github.repository }} + run: | + set -euo pipefail + mapfile -t ISSUES < <(jq -r '.[].number' /tmp/ai-fix/batch.json) + for n in "${ISSUES[@]}"; do + STILL=$(gh issue view "$n" --repo "$REPO" --json labels \ + --jq '[.labels[].name] | index("ai-triage") != null' 2>/dev/null) || { + echo "::warning::could not re-check issue #$n (deleted or transferred?), skipping" + continue + } + if [ "$STILL" = "true" ]; then + echo "::warning::issue #$n still carries ai-triage after the sweep, forcing it out of tomorrow's batch" + gh issue edit "$n" --repo "$REPO" \ + --remove-label ai-triage --add-label ai:needs-human + fi + done + # Belt and braces. The prompt forbids these paths; this enforces it. - name: Guard forbidden paths if: always() && steps.batch.outputs.count != '0'