Skip to content

fix(ci): reopen a monitor's closed issue for its key instead of filing a recurrence - #8786

Merged
kyle-sexton merged 10 commits into
mainfrom
fix/monitors-reopen-closed-issue
Oct 21, 2026
Merged

kyle-sexton merged 10 commits into
mainfrom
fix/monitors-reopen-closed-issue

Conversation

@kyle-sexton

Copy link
Copy Markdown
Member

Refs: #8701

Summary

Bot monitors reopen the existing issue for their key when a signal comes back, instead of filing a new "Recurrence of" or "Regression of" issue. Each recurring signal then lives on one issue, and the open-issue count stops growing with repeats. Duplicates seen on 2026-10-20: #8641 → #8701 and #8643 → #8702 (main-red), #8557 → #8644 (merge-queue). This is the owner-approved backlog lever (b), which GitHub Support assigned to Automation Lanes.

Fix

  • maintenance-monitor-signals: planIssues (issues.mjs) gains a reopen list. A closed match is reopened unless it was closed as not_planned or duplicate (both mute the key; duplicate is new) or it is closed-unchanged (same fingerprint, observed no later than the close). Reopens don't count against MAX_NEW_ISSUES, and there is no age window. writePlan (monitor.mjs) posts the evidence comment, then one PATCH with state: open, state_reason: reopened and the refreshed marker, the same two calls as an update. The run summary lists reopened issues.
  • maintenance-audit-lane-runs: the same rule in planFiling (findings.mjs) and file-findings.mjs. The 14-day regression window is removed. The reopen PATCH leaves the body as is, because this lane's marker is the fingerprint and can't change on a match.
  • scripts/upstream-drift-issues.sh: looks up its issue by exact title over open and closed issues through the REST issues list (creator=github-actions[bot], state=all), not the search API, and reopens a closed one. One paginated read now serves both the lookup and the close-unreported sweep. A failed read now stops the run with exit 1, where it used to skip only the affected repo.
  • Docs: docs/conventions/pr-pipeline/README.md and docs/conventions/upstream-drift/README.md describe the reopen; there is a pr-pipeline fragment.
  • Out of scope: post-merge-demotion-alert.yml. Its per-(signal, SHA) records are what the demotion gate reads, and a repeat of the same key already reopens there.

Basis: Update an issue: state_reason "Can be one of: completed, not_planned, duplicate, reopened, null". List repository issues: state "Can be one of: open, closed, all", and creator. Search allows "up to 30 requests per minute" and can return incomplete_results, which is why the drift lookup leaves it.

Verification

  • node --test over every *.test.mjs in both script directories: 110 pass, 0 fail (run main-side, outside the worker).
  • bash scripts/upstream-drift-issues.test.sh: PASS=114 FAIL=0.
  • New cases: closed-completed with a new fingerprint reopens; the same fingerprint observed after the close reopens; observed exactly at closed_at skips; not_planned and duplicate mute; no match files; reopens don't consume the new-issue cap; the executor comments, then PATCHes with state_reason: reopened.
  • A fresh-context phase verifier passed all 9 acceptance criteria at 94b5e66. Its two nits (a stale comment, a missing boundary test) are fixed in f1adc95.
  • git grep for recurrenceOf, regressionOf, "Recurrence of" and "Regression of" returns nothing.

Related

🤖 Generated with Claude Code

https://claude.ai/code/session_01DZUxjJX2Sbu4ASZUPcwC3M

kyle-sexton and others added 7 commits October 20, 2026 21:54
…g a recurrence

The monitoring lane, the lane sweep's filer and the upstream drift filer
now reopen the closed issue they already hold for a key when the signal
comes back, so each recurring signal lives on one issue. A close as not
planned or duplicate mutes the key; reopens do not count against the
new-issue cap, and no age window applies.

- maintenance-monitor-signals: planIssues gains a reopen list; writePlan
  comments with the new evidence, then PATCHes state open, state_reason
  reopened and the body with the refreshed marker. The summary counts
  reopens. The "Recurrence of" line is gone.
