Detect ticket clusters that share a construct
The measurement
shr has produced ten tickets. Eight closed individually between
2026-06-26 and 2026-08-25 at prio 30-60; two open. The one describing the
shared cause — bug-a-shr-reaches-the-ir-spelled-as-tkident — sat at prio
20, below every symptom it produced, until it was repriced by hand on
2026-08-31.
Nobody mispriced anything. Prio propagates down blocked-by: edges, and
seven of the eight symptoms were filed before the cause ticket existed, so
they could never have declared an edge to it. The ranker reads one ticket at a
time; it has no aperture for the shape of a pile.
This is the same blind spot as root-cause-over-microfix.md's rule — count how
many mechanisms serve the one concept; two is a smell, three is a design flaw —
except that doc asks a human to notice, and nothing measures it.
What to build
Group open and closed tickets by construct tokens drawn from the slug and
summary (shr, settextbuf, widestring, …; stopword the ticket-type prefixes
bug-a-, feature-, and the track letters). Report a cluster when several
tickets share a token, and rank the report by how many members are already in
done/ — a construct with many individually-closed tickets is precisely the
one whose root cause is still open and underpriced.
Two outputs, both cheap:
- a
progress.shsubcommand a human runs when triaging; - a line in
check's output when a cluster crosses a threshold, since that is the report anyone already reads.
The positive control this needs — mandatory
Per CLAUDE.md's a guard that cannot fail is not a guard, and it prints PASS:
ship with an asserted case the scan MUST flag. shr is that case and it is
free — ten tickets, eight closed, the cause at the bottom. If a rewrite of the
scan stops flagging shr, it is broken however green it looks.
A second asserted case worth having is a negative one: a token that appears
in many tickets and is NOT a cluster (compiler, test, a track letter). A
scan that flags everything is the same animal as one that flags nothing.
Scope limit
This RANKS; it does not decide. The output is "these N tickets name one
construct, and M of them are already closed one at a time" — a human or a lane
owner decides whether one is upstream of the others. Do not auto-edit prio:;
that field is the human's signal (CLAUDE.md), and a scan that rewrites it
destroys the input it is reasoning from.
Explicitly NOT the fix that was proposed first
The trigger for this was a proposal to sometimes rank oldest-first to flush stale tickets. Measured the same day and it does not hold: of the 60 oldest ranked tickets the median prio is 32 against 40 for the whole set, only 9 are at prio >= 55, and all three tickets found stale this week were created 2026-08-30 — one day old. Staleness tracks recency and activity, not age, because at ~1900 commits/day a ticket about code under active edit goes stale in hours while an old one is old precisely because nothing has touched that code. Recorded here so the idea is not re-proposed from intuition; the separate one-time triage of the oldest 60 (to reject or reprice, not to work) is still worth doing and is a different job.
Deprioritised 2026-09-02 — the Track T tooling backlog was cut as a pile
This ticket is not being called wrong. It was moved as part of a pile, not judged individually, and nothing here disputes its finding.
Owner decision. 73 of the 74 open track: T tickets were filed between
2026-08-31 and 2026-09-02, 58 on one day. The pile was too large to work through
and returned almost nothing, and a ticket nobody will fix does not sit neutrally
— it stays in the ranker forever at zero value, which is the argument CLAUDE.md
already makes for a terminal folder over a low prio.
Four were kept in the ranker on a purely structural test — an active umbrella or
a hard blocked-by: edge from live work:
umbrella-one-full-tier-run-with-no-red-tier,
feature-t-freebsd-image-and-runner, and the two regression-test-core-* reds
that block the umbrella.
Kept, not deleted, for two reasons: so the finding is not rediscovered and refiled from scratch by the next agent who trips over it, and so it can be pulled back if what it touches becomes load-bearing.
To revive it: move it to the owning lane's backlog, set status: backlog,
and say in the ticket WHAT CHANGED to make it matter now. Restoring it because it
reads well is how the pile comes back.