Skip to content

bug(ci): stale sweep ignores linked PR and sub-issue activity #3190

Description

@purp

User Story

As an OpenShell maintainer on triage duty,
I want an issue with active linked work to stay out of the stale sweep,
so that epics and tracked bugs are not mislabeled state:stale while a pull request implementing them is under review.

Problem Statement

The stale sweep in .github/workflows/stale.yml decides staleness from an issue's updated_at timestamp. GitHub does not bump updated_at when an issue is cross-referenced by a pull request, when a linked PR is pushed to or reviewed, or when a sub-issue is updated. As a result, an issue with active implementation work in flight is treated as inactive and receives state:stale after 14 days.

Only direct activity on the issue itself — a comment, a label change, an edit — clears or prevents the label.

Impact / Why This Matters

Today the label is cosmetically wrong but operationally harmful in three ways:

  1. It misrepresents queue state. During triage, state:stale signals "nobody is working on this." A maintainer scanning the backlog cannot distinguish a genuinely abandoned issue from an epic with an open PR against it.
  2. It requires manual, repeating cleanup. The only workaround is for a human to comment on the issue to bump updated_at, or to hand-apply an exempt label. This has to be redone every 14 days for the life of the work.
  3. It becomes destructive when closing is enabled. days-before-issue-close is currently -1 (dry-run), so nothing closes today. When that is set to 7 as the comment anticipates, an issue with an open, actively reviewed PR will be auto-closed as not_planned.

Observed on #2174:

Time (UTC) Event
2026-08-28T12:07:01Z Stale bot commented and applied state:stale
2026-08-31T08:34:58Z Cross-referenced by PR #3027 (Part of #2174)
2026-09-02, 09-04 PR #3027 pushed and reviewed
updated_at still reads 2026-08-28T12:07:01Z

The same pattern appears earlier in that issue's history: state:stale applied 2026-07-25, cross-references from #2497 (07-27) and #1129 (08-01) did not clear it, and the label was only removed on 08-02 after a human comment.

Sub-issue activity has the same shape — a parent issue's updated_at does not move when a child issue is updated.

Acceptance Criteria

  • An open issue cross-referenced by an open, non-draft pull request is not marked state:stale.
  • An open issue whose sub-issue has recent activity is not marked state:stale.
  • When an issue already labeled state:stale gains a linked open PR or sub-issue activity, the label is removed on the next sweep without a human comment.
  • Issues with no direct activity and no linked PR or sub-issue activity are still marked stale on the existing 14-day schedule.
  • The behavior holds once days-before-issue-close is set to a positive value, so no issue with active linked work is auto-closed.

Reproduction Steps

  1. Open an issue and leave it without direct activity for 14 days so the sweep applies state:stale.
  2. Open a pull request whose body references the issue (Part of #<n> or Closes #<n>). Confirm the cross-referenced event appears in the issue timeline.
  3. Push commits to that PR and leave a review on it.
  4. Run gh api repos/NVIDIA/OpenShell/issues/<n> --jq .updated_at and observe it is unchanged from step 1.
  5. Wait for the next scheduled sweep (17 8 * * *). The state:stale label remains.

Live example, no setup required:

gh api repos/NVIDIA/OpenShell/issues/2174 --jq '{updated_at}'
gh api repos/NVIDIA/OpenShell/issues/2174/timeline --paginate \
  --jq '.[] | select(.event=="cross-referenced") | "\(.created_at)\t\(.source.issue.number)"'

Environment

  • Repository automation, not the OpenShell runtime
  • Workflow: .github/workflows/stale.yml
  • Action: actions/stale v11.0.0 (4391f3da665fdf50b6810c1a66712fb9ba21aa93)
  • Schedule: cron: "17 8 * * *"
  • Current config: days-before-issue-stale: 14, days-before-issue-close: -1 (dry-run)
  • Exempt labels today: state:triage-needed, state:validated, state:accepted, agent:*, roadmap

Notes

actions/stale has no built-in option to consider linked pull requests or sub-issues; it filters and sorts on updated_at only. A fix likely needs a pre-step that queries each candidate issue's timeline for cross-referenced events pointing at open PRs, and the sub-issues API for recent child activity, then feeds the results to exempt-issue-labels or skips those issues.

Applying an exempt label such as state:accepted works as a per-issue mitigation but does not generalize, since it conflates "a maintainer decided to pursue this" with "keep the bot away from this."

Activity

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

Metadata

Metadata

Assignees

Labels

area:buildRelated to CI/CD and buildsstate:acceptedA maintainer decided OpenShell should pursue this issue

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions