Skip to content

feat: /issue_cleanup — GitHub issue-tracker reconciliation door #174

Description

@Jammy2211

Overview

PyAutoLabs has no door that reconciles the GitHub issue trackers. /repo_cleanup sweeps git debris and stops there, /community handles external issues awaiting a reply, and /create_issue / /update_issue are single-issue primitives — nothing owns "audit the open issues, find the dead ones, close them". The trackers had drifted to 82 open issues across 18 repos, of which 35 were closable.

An ad-hoc sweep on 2026-07-28 cleared those 35 (29 shipped-but-still-open, 6 obsolete 2018–2019 PyAutoCTI) leaving 47. This issue makes that reconciliation a reusable, human-gated skill so the tracker never silently drifts to 80+ again.

Plan

  • Add PyAutoBrain/skills/issue_cleanup/ as a standalone execution door modelled on /repo_cleanup: audit → bucketed dashboard → per-bucket human confirmation → execute → recap.
  • Encode the four ways a naive "has a PyAutoMind record → close it" rule was proven wrong, above all the record header-key taxonomy.
  • Require two independent evidence legs (record header + merged PR) before any issue is even proposed for closing.
  • Wire it into COMMANDS.md, bin/install.sh, and the /wake_up digest — audit auto-runs read-only, every close stays human-gated.
Detailed implementation plan

Affected Repositories

  • PyAutoBrain (primary, only)

Branch Survey

Repository Current Branch Dirty?
./PyAutoBrain main M skills/WORKFLOW.md (concurrent, unrelated)

Suggested branch: feature/issue-cleanup
Worktree: ~/Code/PyAutoLabs-wt/issue-cleanup/

What the ad-hoc sweep established

The classifier needed four corrections, each found by verification rather than inspection. These are the skill's core requirements:

  1. Body mentions are not claims. Grepping record files for an issue URL over-matches — complete/2026/05/many-vis-prep-dft.md discusses PyAutoArray#326 in prose while its own - issue: header reads (CI-triage cluster G, no GitHub issue). Only the header line is evidence.

  2. The header key carries the meaning — the load-bearing rule. Across 800 records: issue: (630 uses) means this record completes that issue. But followup-issue:, follow-up-issue:, library-followup-issue:, parent-issue:, upstream-issues-filed: and plan: (13 uses) mean the opposite — the record spawned that issue and it is legitimately open. A loose *issue*: match would close live follow-ups.

  3. Annotations override. Records mark deliberate exceptions inline: (open — findings census stays as reference), (STAYS OPEN — real finding + resumable fit), (STAYS OPEN for the optional model-parity fit leg), (both stay OPEN for parked design work only). Any open token means hands off — and these appear on plan: lines, not just issue: lines.

  4. A record in complete/ does not mean the work completed. ep-hierarchical-scale-collapse.md carries Status: issued — it filed PyAutoFit#1405 and reported two defects on it. The record is complete; the issue is a live bug. Read the status field, not the directory.

Corroborating: PyAutoReduce#8's record already said (CLOSED) while GitHub had it open — closes do silently fail to land.

Buckets

Bucket Definition Action
A shipped completing header key + no open annotation + merged PR closable, on confirmation
B weak evidence record exists, an evidence leg fails report only
C deliberately open annotation says so never touch
D in flight present in active.md / parked.md never touch
E external author is not the maintainer route to /community
F unreconciled no record at all the real backlog; sub-split by age

The PR leg needs both paths: the GitHub timeline cross-reference and a PR number named in the record body — 12 of the 29 closable issues had only the latter, so timeline alone under-reports.

Obsolescence needs a real check, not an age threshold

The 8 oldest issues split on evidence, not age. The 6 PyAutoCTI ones (2693–2785 days) named FrameGeometry, CIFrame, CIData, ci_data_analysis, ci_pattern, phase.py/pipeline — grep of autocti/ returns zero for every one (the CTI resurrection removed that surface), so they closed not_planned. PyAutoHands#16 (test against pre-release deps) and #17 (fail build if RTD docs fail) are the same vintage (~1337 days) but were left open — no --pre workflow and no RTD gating exist in PyAutoHands/.github/workflows/, so they remain valid unimplemented asks. The skill must probe whether the named API/infra still exists.

Implementation Steps

  1. skills/issue_cleanup/issue_cleanup.md — canonical command body (the <verb>.md convention /hygiene and /wake_up follow): scope repos → fetch open issues (select(.pull_request == null)) → parse record headers → classify A–F → dashboard → per-bucket confirm → execute → recap.
  2. skills/issue_cleanup/SKILL.md — thin discovery wrapper, frontmatter name: issue-cleanup (hyphenated for Codex).
  3. skills/issue_cleanup/reference.md — header taxonomy table, bucket definitions, dashboard layout, per-bucket execution.
  4. skills/COMMANDS.md — add /issue_cleanup as a maintenance/execution door (/repo_cleanup is currently absent from this file too; add alongside).
  5. skills/wake_up/wake_up.md — add a read-only reconciliation count to the digest.

Mechanics

  • gh issue close is broken in this environment. Comment first, then gh api -X PATCH repos/<owner>/<repo>/issues/<n> -f state=closed -f state_reason=<completed|not_planned>.
  • completed for bucket A; not_planned for obsolete.
  • Every close leaves a comment naming its evidence (record path + PR) so the decision is auditable and reversible.
  • Recognise bot-authored self-refreshing issues ([url-check], [heart-health]) and exclude them from staleness ranking.

Testing

Re-run the audit half against today's post-sweep state and assert it reproduces the known-good classification: 47 open, zero bucket-A candidates (all closed today), the 5 annotated C issues held back, and the 6 follow-up-key issues correctly not proposed. A real regression bar, not a smoke check.

Install caveat

bin/install.sh run from a worktree repoints ~/.claude at that worktree. Create the two symlinks by hand; leave install.sh to run from the main checkout post-merge.

Key Files

  • PyAutoBrain/skills/issue_cleanup/issue_cleanup.md — command body (new)
  • PyAutoBrain/skills/issue_cleanup/SKILL.md — discovery wrapper (new)
  • PyAutoBrain/skills/issue_cleanup/reference.md — taxonomy + execution detail (new)
  • PyAutoBrain/skills/COMMANDS.md — routing entry
  • PyAutoBrain/skills/wake_up/wake_up.md — digest line

Notes on classification

Brain's Feature Agent returned large (score 9) → split-into-phases; overridden to single phase — one skill in one repo, with the design reasoning already settled by the sweep rather than pending discovery. Brain's cited risk ("public-API change may ripple downstream") is a false positive: a skill body is not an API. Heart is YELLOW (65) but its tick is stale (2026-07-27 17:18, citing 07-21 validation data) and none of its reasons gate a Brain skill addition.

Original Prompt

Click to expand starting prompt

See PyAutoMind/active/issue_cleanup_skill.md. The originating request was:

do we have a skill to do a github issue clean up?

Answered: no — /repo_cleanup covers git debris only, /community covers external issues, /create_issue and /update_issue are single-issue primitives. The user asked for an ad-hoc sweep first, then this skill.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions