Skip to content

ci: stale-PR automation — bestaxbot closer + generic stale (#275) - #279

Merged
allxsmith merged 8 commits into
mainfrom
ci/stale-automation
Jul 11, 2026
Merged

allxsmith merged 8 commits into
mainfrom
ci/stale-automation

Conversation

@allxsmith

@allxsmith allxsmith commented Jul 10, 2026 •

Copy link
Copy Markdown
Owner

Pull Request

Description

Two new zero-Claude workflows for stale-PR hygiene, mirroring oven-sh/bun's close-stale-robobun-prs.yml and stale.yaml:

  • .github/workflows/close-stale-bestaxbot-prs.yml — daily cron (41 3 * * *, deliberately offset from the loop watchdog's 23 */2 * * *) plus workflow_dispatch. Plain shell + gh: lists open bestaxbot PRs, filters updatedAt older than 90 days via a date -u -d '90 days ago' cutoff and jq select(.updatedAt < $cutoff), comments, strips the loop labels (ai-loop / ai-loop-paused / needs-human-review) before closing — the on-slop.yml pattern — so the PR exits the loop state machine cleanly, then closes.
  • .github/workflows/stale.yml — actions/stale pinned by full commit SHA (5bef64f19d7facfb25b37b414482c7164d639639 # v9.1.0). PRs go stale after 30 days, close 14 days later; neverstale exempts; any activity resets the clock (remove-stale-when-updated: true). Issues are deliberately disabled (days-before-issue-stale/close: -1) — a deviation from bun, whose issue side keys off a needs-repro/waiting-for-author triage process this repo doesn't run. Daily cron 17 4 * * *, distinct from both other crons, plus workflow_dispatch.

Both follow house style: header comment block, workflow-level permissions: {}, per-job least privilege (pull-requests: write, issues: write), set -euo pipefail, timeout-minutes.

Docs in the same PR: two rows in the label table in docs/docs/guides/getting-started/ai-development.md (stale, neverstale) and one sentence in root CLAUDE.md's "AI development loop" section.

  • bulma-ui (@allxsmith/bestax-bulma)
  • create-bestax (create-bestax)
  • docs (@allxsmith/bestax-docs)
  • Other (please specify): repo tooling (.github/workflows/) + docs

Related Issue(s)

Closes #275

Type of Change

  • Bug fix
  • New feature
  • Refactor
  • Documentation
  • Performance
  • Build tooling
  • Other (please describe):

Checklist

  • My code follows the project style guidelines
  • I have performed a self-review of my code
  • I have added tests that prove my fix is effective or that my feature works (n/a — workflow YAML; both files validated with a YAML parser and the jq/date filter logic exercised locally)
  • I have added/updated documentation as needed
  • I have updated Storybook stories as needed (bulma-ui) (n/a)
  • My changes require a change to the documentation
  • All new and existing tests passed (no code paths touched; prettier --check passes on the changed markdown)
  • Any relevant dependencies are updated (n/a)
  • If this PR changes commands, conventions, or package structure, the affected CLAUDE.md files are updated

Screenshots / Demos

n/a

Additional Context

Part 4 of 4 alongside #272 / #273 / #274 — all four touch the same label table in ai-development.md, so trivial merge conflicts there are expected and easy to resolve.

actions/stale pin verification: resolved via git ls-remote https://github.com/actions/stale.git 'refs/tags/v9*'. The tags are lightweight (no peeled ^{} entries), so the listed SHAs are the commit SHAs directly. Highest stable v9 tag is v9.1.0 → 5bef64f19d7facfb25b37b414482c7164d639639 (also what the floating v9 tag points at). Reviewers can re-run the same command to verify.

neverstale also exempts bestaxbot PRs from the 90-day closer (the jq filter skips PRs carrying the label), so the label's documented meaning — exempt from stale automation — holds across both layers.

Label rollout note: stale auto-creates on first application (suggested color #ededed); neverstale (#c2e0c6) is human-applied and should be created at rollout.

The prettier hook re-padded the existing label-table rows (whitespace-only column alignment) — no wording changes to sibling rows.

🤖 Generated with Claude Code

https://claude.ai/code/session_01Pohc8xLkdx4gwXkW3xd7up

Summary by CodeRabbit

  • New Features
    • Added automated PR stale handling: PRs become stale after 30 days of inactivity and are closed 14 days later if no activity resumes.
    • Added a separate long-inactivity closer for claude-assisted/bestaxbot PRs after 90+ days, with neverstale fully exempt; the closer posts closure guidance and clears AI-loop-related labels.
  • Bug Fixes
    • Issues are excluded from stale/close automation.
  • Documentation
    • Updated CLAUDE.md and AI development docs to document stale, neverstale, and Claude-assisted timing/exemptions.

@coderabbitai

coderabbitai Bot commented Jul 10, 2026 •

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 4e323d0e-8e12-4cee-9225-f6481e8f8ec3

📥 Commits

Reviewing files that changed from the base of the PR and between 7f7b60a and d4ffd23.

📒 Files selected for processing (3)
  • .github/workflows/close-stale-bestaxbot-prs.yml
  • CLAUDE.md
  • docs/docs/guides/getting-started/ai-development.md
✅ Files skipped from review due to trivial changes (1)
  • CLAUDE.md
🚧 Files skipped from review as they are similar to previous changes (2)
  • docs/docs/guides/getting-started/ai-development.md
  • .github/workflows/close-stale-bestaxbot-prs.yml

Walkthrough

Adds scheduled and manually triggered workflows that close inactive bestaxbot or Claude-assisted PRs after 90 days and manage general pull-request staleness after 30 days plus a 14-day closure period. Documentation describes these timings and the stale and neverstale labels.

Changes

Stale pull request automation

Layer / File(s) Summary
Bestaxbot stale PR closure
.github/workflows/close-stale-bestaxbot-prs.yml
Backfills claude-assisted, selects eligible PRs inactive for 90 days, re-checks them, posts closure guidance, removes AI-loop labels, and closes them.
General stale PR lifecycle
.github/workflows/stale.yml
Marks inactive PRs stale after 30 days and closes them 14 days later, while honoring neverstale, excluding Claude-assisted PRs, and disabling issue processing.
Stale policy documentation
CLAUDE.md, docs/docs/guides/getting-started/ai-development.md
Documents stale timing rules and the stale and neverstale label lifecycle.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Scheduler
  participant StaleWorkflow
  participant GitHub
  Scheduler->>StaleWorkflow: trigger scheduled or manual run
  StaleWorkflow->>GitHub: identify inactive pull requests
  StaleWorkflow->>GitHub: apply stale labels or close eligible PRs
Loading

Possibly related issues

  • allxsmith/bestax issue 275 — Directly covers the stale-PR automation and documentation implemented here.
  • allxsmith/bestax issue 272 — Covers the claude-assisted labeling behavior extended by this automation.

Possibly related PRs

  • allxsmith/bestax#229 — Adds related closure automation using the same AI-loop state labels.
  • allxsmith/bestax#231 — Makes PRs authored by bestaxbot, which is directly targeted by the 90-day closer.
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly summarizes the main change: new stale-PR automation workflows for bestaxbot and generic stale handling.
Description check ✅ Passed The description mostly matches the template, naming affected areas, linked issue, change type, checklist, and extra context.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch ci/stale-automation

Comment @coderabbitai help to get the list of available commands.

@github-actions

Copy link
Copy Markdown
Contributor

Preview Deployment

Preview URL: https://7d20799c.bestax.pages.dev

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @.github/workflows/close-stale-bestaxbot-prs.yml:
- Around line 12-17: Add a workflow-level concurrency group to the closer
workflow identified by its `on` schedule and `workflow_dispatch` triggers, using
a stable group name and cancel-in-progress behavior that prevents overlapping
runs, including manual dispatches. If serialization with the loop watchdog is
required, configure both workflows to use the same concurrency group naming
scheme.
- Around line 47-54: Remove the `|| true` from the `gh pr edit` cleanup command
in the stale PR-closing workflow. Ensure label removal failures stop execution
so `gh pr close` is not called, keeping the PR open when cleanup encounters
authentication, API, or network errors.
- Around line 39-43: Increase the result limit for the gh pr list invocation in
the stale PR processing pipeline by adding --limit 1000 (or another sufficiently
high bound), ensuring all stale bestaxbot PRs are considered rather than only
the default 30.

In @.github/workflows/stale.yml:
- Around line 39-42: Update the stale workflow configuration to exempt
bestaxbot-authored PRs from actions/stale, either by adding the supported
bestaxbot-specific exemption or by ensuring the bot workflow automatically
applies the neverstale label before this sweep. Preserve the existing 30-day
stale and 14-day close settings for other PRs.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 2a000ce6-0135-4fa3-a4f6-fc72b4dfc62b

📥 Commits

Reviewing files that changed from the base of the PR and between 306e3cb and fa03c1a.

📒 Files selected for processing (4)
  • .github/workflows/close-stale-bestaxbot-prs.yml
  • .github/workflows/stale.yml
  • CLAUDE.md
  • docs/docs/guides/getting-started/ai-development.md

Comment on lines +12 to +17
on:
schedule:
# 03:41 UTC daily — deliberately offset from the loop watchdog's
# `23 */2 * * *` so the closer never races a sweep re-dispatch.
- cron: '41 3 * * *'
workflow_dispatch:

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '\n## File list\n'
git ls-files '.github/workflows/*' | sed 's#^`#-` #'

printf '\n## Target workflow\n'
wc -l .github/workflows/close-stale-bestaxbot-prs.yml
cat -n .github/workflows/close-stale-bestaxbot-prs.yml

printf '\n## Search for concurrency and watchdog references\n'
rg -n "concurrency|23 \\*/2 \\* \\* \\*|close-stale|bestaxbot|watchdog|re-dispatch" .github/workflows

Repository: allxsmith/bestax

Length of output: 9279


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '\n## claude-pr-loop relevant sections\n'
sed -n '1,120p' .github/workflows/claude-pr-loop.yml

printf '\n## on-slop relevant sections\n'
sed -n '1,90p' .github/workflows/on-slop.yml

Repository: allxsmith/bestax

Length of output: 8538


Add a concurrency group to the closer workflow. The cron offset doesn’t prevent overlap with manual dispatches or another in-flight run, so duplicate comments and competing label/close operations can still happen. If this needs to serialize with the watchdog too, use the same group naming scheme there.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/close-stale-bestaxbot-prs.yml around lines 12 - 17, Add a
workflow-level concurrency group to the closer workflow identified by its `on`
schedule and `workflow_dispatch` triggers, using a stable group name and
cancel-in-progress behavior that prevents overlapping runs, including manual
dispatches. If serialization with the loop watchdog is required, configure both
workflows to use the same concurrency group naming scheme.

Comment thread .github/workflows/close-stale-bestaxbot-prs.yml Outdated
Comment thread .github/workflows/close-stale-bestaxbot-prs.yml
Comment thread .github/workflows/stale.yml Outdated
@github-actions

Copy link
Copy Markdown
Contributor

Preview Deployment

Preview URL: https://6ca048c6.bestax.pages.dev

@allxsmith allxsmith added the deep-review label Jul 11, 2026 — with Claude

Copy link
Copy Markdown
Owner Author

@claude perform deep review


Generated by Claude Code

@claude

claude Bot commented Jul 11, 2026 •

Copy link
Copy Markdown

Claude encountered an error after 2m 46s —— View job


Deep review in progress

  • Gather context (diff, CodeRabbit findings, latest commit)
  • Review close-stale-bestaxbot-prs.yml
  • Review stale.yml
  • Review docs/CLAUDE.md changes
  • Verify fixes addressed in commit 21f4d75
  • Post final review

claude added 2 commits July 11, 2026 01:28
Two zero-Claude workflows mirroring oven-sh/bun: a daily closer for
bestaxbot PRs inactive 90+ days (strips loop labels before closing, per
the on-slop.yml pattern), and actions/stale (pinned to v9.1.0 by commit
SHA) marking PRs stale at 30 days and closing 14 days later, with a
neverstale exemption label. Issues are deliberately excluded from stale
processing. Docs: label table + CLAUDE.md note.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Pohc8xLkdx4gwXkW3xd7up
The neverstale label documents "exempts a PR from stale automation" —
that must include the 90-day bot sweep, not just the generic stale.yml
layer. Fetch labels in gh pr list and filter them out in jq.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Pohc8xLkdx4gwXkW3xd7up
@allxsmith
allxsmith force-pushed the ci/stale-automation branch from 21f4d75 to f49942a Compare July 11, 2026 01:28
@allxsmith allxsmith added deep-review and removed deep-review labels Jul 11, 2026 — with Claude
@github-actions

Copy link
Copy Markdown
Contributor

Preview Deployment

Preview URL: https://ba4a37ba.bestax.pages.dev

Comment thread .github/workflows/stale.yml Outdated
Comment on lines +39 to +42
days-before-pr-stale: 30
days-before-pr-close: 14
stale-pr-label: stale
exempt-pr-labels: neverstale

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Generic stale layer preempts the 90-day bestaxbot closer — 🟠 Major · Correctness

What: This workflow processes all open PRs (no exempt-authors), and bestaxbot PRs are not automatically given neverstale. So a bestaxbot PR that goes inactive is marked stale at 30 days and closed at 44 days (30 + 14). The dedicated close-stale-bestaxbot-prs.yml only fires at 90 days — 46 days after this workflow has already closed the PR.

Why it matters: The two files encode conflicting intents for the same PRs (44-day vs. 90-day leash), and the stricter one always wins. Consequences:

  • close-stale-bestaxbot-prs.yml is effectively dead — it can never reach a bot PR that has been inactive for 90 continuous days, because such a PR was closed at day 44.
  • The documented behavior is false: CLAUDE.md and ai-development.md now claim "bestaxbot PRs close after 90 days of inactivity," but they actually close at 44. The bot's 90-day close comment (and its loop-label stripping) never runs.

The dedicated closer strongly implies the intent was to give bot PRs a longer, gentler leash (the loop churns them). If so, this workflow must exclude bestaxbot as an author so the 90-day closer becomes the sole authority for bot PRs:

Suggested change
days-before-pr-stale: 30
days-before-pr-close: 14
stale-pr-label: stale
exempt-pr-labels: neverstale
days-before-pr-stale: 30
days-before-pr-close: 14
stale-pr-label: stale
exempt-pr-labels: neverstale
# bestaxbot-authored PRs are handled by close-stale-bestaxbot-prs.yml
# (90-day leash); excluding them here prevents this 44-day layer from
# closing them first and making that workflow unreachable.
exempt-authors: bestaxbot
Timeline of an inactive bestaxbot PR under the current config
gantt
    dateFormat X
    axisFormat %s
    title Inactive bestaxbot PR — days of inactivity
    section stale.yml (all PRs)
    marked `stale`      :milestone, 30, 0d
    CLOSED here         :crit, milestone, 44, 0d
    section close-stale-bestaxbot-prs.yml
    intended close (never reached) :done, milestone, 90, 0d
Loading

PR is gone at day 44; the 90-day bot closer never gets a turn.

If instead the intent is genuinely 44 days for everyone including the bot, then close-stale-bestaxbot-prs.yml and the "90 days" wording in CLAUDE.md/ai-development.md should be removed to avoid the contradiction.

@claude claude Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Deep review — 1 finding

# Severity Area Finding Location
1 🟠 Major Correctness Generic 30/14-day stale closer preempts the 90-day bestaxbot closer, making it unreachable and contradicting the documented "90 days" behavior .github/workflows/stale.yml:39-42

Overall: The change is well-structured and the security hardening is exemplary — permissions: {} at workflow level with narrow job grants, a SHA-pinned actions/stale, zero Claude/token spend, and deliberately offset crons. The one real issue is a layering conflict: stale.yml applies to all PRs with no exempt-authors, so bestaxbot PRs close at day 44, which means the dedicated 90-day close-stale-bestaxbot-prs.yml can never fire and the "bot PRs close after 90 days" wording in CLAUDE.md/ai-development.md is inaccurate. A human should decide the intended bot leash (44 vs. 90 days) and either add exempt-authors: bestaxbot to stale.yml or drop the redundant 90-day workflow + docs. Everything else — the neverstale exemption on both layers, loop-label stripping before close, docs table rows — is correct.

🏄 Clean set on the security barrels, dude — locked-down perms and pinned actions, no worries there. Only snag is two closers paddling for the same wave: the 30-day one drops in and closes out the 90-day bot ride before it ever stands up. Sort out who owns that break and it is all smooth cruising.

…90-day closer (#275)

Addresses the deep-review Major on PR #279: the generic stale.yml closed
every PR at day 44, so the dedicated 90-day bestaxbot closer could never
fire and the documented 90-day bot leash was inaccurate. actions/stale has
no author exemption, so the fix keys off the claude-assisted label that
auto-label-claude-prs.yml (PR #276) applies:

- stale.yml adds claude-assisted to exempt-pr-labels, so AI-assisted PRs
  skip the 30/14 sweep.
- close-stale-bestaxbot-prs.yml now sweeps the union of author:bestaxbot
  and label:claude-assisted (deduped), so labeled human-authored
  Claude-assisted PRs don't escape both layers, and pre-labeler bot PRs
  are still covered by the author query.
- CLAUDE.md and the docs label table describe the two-layer split.

Until #276 merges and labels new bot PRs, unlabeled bestaxbot PRs remain
under the generic 30/14 sweep — an acceptable transition state.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0142miDJt2AX9QUw5fNJt2xu
@github-actions

Copy link
Copy Markdown
Contributor

Preview Deployment

Preview URL: https://817d0932.bestax.pages.dev

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @.github/workflows/close-stale-bestaxbot-prs.yml:
- Around line 61-62: Update the jq filter in the stale PR workflow to use an
inclusive cutoff by changing the updatedAt comparison from < $cutoff to <=
$cutoff, preserving the existing unique_by, neverstale exclusion, and number
selection logic.
- Around line 8-14: Ensure unlabeled PRs authored by bestaxbot are exempted from
the generic stale workflow before its 30/14-day sweep, either by updating
stale.yml’s exemption logic to include author:bestaxbot or by reliably applying
the claude-assisted exemption label to those PRs before the sweep. Preserve the
dedicated 90-day handling in close-stale-bestaxbot-prs.yml.
- Around line 61-65: Revalidate each candidate PR immediately before side
effects in the stale-PR processing loop: use the GitHub CLI to fetch its current
updatedAt timestamp and labels, then skip it if it is no longer older than
CUTOFF or has the neverstale label. Only comment on and close the PR after this
fresh eligibility check, updating the existing jq/while-loop logic accordingly.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: d6fe00dd-09d4-4733-abaa-8e3a15d89c40

📥 Commits

Reviewing files that changed from the base of the PR and between f49942a and 973ce0e.

📒 Files selected for processing (4)
  • .github/workflows/close-stale-bestaxbot-prs.yml
  • .github/workflows/stale.yml
  • CLAUDE.md
  • docs/docs/guides/getting-started/ai-development.md
✅ Files skipped from review due to trivial changes (1)
  • CLAUDE.md
🚧 Files skipped from review as they are similar to previous changes (1)
  • .github/workflows/stale.yml

Comment thread .github/workflows/close-stale-bestaxbot-prs.yml Outdated
Comment thread .github/workflows/close-stale-bestaxbot-prs.yml Outdated
Comment thread .github/workflows/close-stale-bestaxbot-prs.yml
…lusive cutoff (#275)

Addresses the three CodeRabbit findings on the previous push:

- A new first step labels any open bestaxbot PR missing claude-assisted,
  so pre-labeler bot PRs can't be closed at day 44 by stale.yml's generic
  sweep — this job's 03:41 cron fires before the 04:17 sweep, and the
  REST call auto-creates the label like auto-label-claude-prs.yml does.
- The close loop re-fetches state/updatedAt/labels per PR right before
  commenting/closing, skipping anything updated, neverstale-labeled, or
  closed since the listing snapshot; fetch failures count as ineligible.
- The cutoff comparison is now inclusive (<=) to match the documented
  "90+ days" threshold.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0142miDJt2AX9QUw5fNJt2xu
@github-actions

Copy link
Copy Markdown
Contributor

Preview Deployment

Preview URL: https://1653795b.bestax.pages.dev

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

♻️ Duplicate comments (1)
.github/workflows/close-stale-bestaxbot-prs.yml (1)

108-111: 🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win

Cleanup failures are still swallowed by || true.

gh pr edit --remove-label already returns success when a label is absent, so this || true only masks genuine auth/API/network failures — and the PR still closes with stale loop labels attached. Same unresolved concern as a prior review.

🛠️ Proposed fix
               gh pr edit "$PR" --repo "$REPO" \
                 --remove-label ai-loop \
                 --remove-label ai-loop-paused \
-                --remove-label needs-human-review || true
+                --remove-label needs-human-review
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/close-stale-bestaxbot-prs.yml around lines 108 - 111,
Remove the trailing `|| true` from the `gh pr edit` cleanup command in the stale
PR workflow so authentication, API, and network failures are not swallowed; rely
on `gh pr edit --remove-label` succeeding when labels are already absent and
ensure cleanup failure prevents closing the PR.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @.github/workflows/close-stale-bestaxbot-prs.yml:
- Line 57: All three gh pr list invocations in the backfill query and union
selectors omit --limit, so candidates beyond the default 30 are skipped. Update
each command to specify an appropriate sufficiently high --limit, including the
bestaxbot query and both claude-assisted selector queries.

---

Duplicate comments:
In @.github/workflows/close-stale-bestaxbot-prs.yml:
- Around line 108-111: Remove the trailing `|| true` from the `gh pr edit`
cleanup command in the stale PR workflow so authentication, API, and network
failures are not swallowed; rely on `gh pr edit --remove-label` succeeding when
labels are already absent and ensure cleanup failure prevents closing the PR.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 6d0cfaa1-b13e-4ac1-a959-109c24b7d2b4

📥 Commits

Reviewing files that changed from the base of the PR and between 973ce0e and 4f095a3.

📒 Files selected for processing (1)
  • .github/workflows/close-stale-bestaxbot-prs.yml

Comment thread .github/workflows/close-stale-bestaxbot-prs.yml
Two more CodeRabbit findings: gh pr list defaults to 30 results, which
would silently skip older candidates in both the backfill and the close
sweep once the repo has more than 30 matching PRs — all three calls now
pass --limit 1000. And the || true on the loop-label strip masked real
API/auth failures (gh already succeeds when a label is absent), letting
a PR close with loop labels still attached; a genuine failure now aborts
the run and the daily cron retries tomorrow.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0142miDJt2AX9QUw5fNJt2xu
@github-actions

Copy link
Copy Markdown
Contributor

Preview Deployment

Preview URL: https://249b0170.bestax.pages.dev

# Conflicts:
#	docs/docs/guides/getting-started/ai-development.md
@allxsmith allxsmith added deep-review and removed deep-review labels Jul 11, 2026 — with Claude
@github-actions

Copy link
Copy Markdown
Contributor

Preview Deployment

Preview URL: https://4bbe8599.bestax.pages.dev

Comment on lines +11 to +16
# The sweep is the union of author:bestaxbot and label:claude-assisted —
# the label (auto-applied by auto-label-claude-prs.yml) also covers
# human-authored PRs with Claude attribution, and the author query covers
# bot PRs opened before the labeler existed. A first step backfills the
# claude-assisted label onto any unlabeled bestaxbot PR so the generic
# sweep can't close pre-labeler bot PRs at day 44: this job's 03:41 cron

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

auto-label-claude-prs.yml doesn't exist — human-authored Claude PRs are never protected — 🟠 Major · Correctness

What: Both new workflows repeatedly cite auto-label-claude-prs.yml as the source of the claude-assisted label (here, and in stale.yml:11). That workflow does not exist anywhere in the repo — the only thing that ever applies claude-assisted is the backfill step below, and it is scoped to --author bestaxbot.

Why it matters: The stated design is a union: author:bestaxbot plus label:claude-assisted so the label leg "also covers human-authored PRs with Claude attribution." In reality no human-authored PR ever receives the label, so:

  • stale.yml's exempt-pr-labels: …,claude-assisted never matches a human PR → it gets marked stale at 30 days and closed at 44.
  • This 90-day closer's --label claude-assisted leg only ever returns bestaxbot PRs (which the author leg already covers), so it's currently redundant.

Net: the entire "longer leash for human Claude-assisted PRs" story is inoperative. The bot path works (author query + backfill); the human path silently does not.

Fix: Either ship the auto-label-claude-prs.yml labeler in this PR (so the label is actually applied on human PRs with Claude attribution), or drop the claims/leg that depend on it and document that only bestaxbot-authored PRs get the 90-day leash.

Verification
$ ls .github/workflows | grep -i label      → (nothing)
$ grep -rn "auto-label-claude-prs" .         → only the two new files, as dangling references
$ grep -rn 'claude-assisted' .github/workflows
    → applied only by the backfill step (author bestaxbot); exempted in stale.yml

Comment on lines +111 to +114
gh pr edit "$PR" --repo "$REPO" \
--remove-label ai-loop \
--remove-label ai-loop-paused \
--remove-label needs-human-review

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Un-guarded label strip can halt the whole closer — 🟡 Minor · Correctness

What: This diverges from the on-slop.yml pattern it claims to mirror — that one ends the same three --remove-label calls with || true (on-slop.yml:67); here it runs bare under set -e. gh pr edit --remove-label X is a silent no-op only when X still exists as a repo label; if any of ai-loop / ai-loop-paused / needs-human-review has been deleted or renamed, gh exits non-zero with 'X' not found.

Why it matters: The comment justifies dropping the guard as "a failure here is a real API/auth error" — but a label removed from the repo is neither, yet it aborts the step on the first PR in the loop, so no PRs get closed that day (and every subsequent day until the label is restored). Most 90-day-stale PRs carry none of these loop labels, making them the common case that trips it.

Fix: restore the tolerant form so a stray label can't wedge the sweep, while still surfacing genuine auth failures via the daily retry:

Suggested change
gh pr edit "$PR" --repo "$REPO" \
--remove-label ai-loop \
--remove-label ai-loop-paused \
--remove-label needs-human-review
gh pr edit "$PR" --repo "$REPO" \
--remove-label ai-loop \
--remove-label ai-loop-paused \
--remove-label needs-human-review || true

@claude claude Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Deep review — 2 finding(s)

# Severity Area Finding Location
1 🟠 Major Correctness auto-label-claude-prs.yml is referenced as the labeler but does not exist; human-authored Claude PRs never get claude-assisted, so they are swept at 30/14 instead of the intended 90-day leash close-stale-bestaxbot-prs.yml:12, stale.yml:11
2 🟡 Minor Correctness Label strip runs bare under set -e (unlike on-slop.yml's guard); a deleted/renamed loop label makes gh pr edit --remove-label abort the whole closer for the day close-stale-bestaxbot-prs.yml:111-114

Overall: The two-tier stale design is sound and the shell is careful (union dedupe, inclusive cutoff, fail-safe eligibility re-check, offset crons). The riskiest part is that the whole "longer leash for human Claude-assisted PRs" story depends on a labeler workflow (auto-label-claude-prs.yml) that is not in the repo — the bot path works via backfill, but the human path silently does not, so a human should decide whether to ship that labeler here or trim the claims. The label-strip guard is a lower-stakes robustness nit worth restoring. No changes touch library/runtime code, so there is no test/story/docs-API surface at stake beyond the docs table already updated.

🏄 Clean two-lane setup, dude — bot PRs ride the 90-day wave no problem. Just one board (auto-label-claude-prs.yml) never made it to the beach, so the human surfers are gonna wipe out at day 44. Patch that in and it is all smooth swells.

claude added 2 commits July 11, 2026 11:40
# Conflicts:
#	docs/docs/guides/getting-started/ai-development.md
Addresses the remaining CodeRabbit thread: a workflow_dispatch
overlapping the daily cron could double-comment or race gh pr close
into a set -e abort.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Pohc8xLkdx4gwXkW3xd7up
@github-actions

Copy link
Copy Markdown
Contributor

Preview Deployment

Preview URL: https://a4849ce6.bestax.pages.dev

@github-actions

Copy link
Copy Markdown
Contributor

Preview Deployment

Preview URL: https://50d9f42b.bestax.pages.dev

@allxsmith
allxsmith merged commit e6cc2c0 into main Jul 11, 2026
9 checks passed
@allxsmith
allxsmith deleted the ci/stale-automation branch July 11, 2026 11:48
@github-actions

Copy link
Copy Markdown
Contributor

🎉 This PR is included in version 3.2.0 🎉

The release is available on:

Your semantic-release bot 📦🚀

@github-actions

Copy link
Copy Markdown
Contributor

🎉 This PR is included in version 5.4.1 🎉

The release is available on:

Your semantic-release bot 📦🚀

@github-actions

Copy link
Copy Markdown
Contributor

🎉 This PR is included in version 1.0.0 🎉

The release is available on:

Your semantic-release bot 📦🚀

@bestax-release-bot

Copy link
Copy Markdown

🎉 This PR is included in version 1.0.0 🎉

The release is available on:

Your semantic-release bot 📦🚀

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Feature] Stale-PR automation: bestaxbot closer + generic stale (Bun parity)

2 participants