Filed from #8845's measurement (the gate card measured this class and deliberately did not extend the rule; these seams therefore need their own disposition). Unassigned. Not a claim.
Measured on origin/main @ 8664a2c, across the read-seam rule's three scan roots.
The shape
A catch that returns nothing — it falls through, or jumps — above a value that was supposed to be filled by the read. The caller receives an answer indistinguishable from a legitimate one, and no surface says otherwise. Per ADR-0110 D3 those are different facts.
check:durability-log-level cannot see any of these: its read-seam rule classifies a catch by the expression it returns, and these return none. All five are counted in its census and reported as no invented answer.
The set
Excluding diffMetaItem (that seam's disposition is #8833, with the maintainer) and cascadeDeleteRelations (filed separately as #8895 — it is an integrity bypass, not a reporting gap).
| seam | what the caller gets |
|---|
metadata-protocol/src/seed-loader.ts:2058loadExistingRecords() | catch { /* Object may not have records yet */ } returns an empty Map. The upsert-key match then finds nothing, so "cannot read the object" is treated as "no existing rows" — the replay-skip decision this map exists to make is inverted, and the loader writes rows it should have skipped. |
metadata-protocol/src/protocol.ts:8961searchAll() | Per-object catch { continue; }. Objects whose read failed contribute no hits, but the response still reports totalHits: hits.length and truncated as though the scan were complete. |
metadata-protocol/src/protocol.ts:16982findReferencesToMeta() | Per-matcher catch { return; } inside a Promise.all. The returned out[] is silently missing every reference from the source types whose read failed — and this answer drives "what would break if I delete this". |
metadata-protocol/src/protocol.ts:4733getMetaDiagnostics() | catch { continue; } drops the whole type from the diagnostics report. The comment reads "Type not listable in this kernel scope", which is one real reason among several; a store outage produces the same silent omission. |
objectql/src/lifecycle/lifecycle-service.ts:805checkGovernance() | catch { continue; } on the row count. The object is skipped for quota and growth alerting, and is also dropped from nextCounts, so the growth baseline for the next sweep is lost too. |
Lowest-severity first read: the last two are reduced functionality; the first three hand a caller an answer it will act on.
A sixth, different in kind
metadata-protocol/src/protocol.ts:13830publishPackageDrafts() does not fall through — it pushes a fabricated entry:
}catch{commitItems.push({type: d.type,name: d.name,existedBefore: false,prevVersion: null});}Two things to check there. existedBefore: false means "revert = soft-remove"; if the item did exist, a later revert deletes it instead of restoring the previous version. And the comment five lines above says a capture failure "just omits that item from the revert plan", which is not what the code does. Either the comment or the code is wrong; worth a look from whoever owns the revert plan.
Suggested disposition
These share one question — what should a read seam do when the read fails and the answer is an accumulator? — and the repo already has both answers in its vocabulary: discriminate with isMissingTableError and treat only that as truthful emptiness, or carry an explicit "incomplete" fact in the response. Several of the correct seams nearby already do the second (build-probes' issues[], the dangling-reference audit's report.unreadableObjects, history-cleanup's errors counter).
Related
Filed from #8845's measurement (the gate card measured this class and deliberately did not extend the rule; these seams therefore need their own disposition). Unassigned. Not a claim.
Measured on
origin/main@8664a2c, across the read-seam rule's three scan roots.The shape
A
catchthat returns nothing — it falls through, or jumps — above a value that was supposed to be filled by the read. The caller receives an answer indistinguishable from a legitimate one, and no surface says otherwise. Per ADR-0110 D3 those are different facts.check:durability-log-levelcannot see any of these: its read-seam rule classifies a catch by the expression it returns, and these return none. All five are counted in its census and reported asno invented answer.The set
Excluding
diffMetaItem(that seam's disposition is #8833, with the maintainer) andcascadeDeleteRelations(filed separately as #8895 — it is an integrity bypass, not a reporting gap).metadata-protocol/src/seed-loader.ts:2058loadExistingRecords()catch { /* Object may not have records yet */ }returns an emptyMap. The upsert-key match then finds nothing, so "cannot read the object" is treated as "no existing rows" — the replay-skip decision this map exists to make is inverted, and the loader writes rows it should have skipped.metadata-protocol/src/protocol.ts:8961searchAll()catch { continue; }. Objects whose read failed contribute no hits, but the response still reportstotalHits: hits.lengthandtruncatedas though the scan were complete.metadata-protocol/src/protocol.ts:16982findReferencesToMeta()catch { return; }inside aPromise.all. The returnedout[]is silently missing every reference from the source types whose read failed — and this answer drives "what would break if I delete this".metadata-protocol/src/protocol.ts:4733getMetaDiagnostics()catch { continue; }drops the whole type from the diagnostics report. The comment reads "Type not listable in this kernel scope", which is one real reason among several; a store outage produces the same silent omission.objectql/src/lifecycle/lifecycle-service.ts:805checkGovernance()catch { continue; }on the rowcount. The object is skipped for quota and growth alerting, and is also dropped fromnextCounts, so the growth baseline for the next sweep is lost too.Lowest-severity first read: the last two are reduced functionality; the first three hand a caller an answer it will act on.
A sixth, different in kind
metadata-protocol/src/protocol.ts:13830publishPackageDrafts()does not fall through — it pushes a fabricated entry:Two things to check there.
existedBefore: falsemeans "revert = soft-remove"; if the item did exist, a later revert deletes it instead of restoring the previous version. And the comment five lines above says a capture failure "just omits that item from the revert plan", which is not what the code does. Either the comment or the code is wrong; worth a look from whoever owns the revert plan.Suggested disposition
These share one question — what should a read seam do when the read fails and the answer is an accumulator? — and the repo already has both answers in its vocabulary: discriminate with
isMissingTableErrorand treat only that as truthful emptiness, or carry an explicit "incomplete" fact in the response. Several of the correct seams nearby already do the second (build-probes'issues[], the dangling-reference audit'sreport.unreadableObjects,history-cleanup'serrorscounter).Related
return, so acatchthat degrades by FALLING THROUGH into an empty accumulator is structurally invisible #8845 — the measurement card; its PR records why the gate was not extended to catch this shape.diffMetaItem, the same shape,needs-user-decisionwith the maintainer.restrictguard entirely, so a delete that should be refused succeeds silently #8895 —cascadeDeleteRelations, same shape, split out for severity.check:durability-log-level结构性看不见「读接缝把故障答成空值」这一类 —— #4825 / #5108 全家都在闸门盲区里 #5186 / finding(devx): #5186 读接缝规则的「编造空答案」词表看不见「原样返回入参」这一形状 —— #6116 是实证样本 #6451 — the rule and its prior extension.