Skip to main content
Version: 0.1.0-alpha.4 (alpha)

Generic invocation service

latent-wire::invocation implements the generated Tonic Invoke, Cancel, and GetActivation methods. LocalInvocationRuntime connects the adapter to LocalActivationManager, the existing activation lifecycle and bounded journal. The service remains embeddable. The standalone Linux node supplies listener configuration, trusted authentication and shared runtime composition (#14).

Generated RPC foundation​

latent-rpc generates the authoritative Protobuf messages, clients, server trait, server wrapper, and descriptor set from api/proto. The adapter reuses these outputs directly. InvocationServiceAdapter::new(runtime, limits) validates its configuration; with_services additionally injects the clock, principal policy, and trace source. into_server applies the message ceiling to both decoding and encoding.

Conversions preserve optional presence, the three outcome categories, every budget and accounting field, ordered structured error details, and map values. The descriptor golden protects field numbers, cardinality, oneofs, enums, service methods, and reserved fields.

One lifecycle owner​

The adapter validates a request and supplies its trusted principal and trace in InvocationCommand. LocalInvocationRuntime translates that command into ActivationRequest with retry_attempt = 0. The protocol has no caller retry field; arbitrary metadata does not change it.

LocalInvocationRuntime::invoke calls LocalActivationManager::start_with_deadline synchronously before returning its future. The resulting handle owns the exact accepted identity, pinned route, accounting, preparation, cell cleanup, and terminal publication. The adapter creates no parallel status map, detached execution task, or second activation lifecycle.

Standalone supplies LocalInvocationRuntime::with_cleanup with a bounded node-owned supervisor. The bridge reserves a continuation slot before accepting an identity, so a closed or full supervisor rejects before activation work.

Once accepted, a caller-supplied activation ID supports status and cancellation while the unary Invoke is still pending. An absent ID requests manager assignment. Present empty IDs remain present and fail validation. With neither root nor parent, the manager uses the effective activation ID as root. A parent without a root is rejected; explicit root/parent values are bounded opaque correlation claims and require no local ancestor lookup. They grant no additional authority.

Cancel/Get derive the tenant from authenticated context and call the manager's scoped operations. Scope validation and lookup/mutation occur together. Foreign and unknown IDs produce the same NotFound behavior. The manager retains active records and bounds terminal retention; eviction means NotFound cannot establish that an activation never executed. Retained IDs reject duplicate invocation; an ID may receive a new owner after its old terminal record is evicted.

Trusted local authentication and trace context​

A listener or interceptor inserts AuthenticatedInvocationContext into Tonic request extensions. Missing context is unauthenticated. The default LocalPrincipalPolicy rejects anonymous, malformed, or unscoped identities; service principals also need a service identity. Every principal, including an administrator, must carry the exact invocation tenant. Principal claims remain trusted embedding input, never facts reconstructed from caller metadata.

Authentication/context bounds are checked before cloning retained principal information. Invocation metadata under case-insensitive latent.auth.* and latent.principal.* prefixes is rejected before lifecycle work starts. Replacing PrincipalPolicy does not bypass the manager's tenant boundary.

InvocationServiceServices owns an injectable ActivationClock, PrincipalPolicy, and InvocationTraceSource. The default trace source creates fresh trace/span correlation IDs from a source namespace and checked sequence, with flags zero and empty baggage. Trace source output is bounded and validated before acceptance. Invoke metadata supplies neither authentication nor trace propagation. This is a local convention, not an external identity provider or an implementation of incoming trace-header propagation.

Bounded request handling​

InvocationLimits caps encoded requests/responses, payloads, metadata counts and bytes, identifiers, strings, cancellation reasons, deadlines, budget grants, and public error details. Borrowed trusted context is bounded before cloning, and owned request allocations are checked before transfer to the lifecycle. The manager independently enforces its configured request and journal limits; node composition must configure compatible ceilings. LocalInvocationRuntime::new(manager) uses default RPC limits; with_limits(manager, limits) validates and retains custom limits for the bridge's scoped principal checks. Custom composition supplies the same limits to the adapter and bridge, with compatible manager request limits.

Missing targets/budgets, malformed IDs, forged principal metadata, expired request deadlines, and oversized input fail before route resolution, admission, or cell allocation. Explicit zero resource grants remain hard ceilings. Child calls, outbound requests, state/blob I/O, and effects must all be zero in the basic profile. An explicitly configured capability budget profile permits bounded child/outbound/blob counters. State and effect counters remain unsupported. The endpoint's trusted profile selection is independent of request metadata and does not itself authorize capability use.

Deadlines and dropped RPC futures​

The request deadline, trusted transport deadline, and grpc-timeout header can each tighten the effective deadline. The same sampled clock relates the wire absolute deadline and the local monotonic wait; no later wall-clock sample restarts the allowance. Relative budget wall time remains admission-relative. The adapter and manager clocks must use the same monotonic domain. The adapter checks the remaining allowance again after synchronous acceptance: if a Received observation consumes the deadline, the accepted handle expires before its first lifecycle poll, so no route or cell work begins.

Each invocation has an independent typed transport-interruption token, preserving its first disconnect or deadline cause. With standalone's cleanup supervisor, dropping the RPC future marks and transfers the exact manager handle for bounded cooperative cleanup. Status may remain active after the transport has ended; terminal publication follows actual cleanup or conservative abandonment. The original execution deadline and accounting remain unchanged. Accepted explicit Cancel retains priority over that deadline; a raw disconnect does not become an accepted Cancel and cannot override an expired deadline.

LocalInvocationRuntime::new and with_limits retain unsupervised compatibility: dropping the RPC future immediately drops its manager handle. A transport timeout uses that same owner's deadline-abort path, including before its first poll. Both modes preserve identity ownership; neither looks up an ID later to stop a replacement activation. Missing reusable-cell proof still causes quarantine.

A cancellation, timeout, or lost response does not prove execution never began. The caller may query the known ID; the adapter and SDK contracts add no automatic Invoke retry. Cancelling one RPC does not cancel other calls sharing a connection.

Outcomes, status, and public errors​

Guest success, declared domain error, and platform failure occupy distinct response branches. Accepted terminal responses contain the activation ID and final consumption. When resolution succeeded, the receipt includes that exact revision, release digest, and route generation. An accepted failure before resolution represents the absent pin as empty revision/release strings and route generation zero; it never invents routing data. That representation is valid only for a platform-failure response.

GetActivation preserves live phase and terminal category, completion time, success summary or error, and final accounting. Cancel returns Accepted, AlreadyTerminal with its terminal state, or NotFound. Malformed requests and pre-acceptance failures use transport status; accepted execution failures remain platform outcomes unless the transport itself has ended.

Canonical domain/Protobuf conversions preserve internal platform errors. The public adapter separately replaces diagnostic messages with fixed code-specific text and permits only typed fields from known public detail kinds. Unknown kinds, credentials, paths, connection strings, and backtraces are omitted. Declared guest error data remains application data in its own result branch.

Focused validation​

cargo test --locked -p latent-wire

The invocation_service integration target calls all three generated RPC methods in process using a real manager, admission controller, and scheduler. Tiny local catalog, artifact, and backend fixtures cover pending status/cancellation, strict tenant scope including administrators, optional identity and opaque lineage, trace/retry defaults, pre-acceptance rejection, absent/pinned failure receipts, retained ID reuse, catalog pinning, outcome/accounting preservation, public error redaction, dropped-call isolation, a short live timeout, and cell cleanup/reuse. Completion waits have five-second watchdogs. These tests open no listener and run no Wasmtime workload, scale test, or soak. Separate standalone node tests exercise socket-level composition and the bounded release-to-invocation workflow.