From 11f79b65cd2e66fa16d7c3a15b59101b5e528f48 Mon Sep 17 00:00:00 2001 From: backryun Date: Sun, 26 Jul 2026 15:52:08 +0900 Subject: [PATCH] refactor(sse): stop isClaudeEventPayload claiming a narrowing it never performs (#8557) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Eight TS2339s in stream.ts read properties off `never`. `never` here did not mean unreachable code — it meant a type predicate was lying. function isClaudeEventPayload(payload: unknown): payload is JsonRecord ... const flushedParsed = bufferedPayload as JsonRecord; const isClaude = isClaudeEventPayload(flushedParsed); } else if (!isClaude) { // JsonRecord minus JsonRecord = never The predicate answers "does this payload carry a Claude event type?" — a question about contents, not type. A Claude event and a non-Claude one are both JsonRecord, so `payload is JsonRecord` narrows nothing; applied to an argument already typed JsonRecord it collapsed the negative branch to `never`, taking `.id` and `.choices` with it. Changed the return type to `boolean`. No call site depended on the narrowing: both other callers pass the value to updateClaudeEmptyResponseLifecycle(), whose parameter is `unknown`, and passthroughTailProcessor.ts already declares this function as `(payload: unknown) => boolean` — so this aligns the definition with how the codebase already consumes it. 280 -> 272, zero new, on a line-number-agnostic diff of the full tsc error set. The diff is one line, and a type predicate has no runtime representation, so the emitted JavaScript is unchanged. No test added, and no gap to fill: the `never`-typed branch is real, reachable and already covered from both sides — stream-numeric-ids.test.ts exercises "normalizes numeric id in final chunk without trailing newline" (the flush path with a non-Claude payload, i.e. the branch TS believed impossible) and "Claude passthrough does not normalize numeric ids" (the other arm). 338/338 across the 48 SSE/passthrough suites. No explanatory comment either: stream.ts sits exactly at its frozen file-size cap (2887), so a single added line fails check:file-size. The reasoning lives here and in the PR rather than costing a baseline bump on a frozen file. Co-authored-by: backryun --- open-sse/utils/stream.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/open-sse/utils/stream.ts b/open-sse/utils/stream.ts index 60fe7d7fe9..d6f9312c2d 100644 --- a/open-sse/utils/stream.ts +++ b/open-sse/utils/stream.ts @@ -485,7 +485,7 @@ function getClaudeEventType(payload: unknown): string | null { return typeof type === "string" ? type : null; } -function isClaudeEventPayload(payload: unknown): payload is JsonRecord { +function isClaudeEventPayload(payload: unknown): boolean { return getClaudeEventType(payload) !== null; }