A reopen can be correct and still be stale
Systemorph/MeshWeaver#4610, measured 2026-09-17 by re-reading the wave over the GitHub REST API.
On 2026-09-17, between 07:45Z and 07:55Z, the log-incident bot reopened roughly 128 closed issues in
Systemorph/MeshWeaver, each headed "Reopened — this fault is happening again." Two issues
report it: #4577 (≈130 issues, evidence 7–23 days old) and #4610 (≈51 issues, "the predicate is a
count delta, not recency"). They are one wave, not two: #4610's #1109 carries a reopened event
at 07:52:38Z, inside #4577's window, from the same actor.
The rule proposed for it
MeshWeaver.Plugins#2014 replaces "closed ⇒ reopen" with
issue.ClosedAt is { } closedAt && incident.LastSeen > closedAt
— a close is reverted only by an occurrence that postdates it. That is correct and it is the right first predicate: it is the one comparison that distinguishes "the fault came back after you fixed it" from "we are late telling you about the fault you already fixed", which is what the comment-debt clock made possible when it began settling old debt on a timer.
What it does NOT cover
Applying that rule to the wave, per issue, from the same evidence the bot used — the last closed
event before the reopen, and the Last seen: line of the recurrence comment that accompanied it:
| issue | close reverted | comment's Last seen |
under #2014 | evidence age at reopen |
|---|---|---|---|---|
| #2177 | 2026-08-25 23:04:04Z | 2026-08-25 15:01:44Z | stays closed | 22.7 d |
| #2621 | 2026-08-29 08:06:12Z | 2026-08-28 20:50:31Z | stays closed | 19.5 d |
| #2897 | 2026-09-01 23:57:02Z | 2026-08-31 09:24:00Z | stays closed | 16.9 d |
| #1127 | 2026-08-10 20:40:22Z | 2026-08-13 16:23:01Z | still reopens | 34.6 d |
| #2153 | 2026-08-25 19:08:33Z | 2026-08-26 10:06:46Z | still reopens | 21.9 d |
| #2370 | 2026-08-26 16:39:27Z | 2026-08-27 13:03:48Z | still reopens | 20.8 d |
| #1114 | 2026-08-10 21:33:13Z | 2026-09-02 07:40:30Z | still reopens | 15.0 d |
| #1253 | 2026-08-12 12:22:46Z | 2026-09-06 05:54:48Z | still reopens | 11.1 d |
| #2951 | 2026-09-02 18:55:23Z | 2026-09-10 14:13:06Z | still reopens | 6.7 d |
| #1422 | 2026-08-13 18:36:27Z | 2026-09-10 14:47:02Z | still reopens | 6.7 d |
| #1109 | 2026-08-10 12:19:23Z (by a human) | 2026-09-10 19:08:27Z | still reopens | 6.5 d |
8 of 11 sampled still reopen — including all three rows #4610 measured for itself. #2014's own census of the same wave agrees on the proportion from the other side: 53 predate the close, 75 postdate it.
So the two issues report two different defects that produced one wave:
- #4577 — the bot reopened tickets over faults that happened before the close. #2014 fixes exactly that.
- #4610 — the bot asserted "this fault is happening again" about faults last seen days or weeks ago. Every row above is one, and #2014 leaves 8 of 11 of them saying it.
The reopens in the second group are not wrong: those faults really did recur after the close, so the close really was premature. What is wrong is the tense. A ticket reopened at 07:53Z on the strength of something last seen on 13 August, announcing a present-tense recurrence, sends the next reader after a fault that may have stopped five weeks ago — and #4610's harm ("a reopen means nothing until a human re-reads the record") survives the fix that was proposed for it.
What the second predicate has to be
Not a magic window. The system already has exactly one definition of currently happening:
LogWatchOptions.CommentInterval, documented as the rate limit for a fingerprint that "fires
continuously" — it is the resolution at which this system observes a fault as ongoing. A reopen
that asserts the present tense should require evidence inside it.
Two things make that a real change rather than a line:
Reopenhas no clock. Every timing in the filer and in its tests comes from the incident's ownLastSeen— deliberately: "no wall-clock dependency, no sleep, no scheduler to pump". A staleness predicate is the first thing here that genuinely needs now, so it needs a seam (aTimeProvideronLogIncidentFiler), and every existing reopen test needs to set it.- The structural discriminator is NOT available where it is needed. "Was this comment triggered
by a fresh report or by the debt clock" would answer the question with no clock at all — and
LogIncidentWork.Reconcilecarries exactly that. But the clock's reconcile only writesRequestedStatus = Comment; the comment itself is then performed by the ordinary path on the next collection emission, as a work item withReconcile: false. By the timefiler.Commentruns, which trigger fired is no longer knowable.
Both belong in the same change as #2014's predicate, in the method #2014 rewrites — not in a second, competing edit to it.
How this was measured
For each issue: GET /repos/Systemorph/MeshWeaver/issues/{n}/events, taking the most recent
reopened event and the last closed event before it; then
GET /repos/Systemorph/MeshWeaver/issues/{n}/comments, taking the bot comment within two minutes of
that reopen and parsing its - Last seen: line. The verdict column is the new rule applied to those
two timestamps, truncated to the second GitHub reports closed_at in. Read-only: no issue was
opened, closed or reopened.