Skip to content

Add step 6 to issue triage: check for open PRs before opening new ones - #328

Merged
sibson merged 1 commit into
mainfrom
claude/triage-skill-open-prs-42fwfu
Jul 27, 2026
Merged

sibson merged 1 commit into
mainfrom
claude/triage-skill-open-prs-42fwfu

Conversation

@sibson

@sibson sibson commented Jul 27, 2026

Copy link
Copy Markdown
Owner

Summary

Extends the issue-triage skill to search for open pull requests that already address an issue before proposing a fix. This prevents duplicate work and surfaces stalled PRs waiting for review as the most actionable finding.

Changes

  • SKILL.md: Documents step 6, which searches for open PRs addressing the issue and assesses whether they fix the mechanism traced in step 2. Clarifies that this is distinct from step 3 (checking for merged fixes) and changes the action but not the classification. Adds guidance on when to open a competing PR (only if the existing one is stale/inapplicable) and what assessment to include in the issue comment.

  • decision-table.md: Adds "When a PR is already open" section explaining that the classification doesn't change but the action does — specifically, don't open a competing PR unless it's stale, and always include 1–2 sentences assessing whether the open PR addresses the mechanism, carries a test, or contradicts documented design.

  • SKILL.md and decision-table.md: Updates step numbering (6→7, 7→8, 8→9, 9→10) and clarifies that a bare link to an open PR is not enough — the assessment is the deliverable.

  • snapshot.py: Adds --prs mode to freeze the open pull request list into fixtures/open-prs.json, with the same pruning logic as issues. Includes state and draft fields (unlike issues, where closed state is self-announcing; for PRs, "is it open and is it a draft" is the fact under test).

  • evals/fixtures/open-prs.json: New fixture holding 9 open PRs as of 2026-07-27, including fix #285 #287 (fix Beat crash after Redis SERVER_CLOSED_CONNECTION_ERROR #285), Fix/due at calculation 307 #308 (fix Bug: due_at property calculates incorrect next run time due to misuse of remaining_estimate #307), and test: reproduce #74 — rrule skips the occurrence at dtstart #324 (regression test for rrule: first run delayed #74). Shared by all cases that could surface an open PR.

  • evals/evals.json: Updates case 1 (reproducible-bug-and-duplicate) to read the open-prs fixture and expect it to surface Fix/due at calculation 307 #308 without opening a competing PR. Adds case 7 (open-pr-already-proposed) testing Beat crash after Redis SERVER_CLOSED_CONNECTION_ERROR #285, which has an open PR (fix #285 #287) titled only by number — guards against missing PRs that don't name their issue in words.

  • evals/README.md: Documents why the open-prs fixture must hold every open PR (so "search the number, then skim the list" is testable), and updates the case table to note that case 1 now holds back the branch-and-PR sequence because Fix/due at calculation 307 #308 is open, and case 7 tests finding a PR despite its minimal title.

  • check_no_writes.py: Adds add_reply_to_pull_request_comment to the NEVER_ALLOWED list, preventing the skill from reviewing or replying on someone else's PR. Clarifies the distinction: closing is the maintainer's call; reviewing is why step 6 exists.

Notable details

  • The open-prs fixture is shared across all cases, not per-case, because the step under test is "search the number, then skim the list" — a fixture holding only the PR the case is about would hand the answer over before the search ran.

  • Step 6 uses both search_pull_requests (for the number) and list_pull_requests (to skim all open ones), because several PRs in the real repo name their issue only in the title or body, not in words — fix #285 #287 is fix #285, Fix/due at calculation 307 #308 is Fix/due at calculation 307.

  • The assessment of an open PR goes in the issue comment and run report, not as a review on the PR itself — the reporter and maintainer are the audience, and a contributor whose two-year-old PR suddenly gets a critique from a triage bot is not.

  • Attribution footer is always the bare https://claude.ai/code, never a session-specific link — those resolve for nobody but the person who ran it and are noise in a thread the reporter has to read.

Triage could confirm a bug and open a repro PR without ever noticing that a
fix was already sitting in review. The only PR-adjacent instruction was a
clause in step 3 aimed at dating a *merged* fix, and it reached for
search_issues rather than search_pull_requests -- so a contributor who titled
theirs "fix #285" was invisible.

Adds step 6, between duplicate-hunting and classification. It searches the
bare issue number and skims the open list, because several of these PRs name
their issue only in the title and #286 covers two at once. It also asks for an
assessment rather than a bare link: #287 addresses #285 but re-acquires the
lock inside tick(), which docs/design.rst:55 says a node deliberately does not
do, and "fixed by #287" would leave the reporter waiting on a merge that isn't
coming.

An open PR is not a new outcome -- the classification is unchanged -- so it
lands as a section in decision-table.md that overrides outcome A's
branch-and-PR sequence, plus a required "Open PR" line in the report block
that reads "none found" rather than going absent.

Reviewing or replying on someone else's PR is now out of bounds on every run,
not just dry ones, and check_no_writes.py enforces that alongside the
never-close rule.

Also pins down the attribution footer: no session links and no Claude-Session
trailer in anything public. #324 went out with one in its body, which resolves
for nobody but the account that opened it.

Evals: new case 7 on #285/#287, where the PR is the whole answer. Case 1 also
had to change -- PR #308 is open against #307, so its expectation of "branch
and open a PR" was wrong the moment this rule existed. Both read a frozen
fixtures/open-prs.json holding every open PR, not just the relevant one: the
search is the step under test, and a fixture with a single entry would hand
over the answer. Case 6 reads it too, since a batch run turns up #324 for #74.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@sibson
sibson merged commit 9c9c271 into main Jul 27, 2026
9 checks passed
@sibson
sibson deleted the claude/triage-skill-open-prs-42fwfu branch July 27, 2026 23:28
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Bug: due_at property calculates incorrect next run time due to misuse of remaining_estimate Beat crash after Redis SERVER_CLOSED_CONNECTION_ERROR

2 participants