Refs #674, found while reviewing #720. The gate that landed there is sound in the direction that matters most — a new unguarded broad catch fails CI, and a fixed site fails until its ledger entry is removed. This is about the direction it does not cover.
Measured on #720's head (76e25d32)
| experiment |
result |
add a new unguarded catch (IllegalStateException) to core/mcp/src/jvmMain |
RED, names path:line: catch (Type) |
append one line to cancellation-catch-backlog.tsv for it |
exit 0 |
same, with #999999 as the cited issue |
exit 0 |
append to cancellation-catch-allowlist.tsv with 30 junk characters as the reason |
exit 0 |
| fix a backlogged site without editing the ledger |
RED, "ledger says 1, tree has none" |
| add a 2nd violation under an already-listed key (1 -> 2) |
RED |
What that means
Both ledgers are exact-match ratchets per <path, function> key, which is what stops them rotting into fiction. Neither is a monotone ratchet on the total: nothing is fixed-size, checksummed, or required to shrink. The validation on an entry is a >=20-character reason and, for the backlog, any #NNN-shaped token — the issue is never resolved, so a made-up number passes.
So it is a ratchet against silent drift and a logbook against deliberate drift. Appending is strictly less work than fixing the catch, and the allowlist route is the quieter of the two: it needs no issue citation and its site lands on the benign N allowlisted (reasoned exemptions) line instead of the !! N KNOWN ... These are defects banner.
The growth is not invisible — it is a diff line, and the printed count moves — but the gate itself will not stop it, which leaves long-run enforcement resting on a reviewer noticing a ledger diff. That is the human-directed-sweep mechanism the gate was written in #674 to replace.
Possible shapes
Not prescribing one; they trade off differently.
- A ceiling checked into the repo. A
backlog-max constant the gate asserts against, lowered as sites are fixed. Simple, and it makes an increase a deliberate two-line edit that states its own intent.
- Monotone-decrease against the merge base. Compare the backlog total to
origin/main's and fail on an increase. Stronger, but needs the base available in CI and has an escape hatch problem for genuine exemptions.
- Separate the two files' policies. Cap the backlog only, and leave the allowlist uncapped but require its reasons to survive review — the allowlist is meant to grow when a genuinely-exempt site is found, so a cap there is wrong.
- Resolve the cited issue. Confirm the
#NNN in a backlog reason names an issue that exists and is open. Cheap, and it stops a placeholder number.
Whichever shape, it wants the same self-test discipline #720 already established: a positive that fires and a negative that stays silent, plus a mutation that proves the new assertion can fail.
Not urgent
Nothing is broken today. The 60 entries are the real state of the tree, #667 is the named consumer, and the count is printed on every CI run. This is about what the file looks like in three months.
Refs #674, found while reviewing #720. The gate that landed there is sound in the direction that matters most — a new unguarded broad catch fails CI, and a fixed site fails until its ledger entry is removed. This is about the direction it does not cover.
Measured on #720's head (
76e25d32)catch (IllegalStateException)tocore/mcp/src/jvmMainpath:line: catch (Type)cancellation-catch-backlog.tsvfor it#999999as the cited issuecancellation-catch-allowlist.tsvwith 30 junk characters as the reasonWhat that means
Both ledgers are exact-match ratchets per
<path, function>key, which is what stops them rotting into fiction. Neither is a monotone ratchet on the total: nothing is fixed-size, checksummed, or required to shrink. The validation on an entry is a >=20-character reason and, for the backlog, any#NNN-shaped token — the issue is never resolved, so a made-up number passes.So it is a ratchet against silent drift and a logbook against deliberate drift. Appending is strictly less work than fixing the catch, and the allowlist route is the quieter of the two: it needs no issue citation and its site lands on the benign
N allowlisted (reasoned exemptions)line instead of the!! N KNOWN ... These are defectsbanner.The growth is not invisible — it is a diff line, and the printed count moves — but the gate itself will not stop it, which leaves long-run enforcement resting on a reviewer noticing a ledger diff. That is the human-directed-sweep mechanism the gate was written in #674 to replace.
Possible shapes
Not prescribing one; they trade off differently.
backlog-maxconstant the gate asserts against, lowered as sites are fixed. Simple, and it makes an increase a deliberate two-line edit that states its own intent.origin/main's and fail on an increase. Stronger, but needs the base available in CI and has an escape hatch problem for genuine exemptions.#NNNin a backlog reason names an issue that exists and is open. Cheap, and it stops a placeholder number.Whichever shape, it wants the same self-test discipline #720 already established: a positive that fires and a negative that stays silent, plus a mutation that proves the new assertion can fail.
Not urgent
Nothing is broken today. The 60 entries are the real state of the tree, #667 is the named consumer, and the count is printed on every CI run. This is about what the file looks like in three months.