@@ -31,6 +31,11 @@ const makeLiveSlots: MakeLiveSlotsFn = localMakeLiveSlots;
3131// eslint-disable-next-line n/no-unsupported-features/node-builtins
3232export type FetchBlob = ( bundleURL : string ) => Promise < Response > ;
3333
34+ type SupervisorRpcClient = Pick <
35+ RpcClient < typeof vatSyscallMethodSpecs > ,
36+ 'notify' | 'handleResponse'
37+ > ;
38+
3439type SupervisorConstructorProps = {
3540 id : VatId ;
3641 kernelStream : DuplexStream < JsonRpcMessage , JsonRpcMessage > ;
@@ -54,7 +59,7 @@ export class VatSupervisor {
5459 readonly #logger: Logger ;
5560
5661 /** RPC client for sending syscall requests to the kernel */
57- readonly #rpcClient: RpcClient < typeof vatSyscallMethodSpecs > ;
62+ readonly #rpcClient: SupervisorRpcClient ;
5863
5964 /** RPC service for handling requests from the kernel */
6065 readonly #rpcService: RpcService < typeof vatHandlers > ;
@@ -74,9 +79,6 @@ export class VatSupervisor {
7479 /** Capability to fetch the bundle of code to run in this vat. */
7580 readonly #fetchBlob: FetchBlob ;
7681
77- /** Result promises from all syscalls sent to the kernel in the current crank */
78- readonly #syscallsInFlight: Promise < unknown > [ ] = [ ] ;
79-
8082 /**
8183 * Construct a new VatSupervisor instance.
8284 *
@@ -177,17 +179,15 @@ export class VatSupervisor {
177179 * @returns a syscall success result.
178180 */
179181 executeSyscall ( vso : VatSyscallObject ) : VatSyscallResult {
180- this . #syscallsInFlight. push (
181- // IMPORTANT: Syscall architecture design explanation:
182- // - Vats operate on an "optimistic execution" model - they send syscalls and continue execution
183- // without waiting for responses, assuming success.
184- // - The Kernel processes syscalls asynchronously and failures are catched in VatHandle.
185- this . #rpcClient
186- . call ( 'syscall' , coerceVatSyscallObject ( vso ) )
187- // We catch these rejections here to prevent unhandled promise rejections,
188- // as they're an expected part of the architecture, not errors
189- . catch ( ( ) => undefined ) ,
190- ) ;
182+ // IMPORTANT: Syscall architecture design explanation:
183+ // - Vats operate on an "optimistic execution" model - they send syscalls and continue execution
184+ // without waiting for responses, assuming success.
185+ // - The Kernel processes syscalls synchronously on receipt and failures are caught in VatHandle.
186+ // - The vat is terminated and the crank is rolled back if a syscall fails.
187+ this . #rpcClient
188+ . notify ( 'syscall' , coerceVatSyscallObject ( vso ) )
189+ // Just to please the linter (notifications never reject)
190+ . catch ( ( ) => undefined ) ;
191191 return [ 'ok' , null ] ;
192192 }
193193
@@ -204,13 +204,6 @@ export class VatSupervisor {
204204 // Handle delivery errors
205205 deliveryError = error instanceof Error ? error . message : String ( error ) ;
206206 this . #logger. error ( `Delivery error in vat ${ this . id } :` , deliveryError ) ;
207- } finally {
208- // Clean up at the end of a crank
209- this . #syscallsInFlight. length = 0 ;
210- // Reject all pending RPC requests to maintain the optimistic execution model
211- // This prevents late responses from affecting the vat in unexpected ways
212- // between cranks.
213- this . #rpcClient. rejectAll ( new Error ( 'end of crank' ) ) ;
214207 }
215208
216209 // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
0 commit comments