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
Filed by the PM seat as the ruling on PR #9750's open question. The #9657 dev measured this, recommended it, and explicitly declined to take it because pricing the scan population is a lane-PM call. Ruled B.
The defect, in one line
An optional error with no declared alternative is a contract that permits silence.
How it was found
PR #9750 tightened check-durability-degradation-log-level so an optional call (logger.error?.(…)) no longer counts as a loud report — because against a sink with no error, that spelling emits nothing. The tightening turned up six real seams, and every single one was on a sink whose error is declared optional:
package
sink type
plugin-audit ×3
AuthEventAuditLogger, ReadAuditLogger
plugin-email
SweepLogger
plugin-security ×2
ProjectionLogger — whose own comment calls error the "durability-degradation channel"
And the sharpest instance: AuthEventAuditLogger declared error? and debug? and NO warn at all. At that call site there was no fallback channel to reach for, and tsc said so when the dev tried to write the correct shape. Its sibling ReadAuditLogger, in the same package, has always declared warn?. The call site could not have been written correctly against the contract it was given.
⇒ This is a producer defect. AGENTS.md says to fix those in the producer, not with per-site vigilance.
The three options, and why B
option
verdict
A
Leave the sink types as they are (optional error, now with a warn beside it everywhere after #9750) and let the gate keep judging call sites
⛔ leaves a live foot-gun — the contract still permits a silence the gate must catch case by case, forever
B
Require warn on any sink type that declares an optional error, enforced by a small gate over the logger-ish interfaces
✅ ruled
C
Make errorrequired on these sink interfaces (the kernel Logger already requires it)
⛔ falsified today — hosts do inject reduced sinks (SqlDriver's error? exists for exactly that), so C forecloses the legitimate { warn }-only host the drivers were explicitly written for, and it breaks three exported plugin types
The deciding argument is authoring-time, and it is the dev's:
an AI writing a new durability report reads the interface, sees error?and nothing else, and writes error?.(…)
B makes that impossible at the point of authoring. A catches it one gate-run later, every time, forever.
⚠️ The hard part is the population, not the rule
The dev named this precisely and it is why the card exists instead of a PR: drawing the set of "logger-ish interfaces" is a fuzzy-scope problem, and check-durability-degradation-log-level.mjs's own header warns that a gate whose scope is fuzzy is the kind people disable.
So whoever takes this must price the population before writing the rule:
How is the set drawn? Candidates, each with a different failure mode — a name convention (*Logger); structural (an interface whose members are a subset of {error, warn, info, debug, log, fatal}); a declared list in the gate; an explicit marker on the type. Structural is the only one that cannot silently miss a type someone names differently — but it may sweep in unrelated shapes. Measure how many each admits before choosing.
What is the rule exactly? "Optional error ⇒ a non-optional alternative channel must be declared" is the minimum. Whether the alternative must be warn specifically, or any of {warn, info, log}, is a judgement — say which and why.
Both directions, and a --self-test in the file's established style, with every limb observed failing and observed silent.
Not in scope
⛔ Not option C. Do not make error required on the plugin sink types.
⛔ Not a new required context; this argues for a producer-side constraint, not more merge-blocking.
Related
#9657 / PR #9750 (where this was measured) · #9748 (the summary-report sibling, pm:blocked) · #8897 · #9165 (the family disposition) · #9747 — this is the sink-TYPE axis of that card's meta-shape, alongside the call-shape axis. #9747 asks for "unrecognised" to be a distinct verdict; this card asks for one class of unrecognisable contract to stop existing.
Filed by the PM seat as the ruling on PR #9750's open question. The #9657 dev measured this, recommended it, and explicitly declined to take it because pricing the scan population is a lane-PM call. Ruled B.
The defect, in one line
How it was found
PR #9750 tightened
check-durability-degradation-log-levelso an optional call (logger.error?.(…)) no longer counts as a loud report — because against a sink with noerror, that spelling emits nothing. The tightening turned up six real seams, and every single one was on a sink whoseerroris declared optional:AuthEventAuditLogger,ReadAuditLoggerSweepLoggerProjectionLogger— whose own comment callserrorthe "durability-degradation channel"And the sharpest instance:
AuthEventAuditLoggerdeclarederror?anddebug?and NOwarnat all. At that call site there was no fallback channel to reach for, andtscsaid so when the dev tried to write the correct shape. Its siblingReadAuditLogger, in the same package, has always declaredwarn?. The call site could not have been written correctly against the contract it was given.⇒ This is a producer defect. AGENTS.md says to fix those in the producer, not with per-site vigilance.
The three options, and why B
error, now with awarnbeside it everywhere after #9750) and let the gate keep judging call siteswarnon any sink type that declares an optionalerror, enforced by a small gate over the logger-ish interfaceserrorrequired on these sink interfaces (the kernelLoggeralready requires it)SqlDriver'serror?exists for exactly that), so C forecloses the legitimate{ warn }-only host the drivers were explicitly written for, and it breaks three exported plugin typesThe deciding argument is authoring-time, and it is the dev's:
B makes that impossible at the point of authoring. A catches it one gate-run later, every time, forever.
The dev named this precisely and it is why the card exists instead of a PR: drawing the set of "logger-ish interfaces" is a fuzzy-scope problem, and
check-durability-degradation-log-level.mjs's own header warns that a gate whose scope is fuzzy is the kind people disable.So whoever takes this must price the population before writing the rule:
*Logger); structural (an interface whose members are a subset of{error, warn, info, debug, log, fatal}); a declared list in the gate; an explicit marker on the type. Structural is the only one that cannot silently miss a type someone names differently — but it may sweep in unrelated shapes. Measure how many each admits before choosing.error⇒ a non-optional alternative channel must be declared" is the minimum. Whether the alternative must bewarnspecifically, or any of{warn, info, log}, is a judgement — say which and why.--self-testin the file's established style, with every limb observed failing and observed silent.Not in scope
errorrequired on the plugin sink types.Related
#9657 / PR #9750 (where this was measured) · #9748 (the summary-report sibling,
pm:blocked) · #8897 · #9165 (the family disposition) · #9747 — this is the sink-TYPE axis of that card's meta-shape, alongside the call-shape axis. #9747 asks for "unrecognised" to be a distinct verdict; this card asks for one class of unrecognisable contract to stop existing.Generated by Claude Code