test: finish the Remote-result and picker-split test migrations

Every generated Remote method resolves to `RemoteResult<T>`, so the Gateway
client spec asserts the ok and error branches instead of the unwrapped value
and a throw, and the generator fixtures declare the wrapper in the consumer
face they typecheck. The RPC-failure test splits into the Host error carried
verbatim in the error branch plus a transport throw folded into it.

The runtime client, ui-command and ui-plan benches answer the generated
commands Remote through its result branches and provide the `remote.commands`
namespace their plugins now inject; the ui-command bench also serves the `$on`
the service subscribes on construction.

The directory-picker chooser mounts a backend and its surface as a pair, so the
real-Loader composition serves both surface packages and asserts each entry
arrives and leaves with its backend.
This commit is contained in:
imccyu
2026-08-11 23:33:17 +08:00
parent 03f88e3c3d
commit 92e0e3377f
9 files changed
+138 -64

No files matched your search

@@ -33,7 +33,9 @@ async function bench() {
scopeOf: (c: Context) => scopeOf(c),
})
const commandsRemote = { list: () => Promise.resolve([]) }
ctx.provide('remote', { commands: commandsRemote })
// The service subscribes its cache-invalidation events on construction, so
// the Remote face needs `$on` even where this spec dispatches none.
ctx.provide('remote', { commands: commandsRemote, $on: () => () => {} })
ctx.provide('remote.commands', commandsRemote)
await ctx.plugin(SlotsService).await()
ctx.slots.register({
@@ -40,6 +40,28 @@ interface BenchOptions {
addressed?: SessionId
}
/**
* Fold one programmed answer into the generated Remote face's outcome: a
* resolved value is the ok branch, a rejection is the transport failure the
* carrier reports in the error branch instead of throwing at the caller.
* @param produce - the scripted answer for one Remote method.
* @returns the carried result the service reads.
*/
async function carried<T>(produce: () => Promise<T>) {
try {
return { ok: true as const, value: await produce() }
} catch (error) {
return {
ok: false as const,
error: {
code: 'internal',
message: error instanceof Error ? error.message : String(error),
details: {},
},
}
}
}
async function bench(opts: BenchOptions = {}) {
const ctx = new Context()
const registered = new Map<string, SlashSource>()
@@ -50,21 +72,22 @@ async function bench(opts: BenchOptions = {}) {
const commandsRemote = {
list: async (sessionId: SessionId) => {
listCalls.push({ sessionId })
const value = await (opts.commands ?? (p => Promise.resolve({
commands: p.sessionId === sid('s2') ? S2_CMDS : S1_CMDS,
})))({ sessionId })
return { ok: true as const, value: value.commands }
return await carried(async () => {
const value = await (opts.commands ?? (p => Promise.resolve({
commands: p.sessionId === sid('s2') ? S2_CMDS : S1_CMDS,
})))({ sessionId })
return value.commands
})
},
execute: async (sessionId: SessionId, line: string) => {
executeCalls.push({ sessionId, line })
const fallback = (): Promise<ExecuteValue> => Promise.resolve({ matched: true })
const value = await (opts.execute ?? fallback)({ sessionId, line })
return {
ok: true as const,
value: value.matched
return await carried(async () => {
const fallback = (): Promise<ExecuteValue> => Promise.resolve({ matched: true })
const value = await (opts.execute ?? fallback)({ sessionId, line })
return value.matched
? { commandId: value.commandId ?? 'fake-command', result: { kind: 'success' as const } }
: undefined,
}
: undefined
})
},
}
ctx.provide('slash', {