mirror of
https://github.com/stablyai/orca.git
synced 2026-10-04 08:02:09 +00:00
FolderWorkspacePathStatus is cast, not decoded, off the runtime RPC wire -- runtime-rpc-envelope declares result: z.unknown(), so unwrapRuntimeRpcResult hands back whatever the host sent. Both title and description switch on status.reason with no runtime guard, so a newer host publishing a fifth reason matched nothing and returned undefined. FolderPathStatusIndicator's `!title` check then dropped the whole indicator, and a broken folder workspace rendered as healthy -- worse than the blank toast #15002 fixed, because there the warning was empty and here it is gone. Guard before each switch, the shape #15002 landed. A default: arm is not available: the type-aware config sets allowDefaultCaseForExhaustiveSwitch:false and rejects one with switch-exhaustiveness-check. Extract that guard into isHandledWireDiscriminant instead of hand-writing a third and fourth copy, and move #15002's two bespoke guards onto it. It takes unknown and checks typeof before Object.hasOwn -- hasOwn coerces its key, so a host that widened the field to an array sends ['missing'], which a hasOwn-only guard admits before the switch drops it straight back out. That was the P1 found in review on #15002; one implementation makes it structural instead of tribal. An unrecognized reason gets its own copy rather than reusing 'unavailable'. The unavailable remedy -- "Check the runtime or SSH connection and try again" -- is a false lead here: the host did check and reported the folder unusable, so retrying and inspecting a healthy connection wastes the user's time. Update Orca is the real remedy. Adding a fifth reason still fails typecheck in two places: TS2741 on the Record and TS2366 plus switch-exhaustiveness-check on both switches.
16 lines
880 B
TypeScript
16 lines
880 B
TypeScript
// Why: runtime RPC results are cast, not decoded — `runtime-rpc-envelope` declares `result:
|
|
// z.unknown()` — so a host on a newer build routinely puts a discriminant on the wire that this
|
|
// build's union has never heard of, and a switch on it falls through to `undefined`.
|
|
//
|
|
// Callers pass a `Record<TheUnion, true>` so a new union member fails typecheck twice: on the Record
|
|
// (TS2741) and on the switch (`switch-exhaustiveness-check`, which forbids an absorbing `default:`).
|
|
//
|
|
// typeof first: `Object.hasOwn` coerces its key, so a host that widened the field to an array sends
|
|
// `['missing']`, which a hasOwn-only guard admits before the switch drops it straight back out.
|
|
export function isHandledWireDiscriminant<T extends string>(
|
|
value: unknown,
|
|
handled: Record<T, true>
|
|
): value is T {
|
|
return typeof value === 'string' && Object.hasOwn(handled, value)
|
|
}
|