You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
check:durability-log-level cannot represent a seam that propagates a durability failure by RETURNING an outcome object — its propagation lists are keyed on callee names #16233
scripts/check-durability-degradation-log-level.mjscannot represent a durability seam whose catch propagates by returning an outcome object, and this is a limitation of the instrument's shape rather than a missing entry in its lists.
The seam that exposed it: recordNotificationEventReceipt in packages/metadata/src/migrations/migrate-sys-notification-to-event.ts (added by PR #16230).
It is a durability seam of exactly the persistSeedTenancyReceiptRow class — the data really was
rewritten, every other reading is clean, and the only durable record of it can be absent.
Why the gate cannot hold it:
DURABILITY_CRITICAL_CALLEES does not name it — that part is merely an entry.
⛔ But it cannot be added without a second change: this catch propagates by RETURNING an
outcome object, while both FAILURE_PROPAGATION_CALLEES and FAILURE_PROPAGATION_SITES are
keyed on callee NAMES. A returned object literal has none.
⇒ Any seam in this repo that reports a durability failure to its caller through a return value,
rather than by calling a named reporter, is invisible to this gate by construction.
Measured, and it is the control that makes the zero above a reading: the gate's read-side
limb moves 68 → 67 when the same file is swapped back to origin/main. ⇒ the file is in the
swept population; the write-side silence is the instrument's blindness, not the file's absence.
⚠️NOT a live defect. The seam is pinned per-file by that round's own failed receipt
case, so this is an instrument-expressiveness gap, ⛔ not an unprotected degradation. Hence finding, not bug.
⚠️NOT measured: how many other seams in the tree propagate this way. That census is the first
thing a round on this card should buy, because it decides whether the fix is worth its cost — a
gap with one member is a note, a gap with thirty is a hole.
Why the shape of the fix is not obvious
A name-keyed list cannot key on "returns an object with a failure-shaped field". The candidate
directions each cost something and none is free:
Key on the enclosing function's name instead of the callee's, for a declared set of seams —
cheap, but it moves the gate from "what does this call do" to "who is asking", which is a
different question and may weaken the existing 29.
Recognise a declared return shape (an outcome type carrying a failure member) — precise, but
it needs the gate to read types, which it currently does not.
Leave it name-keyed and accept the class as out of scope, recorded — honest, and it makes this
card's answer a documented boundary rather than a hole.
⛔ This card proposes none of them. It records the gap, its measurement, and its control.
⚠️ Context a maintainer may want more than this row
This is now the third open finding against this one script, alongside a decision and a blocked
triage card:
triage the parameterless-catch read seams, then decide the 2a criterion
⇒ Five open items on one instrument. Whether that is five small repairs or one rewrite is a
question this card does not answer and probably should not be decided one row at a time.
Provenance and dedup
Found by the #16100 execution round, which could not file it itself and said so rather than
guessing: filing without a duplicate check is a forbidden shape, and its dedup channel was gone in
both directions — REST /search/issues is not served on that channel (a same-session control query
that must have hit #16100 came back empty, so its zero was a channel artefact, not a reading),
and both search_issues MCP calls were refused by the user-level rate limit. It handed the row to
the PM seat instead. Its full reasoning: #16100 (comment)
Dedup performed by this seat, over a complete enumeration rather than a search: all 652 open
issues fetched with bodies (651 of 652 carry one) and grepped locally. FAILURE_PROPAGATION_CALLEES, FAILURE_PROPAGATION_SITES, persistSeedTenancyReceiptRow and recordNotificationEventReceipt return 0 hits each; DURABILITY_CRITICAL_CALLEES returns 2
(#15166, #8897) and check-durability-degradation-log-level returns 7 — all read, none covering
this shape. Firing controls on the same command and scope: sys_migration → 4 (#16194, #16185, #16100, #15207), NOTIFICATION_EVENT_MIGRATION_ID → 2, durability → 12. ⇒ the zeros are readings.
Filed unassigned and ungraded — domain:* and priority are triage's.
The gap
scripts/check-durability-degradation-log-level.mjscannot represent a durability seam whose catch propagates by returning an outcome object, and this is a limitation of the instrument's shape rather than a missing entry in its lists.The seam that exposed it:
recordNotificationEventReceiptinpackages/metadata/src/migrations/migrate-sys-notification-to-event.ts(added by PR #16230).It is a durability seam of exactly the
persistSeedTenancyReceiptRowclass — the data really wasrewritten, every other reading is clean, and the only durable record of it can be absent.
Why the gate cannot hold it:
DURABILITY_CRITICAL_CALLEESdoes not name it — that part is merely an entry.outcome object, while both
FAILURE_PROPAGATION_CALLEESandFAILURE_PROPAGATION_SITESarekeyed on callee NAMES. A returned object literal has none.
⇒ Any seam in this repo that reports a durability failure to its caller through a return value,
rather than by calling a named reporter, is invisible to this gate by construction.
What was measured, and what was not
adr-0030-notification-eventmigration writes itssys_migrationreceipt row per the ruled ledger-claim matrix —last_run_aton every completed run,applied_atonmigratedonly, neververified_at(#15710 follow-on) #16100 round, on its own diff): the gate's write-side limb reports 29seams both with and without the new file — i.e. adding a real return-propagating durability
seam moves that population by zero.
limb moves 68 → 67 when the same file is swapped back to
origin/main. ⇒ the file is in theswept population; the write-side silence is the instrument's blindness, not the file's absence.
failedreceiptcase, so this is an instrument-expressiveness gap, ⛔ not an unprotected degradation. Hence
finding, notbug.thing a round on this card should buy, because it decides whether the fix is worth its cost — a
gap with one member is a note, a gap with thirty is a hole.
Why the shape of the fix is not obvious
A name-keyed list cannot key on "returns an object with a failure-shaped field". The candidate
directions each cost something and none is free:
cheap, but it moves the gate from "what does this call do" to "who is asking", which is a
different question and may weaken the existing 29.
it needs the gate to read types, which it currently does not.
card's answer a documented boundary rather than a hole.
⛔ This card proposes none of them. It records the gap, its measurement, and its control.
This is now the third open finding against this one script, alongside a decision and a blocked
triage card:
pm:on-holdcollectLoggedLevelsonly records part of what it shouldpm:on-holdreadInventionKeyfalls back where it should notpm:on-holdpm:blocked⇒ Five open items on one instrument. Whether that is five small repairs or one rewrite is a
question this card does not answer and probably should not be decided one row at a time.
Provenance and dedup
Found by the #16100 execution round, which could not file it itself and said so rather than
guessing: filing without a duplicate check is a forbidden shape, and its dedup channel was gone in
both directions — REST
/search/issuesis not served on that channel (a same-session control querythat must have hit #16100 came back empty, so its zero was a channel artefact, not a reading),
and both
search_issuesMCP calls were refused by the user-level rate limit. It handed the row tothe PM seat instead. Its full reasoning:
#16100 (comment)
Dedup performed by this seat, over a complete enumeration rather than a search: all 652 open
issues fetched with bodies (651 of 652 carry one) and grepped locally.
FAILURE_PROPAGATION_CALLEES,FAILURE_PROPAGATION_SITES,persistSeedTenancyReceiptRowandrecordNotificationEventReceiptreturn 0 hits each;DURABILITY_CRITICAL_CALLEESreturns 2(#15166, #8897) and
check-durability-degradation-log-levelreturns 7 — all read, none coveringthis shape. Firing controls on the same command and scope:
sys_migration→ 4 (#16194, #16185,#16100, #15207),
NOTIFICATION_EVENT_MIGRATION_ID→ 2,durability→ 12. ⇒ the zeros are readings.Filed unassigned and ungraded —
domain:*and priority are triage's.Generated by Claude Code