Observation class — recording only, no verdict asserted, no pm:queue. Unassigned. Found while measuring for #11921 (PR #12137); ⛔ deliberately not fixed there — #11921 forbids its fix riding along with any other change.
Measured on origin/main @ 8619f9513.
What I found
isReadCall() (scripts/check-durability-degradation-log-level.mjs) follows a same-file wrapper by walking the wrapper's body with walkSameTickInclusive, which refuses to descend into anything runsLater() calls a later body — every FunctionExpression and ArrowFunction included.
For the try block that refusal is correct and documented at the top of the file:
Nested function bodies inside the try are NOT descended into: a callback registered inside a try (ctx.hook('kernel:ready', async () => …)) runs later and is not guarded by that catch.
For a wrapper body the question is a different one, and the same answer is not obviously right. A wrapper whose driver read sits inside a synchronously invoked callback —
async function loadAll(ids: string[]) {
return Promise.all(ids.map((id) => this.driver.findOne(TABLE, { where: { id } })));
}
— does perform the read on the caller's behalf, inside the caller's try. runsLater() cannot tell that arrow apart from a deferred hook callback, so the wrapper reports "no read" and its caller's try/catch never enters the read-seam population at all.
How big, honestly bounded
Replacing walkSameTickInclusive with walkAll in the wrapper recursion only (a throwaway probe, not a proposed fix) moves the census over the three scan roots:
| recognizer |
read seams |
today (walkSameTickInclusive) |
64 |
probe (walkAll) |
72 |
⚠️ 8 is an upper bound, not the number. walkAll also descends into genuinely deferred callbacks — the ctx.hook(...) shape the header names — which correctly should not count. Telling "invoked now" from "invoked later" needs to know what the receiving method does with its argument, which is the same provenance problem #11921 is about. Somewhere between 0 and 8 of those 8 are real misses; nobody has read them one by one, and I did not, because that is the triage this filing is asking for rather than performing.
Direction of the error
Under-count, which is the safe direction for a gate: a real read seam is missing from the population rather than a fake one being added. But it is the same class of cost #11921 records — the read-seam census is the denominator for #5186, #6451, #9165, #8845 and #8901, and a denominator that silently omits members is as hard to reason about as one that silently includes them.
Nothing is broken and no verdict is wrong today: this is an invisibility, not a misclassification, so no site's grade changes either way.
Related
Dedupe performed
⚠️ The prescribed channel was unavailable, and this is declared rather than papered over: direct GitHub REST from this seat returns "GitHub access is not enabled for this session" to curl and gh is not installed — the condition already filed as #12123. The dedupe therefore ran through one bounded MCP list_issues call: 24 open finding issues, a non-empty control. None addresses isReadCall, the wrapper recursion, walkSameTickInclusive, or the read-seam population; the nearest neighbours are unrelated gates (#12064 bare-root-worklist, #12046 turbo task-graph). A local grep over the gate file confirms the narrowness is recorded for the try side only (top-of-file, "Nested function bodies inside the try") and nowhere for the wrapper side.
Generated by Claude Code
Observation class — recording only, no verdict asserted, no
pm:queue. Unassigned. Found while measuring for #11921 (PR #12137); ⛔ deliberately not fixed there — #11921 forbids its fix riding along with any other change.Measured on
origin/main@8619f9513.What I found
isReadCall()(scripts/check-durability-degradation-log-level.mjs) follows a same-file wrapper by walking the wrapper's body withwalkSameTickInclusive, which refuses to descend into anythingrunsLater()calls a later body — everyFunctionExpressionandArrowFunctionincluded.For the
tryblock that refusal is correct and documented at the top of the file:For a wrapper body the question is a different one, and the same answer is not obviously right. A wrapper whose driver read sits inside a synchronously invoked callback —
— does perform the read on the caller's behalf, inside the caller's
try.runsLater()cannot tell that arrow apart from a deferred hook callback, so the wrapper reports "no read" and its caller'stry/catchnever enters the read-seam population at all.How big, honestly bounded
Replacing
walkSameTickInclusivewithwalkAllin the wrapper recursion only (a throwaway probe, not a proposed fix) moves the census over the three scan roots:walkSameTickInclusive)walkAll)walkAllalso descends into genuinely deferred callbacks — thectx.hook(...)shape the header names — which correctly should not count. Telling "invoked now" from "invoked later" needs to know what the receiving method does with its argument, which is the same provenance problem #11921 is about. Somewhere between 0 and 8 of those 8 are real misses; nobody has read them one by one, and I did not, because that is the triage this filing is asking for rather than performing.Direction of the error
Under-count, which is the safe direction for a gate: a real read seam is missing from the population rather than a fake one being added. But it is the same class of cost #11921 records — the read-seam census is the denominator for #5186, #6451, #9165, #8845 and #8901, and a denominator that silently omits members is as hard to reason about as one that silently includes them.
Nothing is broken and no verdict is wrong today: this is an invisibility, not a misclassification, so no site's grade changes either way.
Related
check:durability-log-level's read-seam population admits a catch that guards no storage read —isReadCall()matches the callee NAME with no receiver check, soArray.prototype.findpulls a try/catch in #11921 / PR fix(gate): read-seam recognizer matched a callee NAME with no shape check, soArray.prototype.findpulled non-read catches into the census #12137 — the mirror-image defect (name matching with no provenance), where the error ran the other way.collectLoggedLevelsonly recognises a logger named logger/log/console, so a catch that reports through an injected logger reads as silent to BOTH rules #8897 — the receiver-name narrowness in the same file, decided (option 1) in PR fix(gate): read-seam recognizer matched a callee NAME with no shape check, soArray.prototype.findpulled non-read catches into the census #12137.Dedupe performed
curlandghis not installed — the condition already filed as #12123. The dedupe therefore ran through one bounded MCPlist_issuescall: 24 openfindingissues, a non-empty control. None addressesisReadCall, the wrapper recursion,walkSameTickInclusive, or the read-seam population; the nearest neighbours are unrelated gates (#12064bare-root-worklist, #12046 turbo task-graph). A localgrepover the gate file confirms the narrowness is recorded for thetryside only (top-of-file, "Nested function bodies inside thetry") and nowhere for the wrapper side.Generated by Claude Code