fix(native-chat): narrow the retraction frame through its own type

Typecheck caught what the tests could not: `removed` is not on
RuntimeMobileSessionTabsResult. The repo already names the shape —
RuntimeMobileSessionTabsRemovedResult — so this reads it through a guard rather
than the inline cast the mainstream path uses.
This commit is contained in:
Merge Sim
2026-09-05 20:06:43 -07:00
parent f24dc45035
commit ca7119c4d2
@@ -1,4 +1,7 @@
import type { RuntimeMobileSessionTabsResult } from '../../../../shared/runtime-types'
import type {
RuntimeMobileSessionTabsRemovedResult,
RuntimeMobileSessionTabsResult
} from '../../../../shared/runtime-types'
import type { WorktreeRuntimeOwnerState } from '../../lib/worktree-runtime-owner'
import { getExecutionHostIdForWorktree } from '../../lib/worktree-runtime-owner'
import {
@@ -26,6 +29,13 @@ import { hostSnapshotAffirmsWorktreeContents } from '../host-session-snapshot-au
export const LOCAL_STRUCTURED_SESSION_OWNER = 'local-structured-session'
/** The host saying it no longer publishes this worktree at all, rather than publishing an empty one. */
function isWorktreeRetraction(
snapshot: RuntimeMobileSessionTabsResult
): snapshot is RuntimeMobileSessionTabsRemovedResult {
return (snapshot as Partial<RuntimeMobileSessionTabsRemovedResult>).removed === true
}
export function applyStructuredSessionTabSnapshots(
snapshots: readonly RuntimeMobileSessionTabsResult[],
owner = LOCAL_STRUCTURED_SESSION_OWNER
@@ -104,7 +114,7 @@ export function applyLocalStructuredSessionTabSnapshots<
}
)
next = patch === next ? next : ({ ...next, ...patch } as State)
if (snapshot.removed === true) {
if (isWorktreeRetraction(snapshot)) {
// A retraction was applied above — the mirrored rows must go — but it is not a publication
// to fence later frames against. Recording it would retire the renderer's own epoch, which
// is one string for the whole process lifetime, and every republication afterwards would be