ci(stale): enable 60+30 stale/close policy for pull requests#3375
Conversation
- Fix the repository guard so the workflow actually runs on QwenLM/qwen-code (it was previously gated to google-gemini/gemini-cli and never executed in this repo). - Scope the behavior to pull requests for now; issue policy will be introduced separately once triage labels are in place. - Mark a PR stale after 4 weeks without activity, then close it after another 4 weeks. - Exempt pinned, security, status/blocked, status/on-hold, and status/ready-for-merge from auto-close. - Remove the stale label automatically when activity resumes, and process the oldest PRs first on each run.
📋 Review SummaryThis PR enables the stale bot for pull requests in the 🔍 General Feedback
🎯 Specific Feedback🟢 Medium
🔵 Low
✅ Highlights
|
Five weeks + five weeks gives contributors more slack around holidays and busy periods, and reduces the first-run impact on the existing backlog. The total window moves from 56 days to 70 days.
Shift by one hour so results are ready before the Beijing work day starts (08:30 local), while still avoiding the top of the hour (the high-contention window for GitHub-hosted runners) and staying 30 minutes after release.yml at 00:00 UTC.
|
LGTM — the changes are clean and correct: guard fix, 35+35 PR stale policy, and exempt labels are all reasonable. Two non-blocking suggestions:
After merge, remember to manually trigger LGTM — 改动干净正确:守卫修复、35+35 策略、豁免标签都合理。两个非阻塞建议:
合并后记得手动 |
- Remove the `github.repository == 'QwenLM/qwen-code'` job guard: scheduled runs are already disabled on forks by GitHub, and workflow_dispatch is manually-triggered so the guard adds no safety. - Add a comment explaining the `operations-per-run: 100` rationale (rate-limit headroom given the ~150-PR backlog).
Give authors a longer idle window before the stale warning (60 days) while shortening the grace period after the warning (30 days). Total time-to-close is unchanged at 90 days, but the louder signal now lands closer to the actual closure so authors are less likely to be caught off guard by a silent auto-close.
Merged 6 upstream commits while preserving HopCode architecture: Features synced from upstream: - feat(mcp): OSC 52 copy hotkey for OAuth authorization URL (QwenLM#3393) Press 'c' during OAuth to copy URL via terminal clipboard, works over SSH - feat(cli): early input capture to prevent keystroke loss during startup (QwenLM#3319) Buffers keystrokes during REPL init, replays once UI is mounted - perf(vscode): fix input lag in long conversations via React.memo (QwenLM#2550) MessageList/UserMessage/AssistantMessage wrapped with React.memo - feat(vscode-ide-companion): agent execution tool display (QwenLM#2590) Render dedicated agent execution cards in webview - fix(build): invoke tsx via node --import instead of npx (QwenLM#3237) Fixes bun compatibility for generate:settings-schema script - ci(stale): enable 35+35 stale/close PR policy (QwenLM#3375) Conflict resolution: - packages/vscode-ide-companion/.../toolcalls/index.tsx: kept @hoptrendy/webui, added ToolCallData to imports (upstream added it) - All @qwen-code/* import paths preserved as @hoptrendy/* (HopCode arch) - HopCode branding, version, and CI workflows preserved Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…3375) * ci(stale): enable 28+28 stale/close policy for pull requests - Fix the repository guard so the workflow actually runs on QwenLM/qwen-code (it was previously gated to google-gemini/gemini-cli and never executed in this repo). - Scope the behavior to pull requests for now; issue policy will be introduced separately once triage labels are in place. - Mark a PR stale after 4 weeks without activity, then close it after another 4 weeks. - Exempt pinned, security, status/blocked, status/on-hold, and status/ready-for-merge from auto-close. - Remove the stale label automatically when activity resumes, and process the oldest PRs first on each run. * ci(stale): loosen PR cadence from 28+28 to 35+35 Five weeks + five weeks gives contributors more slack around holidays and busy periods, and reduces the first-run impact on the existing backlog. The total window moves from 56 days to 70 days. * ci(stale): move cron from 01:30 UTC to 00:30 UTC Shift by one hour so results are ready before the Beijing work day starts (08:30 local), while still avoiding the top of the hour (the high-contention window for GitHub-hosted runners) and staying 30 minutes after release.yml at 00:00 UTC. * ci(stale): drop redundant repo guard and document ops-per-run - Remove the `github.repository == 'QwenLM/qwen-code'` job guard: scheduled runs are already disabled on forks by GitHub, and workflow_dispatch is manually-triggered so the guard adds no safety. - Add a comment explaining the `operations-per-run: 100` rationale (rate-limit headroom given the ~150-PR backlog).
Background
qwen-code currently has 139 open PRs, 36 of which have had no activity for more than 60 days. One direct reason: the pre-existing
ifguard in.github/workflows/stale.ymlwas hard-coded togoogle-gemini/gemini-cli, so the workflow never executed inQwenLM/qwen-code— the stale automation has in fact never been active.What this PR does
ifguard entirely. Scheduled runs are already disabled on forks by GitHub, andworkflow_dispatchis manually-triggered, so the guard added no real safety — only maintenance overhead.status/stalelabel and post a reminder comment.pinned,security,status/blocked,status/on-hold,status/ready-for-merge.remove-stale-when-updated: true— any push by the author or any comment automatically strips the stale label on the next cron run.ascending: true+operations-per-run: 100— older PRs are processed first, and each run is capped at 100 operations to stay well under GitHub's hourly rate limit.Why 60 + 30
Calibrated against common industry practice:
Reasons for choosing 60 + 30:
These numbers are not final. I recommend revisiting the false-close rate after 2–3 months of operation and adjusting the windows once the backlog stabilizes.
Why issues are deferred
type/bug-confirmedetc.), then introduce an issue-level stale policy in a separate PR.Expected first-run impact (based on the current 139 open PRs)
Nothing closes on day one — every affected PR gets a full 30-day reaction window. Authors can push or comment to keep it alive, and maintainers can apply an exempt label to block auto-close.
Trigger mechanism
workflow_dispatchin the Actions tab.Follow-ups (after merge)
google-gemini/gemini-cliguard bug (at minimumgemini-self-assign-issue.ymlhas this problem).status/ready-for-mergeafter approving, so PRs waiting only on a merge are not mis-closed.Test plan
workflow_dispatchonce manually to validate the ascending order, exempt-label handling, and theoperations-per-run: 100batching.status/ready-for-mergeis skipped.背景
qwen-code 当前有 139 个 open PR,其中 36 个已经超过 60 天没有活动。一个直接原因:原先
.github/workflows/stale.yml的if守卫写死的是google-gemini/gemini-cli,在QwenLM/qwen-code仓库里永远不会执行,也就是 stale 自动化从来没生效过。这个 PR 做了什么
if守卫。GitHub 对 fork 默认禁用 scheduled workflow,workflow_dispatch本身又只有写权限者能触发,所以这层守卫没有实际安全收益,只增加维护负担。status/stale标签 + 发提醒评论。pinned、security、status/blocked、status/on-hold、status/ready-for-merge。remove-stale-when-updated: true——作者 push 或任何人评论后,下一次 cron 自动撕掉 stale 标签。ascending: true+operations-per-run: 100——老 PR 优先处理,每次最多操作 100 条,远离 GitHub 小时级限流红线。为什么是 60 + 30
对标业界常见做法:
选 60 + 30 的理由:
数字不是最终的。建议运行 2–3 个月后复盘误关率,再根据数据调整。
为什么 issue 先不动
type/bug-confirmed等分诊标签体系,再用单独 PR 处理 issue 的 stale 策略。首次运行预估影响(基于当前 139 个 open PR)
第一天不会关任何 PR——每个受影响的 PR 都有完整的 30 天反应窗口,作者可以 push / 评论续命,maintainer 也可以打豁免标签拦住。
触发机制
workflow_dispatch。合并后的 Follow-ups
google-gemini/gemini-cli的坏守卫(至少gemini-self-assign-issue.yml有同样问题)。status/ready-for-merge豁免标签,避免长期 approve 但卡在等合并的 PR 被误关。Test plan
workflow_dispatch一次,验证 ascending 顺序、豁免标签、operations-per-run: 100的批量行为。status/ready-for-merge的 PR 被豁免不处理。