Skip to content

The logger?.error?.(…) spelling also carries two SUMMARY durability reports that no catch guards, so no gate can see them #9748

Description

@os-steve

Filed unassigned by the dev seat implementing #9657, session session_01XqDQYVU5smx29ts9pAErja. Not a claim. Duplicate-searched by keyword and by spelling first.

What #9657 left standing

#9657 makes check:durability-log-level reject logger.error?.(…) as a way to satisfy the rule: error is declared optional on these sinks, so an optional call emits nothing when the method is absent. Six seams were repaired there — every one the gate can reach.

The gate only judges a call inside a catch that guards a declared durability-critical callee. Two reports in the same two files are spelled identically and are outside any such catch, so nothing flags them and #9657's PR deliberately left them alone:

sitewhat is lost when the sink has no error
packages/plugins/plugin-email/src/outbox-sweep.ts:227the batch summary — "N stranded sys_email row(s) could NOT be delivered". Accepted mail that never reached a recipient, reported to nobody.
packages/plugins/plugin-security/src/permission-set-projection.ts:1067the reconcile summary — "N FAILED backfill(s)". Its own comment says an info "reconciled" line over a failed backfill is "the reassuring half-truth this rule exists to remove" — and against an error-less sink it prints neither.

Both are the SUMMARY of a per-row failure that #9657 did repair, so on an error-less sink the per-row line now lands at warn while the summary that counts them stays silent. That split is the reason to record this rather than leave it: the counts and the detail now report through different channels.

Why this is not simply "sweep the spelling"

45 non-test call sites in packages/ use .error?.(. Most are not durability reports at all, and the spelling is correct wherever the sink genuinely has no alternative. Deciding which are which is the judgement, and it is exactly the judgement DURABILITY_CRITICAL_CALLEES exists to avoid making by heuristic. Options, none free:

  1. Repair these two by hand (they are named above, and both files already carry the fallback shape from check-durability-degradation-log-level: loggerLevel cannot see the (logger.error ?? logger.warn)(…) fallback, so a loud catch reads as silent-swallow — and the spelling it CAN see prints nothing #9657's PR — the edit is mechanical and local). Leaves the class open.
  2. Extend the gate's population so a summary line about failures it already counted is judged, e.g. keying on the accumulator the catch wrote to rather than on the catch. That is check-durability-degradation-log-level: the read-seam invention rule keys on return, so a catch that degrades by FALLING THROUGH into an empty accumulator is structurally invisible #8845's blind spot from the other side, and it is a scope change to the rule, not a vocabulary addition.
  3. Record and do nothing — the per-row report is repaired, so the operator is no longer blind, only under-counted.

⛔ No recommendation between 2 and 3: it is the same population-vs-criterion choice the #9165 disposition ruled on for the sibling gate, and pricing it is a lane-PM call rather than a fact I measured. Option 1 is cheap enough that it may not need the other two decided first.

Not claimed

Related: #9657 (the matcher + the six repaired seams) · #8845 (the read-seam rule's exit-shape blind spot) · #9165 (the disposition that framed this family).

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions