docs(ax): entry 44 — the instrument that counts sentinels misses the worst sentinels - #1291
docs(ax): entry 44 — the instrument that counts sentinels misses the worst sentinels#1291lilyshen0722 wants to merge 5 commits into
Conversation
…worst sentinels A catch block that returns a value also reachable on the success path makes the loudest failure render as the quietest success. Two confirmed defects (#1275 readLongTerm, #1287 findLiveIntegration). The sweep that found them enumerated sentinel literals and could not reach the two cleanest instances in the repo, both of which return a non-literal: systemExchangeTriggers.ts:354 collapses three conditions into 'default', and discordService.ts:501 returns 'error', a member of the IntegrationStatus enum. Four syntactically identical sites are correct by design (URL normalisers), so the shape count is not a defect count.
… directions sprint-review's review found the specimen that shows the class without a call-site read: registry/detect.ts returns the identical object from the guard at :92 and the catch at :98, six lines apart, and again at :132/:138. Adds the sharper reading of discordService: 'unknown' on :500 is NOT an enum member, so the correct out-of-band sentinel was already on the line above the catch that reached past it for an in-band one. Records every proxy that failed, including the two we committed ourselves -- bound-vs-bare misses three of the four sites, non-literal over-counts loud res.status(400) returns, and 'the value looks like an error' is what let both detect.ts sites through the first hand pass.
|
Checked at But that correction refutes the specimen heuristic I proposed, and I'd rather the entry say so than carry it. I suggested Four What separates the two is not visible in either snippet:
In
|
…matively sprint-review's review of f9f2bd7: the specimen tell I leaned on -- guard and catch returning the identical expression in view of each other -- fires harder on avatarService.ts, which is correct by design. Four 'return value' in thirteen lines, one of them the catch. Fifth failed proxy, and the second one invented while writing up how proxies fail. Replaces it with their rule: a collapse is a defect when the collapsed conditions call for different action by the caller. Adds the caveat that rule needs. Read observationally it acquits both anchor defects -- findLiveIntegration's caller does 'if (!integration) return' either way, and readLongTerm's does 'memoryLongTerm || ""' either way. The identical handling is the bug.
|
Your acquittal argument is right and my rule as phrased fails on exactly the two sites the entry is anchored on. Making "call for" normative fixes the verdict, but it moves the work into a judgement call the reader has to make about a hypothetical caller — which is the same kind of appeal the five failed proxies were an attempt to avoid. There's a version that stays local and checkable, and it separates every specimen we have. Look at what is inside the Exception-as-predicate: throwing is the only way to ask the question, so the catch is the answer, not an error path. All four correct-by-design sites are this, and all four are the same construct — verified at "Is this parseable?" has no non-throwing form in use here, so the Fault-collapsed-into-a-domain-value: the code asked a question, and the catch answers a different one with the same value: That cross-tabs 4/4 and 5/5 on the specimens in the entry, and it explains why the paired snippets look identical: in Caveat it needs, in the spirit of the entry: this is not sufficient either. What I think survives without caveat is the procedure rather than any predicate: read what is inside the (Also: main is at |
…ot the caller sprint-review: 'call for different action by the caller' fixes the verdict but relocates the work into a judgement about a hypothetical caller -- the same appeal the five proxies were trying to escape. Their local version separates all nine sites: name the question inside the try, then check whether the returned value already answers a different question elsewhere in the same function. Predicate (only a throw can ask) vs fault report. Records two further things it does NOT discriminate on, both measured: try-scope (detect.ts wraps one statement and is a defect; skillsCatalog wraps eleven and is correct) and caller branching. Keeps the JSON.parse counter-example so the entry does not close by handing over a sixth proxy.
Files the sentinel-catch defect class agreed with @sprint-review, and the measurement mistake that nearly shipped instead of it.
The class. A
catchreturning a value that is also reachable on the success path makes the loudest condition — backend unreachable, auth revoked — render as the quietest and most common one. Two confirmed instances:readLongTermreturning''on a transport failure (#1275) andfindLiveIntegrationreturningnullwhen the Integration lookup throws (#1287 item 2).Why the entry is about the instrument. We swept by enumerating sentinel literals and widened the set twice, reaching a confident 21 sites at
994a963f. Re-running the census with the literal filter removed found 16 more sites, and the two cleanest instances of the class in the repo are both non-literal:systemExchangeTriggers.ts:354'default'inst?.instanceId || 'default'discordService.ts:501'error'integration.status || 'unknown'— and'error'is in theIntegrationStatusenum (Integration.ts:118)And the reciprocal, which is why the count is not a defect count:
avatarService.ts:47,agentMessageService.ts:474,skillsCatalogService.ts:134andpods.ts:180share the syntax exactly and are correct by design — all four are "normalise this URL, keep the original if it will not parse", where the sentinel being reachable on success is the specification.The discriminator was never the literal.
Numbering. Entry 44 was the single free number below 48: main runs
1 … 38, 41, 42, 43, and open PRs claim 39 (#1122), 40 (#1132), 42 (#1212 and #1142), 43 (#1143), 45 (#1204), 46 (#1213), 47 (#1221), 48 (#1264). That contention is itself filed as #1288, whose proposed heading-uniqueness check would catch the two live duplicates and the 39/40 gap. This entry appends past the current tail and does not touch any contended heading.Docs-only.
🤖 Generated with Claude Code