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

Activation-scoped capabilities

The generic Wasmtime backend implements four imports: latent:context/context, latent:log/log, latent:clock/monotonic, and latent:clock/wall, all at version 0.1.0. They are explicit Component Model imports supplied to a fresh store for each activation. Preparation verifies the component's declared surface, and an invocation must bind exactly its prepared imports. No WASI filesystem, environment, network, process, or other ambient authority is installed. The remaining platform capability packages are contracts for later implementation. Completion of Phase 2 adds package delivery, currentness, native caching and rollout control; it does not expand this guest import set. The 41-ticket Phase 3 backlog is planned work, with no Phase 3 providers or host ABI implementation merged.

The local activation manager supplies these capabilities with the activation's shared accounting owner inside the delivered standalone node. Phase 3 plans the shared capability broker, HTTP/blob/secrets/events providers, local child calls, random and custom metrics, application ingress and web/SSR integration. Transactional state/effects, cluster transport and durable workflow suspension remain later phases; declared WIT alone makes none of them callable.

Context disclosure​

Identity, lineage, authenticated principal identity, core trace fields, and the effective deadline come from the pinned activation envelope and its admission budget. The guest cannot replace these fields through metadata or log fields. Lineage alone does not grant authority. Mutable context is never retained for the next occupant of a reused execution cell.

WasmtimeConfig.context_policy is a ContextExposurePolicy with three public lists. Defaults expose metadata whose key starts with guest. and expose no principal claims or trace baggage. Metadata keys keep their complete namespace. metadata_prefixes selects case-sensitive prefixes; claim_keys and baggage_keys select exact, case-sensitive keys. An empty list exposes nothing from that map. The policy does not remove pinned identity, principal subject/kind/tenant/service, trace ID/span ID, or trace flags.

Each policy list permits at most 32 distinct nonempty entries, each at most 256 UTF-8 bytes without control characters. Factory creation rejects invalid policy. The exposure policy participates in preparation compatibility. Request context also has a bounded allocation allowance checked before its strings and maps are cloned into host state. Operators should deliberately select guest-visible metadata and allowlist claims/baggage for the intended workload.

Clocks and live accounting​

WasmtimeHostServices supplies an Arc<dyn ActivationClock> and an optional structured log sink. WasmtimeComponentEngineFactory::with_host_services accepts these node-owned dependencies; the ordinary constructor uses the system clock and bounded capture. The same clock abstraction is available in latent-core and reexported by latent-node for existing callers.

The monotonic capability reports elapsed nanoseconds from an origin sampled once by the node factory. Values saturate at u64::MAX and clamp backward observations within that activation. A fresh activation shares the origin and has fresh clamp state, so it can observe a lower value after an injected clock regression. Wall time reports Unix milliseconds and may move backward after a clock adjustment; it is not the elapsed-time or deadline source. Admission and execution must use the same monotonic clock domain. An injected clock makes those distinctions testable without waiting for time to pass.

Terminal wall-time consumption uses this same monotonic clock. Runtime profiling timings measure real process elapsed time independently of injected test clocks.

remaining-budget observes the live activation ledger, current store fuel, and aggregate observed memory. CPU and memory consumption already incurred by the guest reduce the result; accepted log bytes reduce the same ledger immediately. Remaining wall time follows the original effective monotonic deadline. It does not restart at guest entry or after a host call.

An activation owner supplies its existing ActivationBudget through ExecutionCancellation::budget_accounting. This shares accounting with the capabilities and terminal reconciliation. Direct backend callers that omit the ledger get one local fallback ledger. The backend reports consumption and cleanup; the activation owner performs terminal finalization. No separate guest-visible budget grants additional resources.

Structured log acceptance​

The host validates the message and guest fields before publication. Messages are limited to 256 UTF-8 bytes, guest field counts to 16, names to 64 bytes, and values to 256 bytes. Names must be nonempty ASCII letters, digits, underscore, hyphen, or period. Duplicate names are invalid.

The case-insensitive latent. namespace is reserved. The host adds trusted latent.activation_id, latent.trace_id, and latent.span_id fields. An unprefixed activation_id field is ordinary guest data, preserving the retained echo fixture's convention without making that field authoritative.

Log-byte accounting charges the complete compact UTF-8 JSON record in this top-level field order:

{"activation_id":"a","level":"info","message":"m","fields":{"latent.activation_id":"a","latent.span_id":"s","latent.trace_id":"t"}}

Fields are sorted by key. The charge includes names, punctuation, escaped string bytes, and trusted correlation, with no trailing newline. The activation log budget and configured per-invocation entry/byte limits must all admit the record. Invalid fields and exhausted limits return typed WIT failures and publish nothing.

A custom StructuredLogSink::try_emit receives the CapturedLog and those exact encoded bytes. Implementations must make a bounded, nonblocking acceptance decision. Returning LogSinkError::Unavailable becomes the WIT unavailable error, refunds the reservation, and leaves bounded capture unchanged. After custom acceptance, or when using the default sink, the host commits the charge and records the accepted log in bounded node capture. write success means acceptance by that sink; it does not establish external durable delivery. factory.log_sink() and backend snapshots expose bounded accepted capture.

Focused validation​

tools/validate_contracts.sh builds a separate maintained Rust/WIT capability component and runs capabilities_backend. Its small tests cover default and explicit context filtering, pinned identity across cell reuse, live fuel/memory and log accounting, backward wall adjustments, monotonic clamping/reset, escaped record byte boundaries, reserved/invalid fields, sink rejection/refund, missing clock grants, and actual imports from nine unavailable capability families. Each invocation has a five-second watchdog and checks resource cleanup.

After the contracts gate has built the fixture, run it directly with:

LSF_CAPABILITIES_COMPONENT=target/capsules/capabilities/capabilities-capsule.wasm \
cargo test -p latent-wasmtime --test capabilities_backend --locked -- \
--ignored --nocapture --test-threads=1

These are bounded semantic regressions. They do not establish the long-running reclamation, dormant-release scale, or complete Phase 1 conformance evidence in the validation contract.