- maintenance-audit-lane-runs: planFiling reopens instead of filing with
  regressionOf; writeAll comments with the checked claims, then PATCHes
  the state. The fingerprint marker cannot change, so the body is kept.
- upstream-drift-issues.sh: one paginated REST list of the bot's issues
  in every state replaces both title searches; a closed issue is reopened
  and its body replaced.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DZUxjJX2Sbu4ASZUPcwC3M
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DZUxjJX2Sbu4ASZUPcwC3M
upstream-drift is not in fragment mode, so the fragment check rejects it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DZUxjJX2Sbu4ASZUPcwC3M
@kyle-sexton
kyle-sexton marked this pull request as ready for review October 21, 2026 02:22
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Oct 21, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-10-21T02:24:23.349377Z 15788f7 Draft marked ready
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@github-actions

github-actions Bot commented Oct 21, 2026 •

Copy link
Copy Markdown
Contributor

claude-security-review reviewed 799f7670d3caeface6bfd623254ae702247cd4a5: 0 finding(s), 0 as inline comments.

Security review (incremental, 832dc79..799f767): no security findings.

The four changed files are file-findings.mjs, monitor.mjs and their tests. The change reorders GitHub API calls in the reopen path. The re-triage label calls (add the filing labels, remove agent-ready) now run before the PATCH that sets the state to open. If a label call fails, the issue stays closed and the next run retries it.

  • Trust boundary: I found no change. The calls hit the same endpoints with the same inputs: the repo, the issue number, and the label list the workflow already supplies. The fingerprint marker and the rendered comment body are built exactly as before.
  • Injection and credentials: The diff adds no new input handling, string interpolation, token use or command execution.
  • Authorization: It adds no new permission or capability.
  • Failure ordering: The new order is safer. A partial failure can no longer leave an issue open with agent-ready still on it. Before this change, a failed DELETE left the issue reopened and still marked ready for unattended agent pickup. The tests now assert that the issue stays closed, the body stays unchanged, and the planner re-selects it for reopen.
  • Instruction surfaces: The diff deletes no standing instruction, rule, hook allowlist or guardrail.

I did not consult the instruction exception register, because nothing in this diff removes or softens an instruction.

@github-actions

github-actions Bot commented Oct 21, 2026 •

Copy link
Copy Markdown
Contributor

claude-review reviewed 799f7670d3caeface6bfd623254ae702247cd4a5: 0 finding(s), 0 as inline comments.

No findings. I reviewed the incremental diff since 832dc79 (the four files listed) and read monitor.mjs for context. I did not run the tests.

The change moves the reopen PATCH to the end of the sequence in both file-findings.mjs and monitor.mjs: comment, then label POST, then agent-ready DELETE, then PATCH. A failed label or DELETE call now leaves the issue closed with its old fingerprint, so the next run plans the reopen again. Before, the PATCH came first, so a failure after it left an open issue that was never re-triaged and was not retried.

In monitor.mjs the marker is refreshed in that same last PATCH, so it is not advanced early. The new tests cover this:

  • They check that the PATCH is absent after a 500 on the DELETE.
  • They check that the issue stays closed and the body is unchanged.
  • They check that planFiling / planIssues plan the same reopen again from the unchanged state.
  • The call-order assertions were updated to the new sequence.

One minor behavior I noted but did not report: while the failure persists, each retry posts another evidence or reopen comment before it fails again. The earlier ordering already had this property for a failed PATCH, so I did not count it as a finding.

No closing issue is declared: the PR uses Refs: #8701, which is a link, not an issue it closes.

kyle-sexton and others added 2 commits October 20, 2026 22:43
… reopened issue

upstream-drift-issues.sh now ignores a github-actions[bot] issue whose
body carries the monitoring lane's first-line marker or the lane sweep's
last-line marker, in both the title lookup and the close-unreported sweep.

A reopen in the monitoring lane and the lane sweep re-adds the filing
labels that exist and removes agent-ready, taking a 404 as already gone,
1 s apart like the other writes.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DZUxjJX2Sbu4ASZUPcwC3M
…abel call retries

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DZUxjJX2Sbu4ASZUPcwC3M
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.

1 participant