mirror of
https://github.com/stablyai/orca.git
synced 2026-10-25 16:03:53 +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.
35 lines
1.5 KiB
TypeScript
35 lines
1.5 KiB
TypeScript
import { describe, expect, it } from 'vitest'
|
|
import { isHandledWireDiscriminant } from './handled-wire-discriminant'
|
|
|
|
const HANDLED: Record<'missing' | 'unavailable', true> = {
|
|
missing: true,
|
|
unavailable: true
|
|
}
|
|
|
|
describe('isHandledWireDiscriminant', () => {
|
|
it('admits the handled members', () => {
|
|
expect(isHandledWireDiscriminant('missing', HANDLED)).toBe(true)
|
|
expect(isHandledWireDiscriminant('unavailable', HANDLED)).toBe(true)
|
|
})
|
|
|
|
it('rejects a member this build has never heard of', () => {
|
|
expect(isHandledWireDiscriminant('permission-denied', HANDLED)).toBe(false)
|
|
})
|
|
|
|
// Why: Object.hasOwn coerces its key, so a guard typed (x: string) admits ['missing'] — whose
|
|
// toString matches a handled key — and the value then falls straight back out of the switch.
|
|
// This is the P1 found in review on #15002; it is the reason the parameter is `unknown`.
|
|
it('rejects a non-string the wire can carry', () => {
|
|
for (const value of [['missing'], null, undefined, 0, true, { missing: true }, Symbol('x')]) {
|
|
expect(isHandledWireDiscriminant(value, HANDLED), String(value)).toBe(false)
|
|
}
|
|
})
|
|
|
|
// Why: hasOwn, not `in` — inherited keys are not handled members.
|
|
it('does not admit inherited object keys', () => {
|
|
expect(isHandledWireDiscriminant('toString', HANDLED)).toBe(false)
|
|
expect(isHandledWireDiscriminant('constructor', HANDLED)).toBe(false)
|
|
expect(isHandledWireDiscriminant('__proto__', HANDLED)).toBe(false)
|
|
})
|
|
})
|