# Plugin Runtime
Alma plugins are untrusted Wasm components. The runtime is a mediation layer,
not an editor owner. It validates static input, constructs authority proofs,
runs bounded guest updates, and publishes only typed proposals to existing
owners.
The v1 product goal is local Wasm plugins that can observe editor state and
propose bounded work without compromising editor correctness, local files, user
text, or UI responsiveness. Default builds and default configs remain
plugin-runtime-free and default-deny.
## Status
Implemented:
- static registry config, plugin identity validation, component path shape
validation, manifest parsing, and effective grant projection
- explicit whole-workspace grant spelling and workspace-relative grant
validation
- runtime limit validation with closed field diagnostics, including a
host-sized non-zero sealed-batch cap for registry-level `PluginIntentQueue`
scheduling
- policy-opened manifest and component byte tokens
- typed WIT host-import metadata for exposed import name, capability atom, and
redacted operational class
- closed guest-decode field vocabulary for generated-to-Alma validation
diagnostics at host-import boundaries
- public task-based `workspace.observe` start/poll/take WIT imports, including
an opaque task resource, closed poll/take result variants, redacted
operational import classes, and drift coverage proving the WIT has no
blocking read import and no partial task group
- host-owned buffer and view handles with generation invalidation and
live-handle limits
- borrowed WIT resources for update-scoped view and buffer authority, resolved
through store-local Wasmtime `ResourceTable` lookup
- typed Wasmtime update-resource reps for view and buffer resources, so
guest-call borrows, cleanup, and setup rollback cannot swap resource kinds by
raw table-index convention
- shared host authority proof for per-plugin identity and effective
capabilities, reused by live contexts and per-update snapshots
- per-update host import sessions with discardable effect and workspace I/O
batches
- Wasmtime component validation, loading, lifecycle calls, fuel limits,
shared epoch-driven wall-clock timeouts, memory limits, and message-size
limits behind `plugin-runtime`, split under `runtime/wasmtime/` by adapter,
store/import state, resource-table vocabulary, workspace observe-task
resources, scheduled-update proofs, execution guards, errors, and tests
- generated `status.publish`, `buffer.observe`, `buffer.propose_edit`,
task-based `workspace.observe`, and `workspace.artifact_write` host import
adapters
- typed Wasmtime failure phases for redacted outer diagnostics, while exact
runtime errors retain their source enums
- adapter-local Wasmtime host-import rejection envelopes that keep the first
redacted import class paired with its typed source error
- closed Wasmtime failure classes for redacted lower-level runtime detail
- closed operational runtime-failure classes, including canonical ABI
post-return cleanup
- closed host-import diagnostic names for Wasmtime operational events
- revision-guarded plugin buffer edit proposals that reach the buffer owner
through `PluginIntentQueue`
- retry-safe `PluginIntentQueue` admission: saturation returns the closed
queue rejection with the still-sealed effect batch for retry or explicit
redacted discard, and its consuming split returns named queue-error and
batch fields
- empty sealed effect, workspace I/O, and workspace observe-task batches are
no-op scheduler admissions; they do not consume bounded queue capacity or
emit saturation diagnostics
- a typed proposal lane for plugin buffer edit proposals, with compatibility
auto-apply and explicit manual apply/reject request paths
- closed error-kind vocabularies for plugin intent queue, proposal lane,
proposal decision, and proposal receipt-log diagnostics
- per-plugin config policy for buffer edit proposal review, defaulting to
`auto_apply` and allowing explicit `manual_review`
- buffer edit proposal provenance and receipts whose proposal-specific
capability type is backed by `CapabilityAtom`
- capability atoms that own stable spellings, authorization-ref path arity, and
redacted shapes for WIT and host authorization adapters
- a first visible chrome summary for pending proposals, using redacted edit
shape and no raw ECS ids
- a redacted one-hunk diff preview for the first pending proposal
- chrome apply/reject controls that emit typed proposal request messages
- bounded in-session proposal receipts for proposal-lane rejection,
buffer-owner acceptance, and buffer-owner rejection
- chrome proposal status for pending proposals and the latest retained receipt
- real observe-plus-propose component coverage through the runtime, intent
queue, and buffer owner
- real workspace artifact-write component coverage through the runtime and
deferred workspace I/O boundary
- a single active-update scheduling proof consumed by Wasmtime update setup
- store-local Wasmtime active update state that pairs the host import session
with the rooted update resources it must clean up after guest return
- store-local Wasmtime workspace observation task state that pairs the task
queue, persistent task resources, and active-update task resource reps; the
reps are typed inside the adapter, and the persistent-resource cap is a
non-zero proof derived from the same queue limit as task scheduling
- host-import snapshot construction rejects host grants and handle stores from
different plugin identities
- Wasmtime update setup rejects nested active sessions instead of relying on a
debug assertion
- `PluginHostImportError` owns the closed operational rejection class for
non-authorization import failures; authorization failures continue to emit
denied-import events
- operation-typed workspace I/O execution completions with distinct read and
write success/error result types
- workspace I/O success accessors for deliberate owner/user surfaces, with
debug output reduced to redacted operation and length shapes
- bytes-only `workspace.observe` delivery projection from read completions,
keeping guest-facing read results separate from owner-facing display path and
filesystem error metadata
- a redacted `workspace.observe` delivery shape used by task result debug and
runtime trace adapters, so byte payloads are not inspected at later
diagnostic boundaries
- direct host-session workspace observations that require explicit
`FilesystemConfig`, authorize through captured plugin authority, read through
the pending workspace I/O ledger and `fs_utils`, return only
`PluginWorkspaceObserveOutcome`, spend the per-update workspace request
budget, do not enqueue deferred workspace I/O, and remain plugin-internal;
public guest reads use the task/result ABI instead
- shared workspace request-budget accounting for deferred workspace I/O, direct
host-session observations, and task-style observation reservations
- deferred workspace I/O request counts derive from the pending batch's
retained operations instead of a second mutable ledger counter; the shared
ledger owns identity, budget, and non-deferred charges
- task-style workspace observation reservations reject paired workspace I/O
ledgers from other plugin identities before charging budget or reserving a
task id
- workspace I/O and observe-task queue admission errors expose closed error
classes and closed mismatch source vocabularies for access-proof,
request-ledger, identity, and queue reservation failures
- workspace request-budget, pending-effect, intent queue, proposal lane,
observe-task pending-capacity, workspace worker, and operational queue
saturation diagnostics carry the validated non-zero cap proof internally
while preserving the existing redacted display and event text
- workspace read/write access proofs retain the issuing `PluginIdentity`;
filesystem-policy tokens stay internal to `workspace_io`, and pending
workspace I/O rejects access proofs from a different plugin identity before
any filesystem policy execution
- a runtime-owned workspace observation task queue with non-zero host task ids,
bounded pending reads, bounded retained results, identity-scoped poll/take,
FIFO filesystem-policy execution, bounded single-task and capped batch
execution, an explicitly named all-task drain for callers that choose
unbounded execution, retention eviction, revocation cleanup, and
pending-capacity plus non-reused task-id reservation before guest-visible
return, with queue debug output reduced to counts
- pending and sealed workspace observation task batches in the host-import
session. Failed updates discard task requests, while successful updates can
enqueue sealed task batches with already-reserved ids all-or-nothing before
the task queue performs any filesystem-policy work. The host session returns
one resource-authority proof that pairs the identity-scoped handle with the
workspace path authorized for later poll/take revalidation. The public start
import returns the identity-scoped handle as an opaque WIT resource. Dropping
that resource before successful guest return removes the uncommitted task
request and releases its pending-capacity reservation. Batch debug output is
count-shaped; task handles remain behind explicit accessors.
- pending effect batch limit field and rejection-class vocabulary for closed
host-import diagnostics
- workspace observation task requests retain the producing update's non-zero
read byte cap, so later queue execution cannot widen the result bound by
caller convention.
- workspace read and write execution paths accept non-zero byte cap proofs
owned by the workspace I/O budget boundary instead of raw numeric
conventions.
- deferred workspace artifact writes retain a bounded payload proof after
queue admission, so pending and sealed write work cannot carry an over-budget
payload by internal convention.
- host queues, handle stores, ledgers, and pending batches consume validated
limit and budget proofs directly; zero-limit validation stays at proof
constructors, and constructors that receive those proofs are infallible.
- paired host-import, post-update scheduling, and scheduled owner-publication
proof constructors enforce same-plugin identity in release builds before
constructing the proof value
- validated runtime limits retain the sealed-batch scheduler cap as a
host-sized non-zero proof, so scheduler policy does not reinterpret serialized
config integers.
- runtime limits, workspace I/O budgets, and workspace observation task queue
limits report zero-limit failures through closed field vocabularies with
stable text.
- production workspace observation task enqueueing through sealed
successful-return batches only. Direct queue insertion from an authorized read
proof is test-only, so runtime code cannot bypass the session request ledger
or failed-update discard boundary.
- retry-safe sealed workspace observation task admission: a queue mismatch
returns the closed queue rejection with the still-sealed batch, so callers can
retry on the owning queue or drop the batch deliberately. Its consuming split
returns named queue-error and batch fields.
- sealed workspace observation task admission retains the validated pending
queue storage through enqueue, so reservation validation and pending
publication cannot drift as separate caller conventions.
- explicit sealed workspace observation task discard after successful guest
return but before queue admission, returning a redacted discard report while
releasing the held queue reservations.
- bounded workspace I/O queue with FIFO execution and revocation cancellation
- retry-safe sealed workspace I/O worker queue admission: saturation returns
the closed queue rejection with the still-sealed batch, so callers can retry
after capacity frees or explicitly discard the batch with a redacted cleanup
report. Its consuming split returns named queue-error and batch fields.
- all-identity workspace I/O worker and workspace observation task queue
cancellation for shutdown or broad teardown, returning deterministic
per-identity redacted reports without filesystem work or guest delivery
- Wasmtime instance revocation cleanup for workspace observation tasks through
`cancel_workspace_observe_tasks_for_revocation`, gated by a
`PluginRevocationReport` identity proof and clearing queue-owned task state,
uncommitted active-update task requests, and persistent task resources
- Wasmtime instance shutdown cleanup for workspace observation tasks through
`cancel_workspace_observe_tasks_for_shutdown`, clearing runtime-owned
queue state, uncommitted active-update task requests, and persistent task
resources without requiring lifecycle mutation
- a Wasmtime revocation helper that prechecks runtime/state identity before
mutating host state, then pairs the `PluginRevocationReport` with
runtime-owned workspace observation task cleanup in one result
- Wasmtime revocation cleanup splits lifecycle revocation from runtime-owned
workspace observation task cleanup through named fields instead of a
positional tuple
- task-based workspace observation enqueue rejects sealed batches whose plugin
identity does not match the runtime instance, and enqueue, single-task
execution, non-zero capped batch execution, and drain-all execution require
the matching active `PluginInstanceState`, so revoked instances cannot admit
sealed observe-task batches or run queued filesystem work
- a Wasmtime update helper that schedules task-based workspace observations
back onto the producing runtime queue after successful guest return, while
returning a `WasmtimePluginScheduledUpdate` proof that pairs sealed editor
and workspace I/O owner work with already-scheduled task evidence
- post-update observe-task schedule recovery consumes the paired schedule-error
proof and rebuilds the scheduled-update proof after a successful task retry,
so owner-loop callers do not split retryable owner work from retryable task
work by convention
- post-update observe-task schedule discard consumes that same proof and returns
one redacted report for discarded owner work and unscheduled task work
- failed-update, owner-work, post-update schedule, and scheduled owner discard
report debug output is count-shaped at the outer boundary, without nested
discard-report formatting or task-handle lists
- Wasmtime scheduled-update debug output reports identity and work counts
only. Post-update schedule-error debug output also reports the closed
enqueue rejection class, without formatting retained owner batches or
retryable task batches.
- paired owner-publication queue admission for sealed editor effects and sealed
workspace I/O, validating both owner queues into a private paired admission
proof that retains the target queue borrows until publication. Each
individual owner queue admission owns its sealed batch until publication, and
rejection returns the owner-work proof intact while success returns a named
owner-publication report; debug output reports only identity, closed
rejection class when present, and work counts. Consuming owner-queue enqueue
failures expose named queue-error and owner-work fields for retry decisions.
- scheduled-update owner-publication API that consumes
`WasmtimePluginScheduledUpdate`, publishes the remaining owner work through
the paired owner queues, returns a named success report with both the
owner-publication report and already-admitted observe-task scheduling report,
and on owner-queue rejection keeps the retryable owner work paired with that
scheduled-task report
- scheduled-update owner-publication retry that consumes the paired
owner-queue failure and either returns the named publication report or the
same paired failure shape, so callers do not split already-scheduled task
evidence from retryable owner work by convention
- scheduled-update owner-publication discard returns a named report that keeps
discarded owner work paired with the already-admitted task scheduling report;
report accessors name that evidence as scheduled task work, and debug output
uses counts rather than retained batch internals or task-handle lists
- scheduled-update and scheduled-owner-publication public split APIs return
named part structs for owner work, retryable queue errors, discard evidence,
and already-scheduled task evidence instead of positional tuples
- successful-return and owner-batch public split APIs return named part structs
for editor effects, workspace I/O, and runtime-owned observe-task work
instead of positional tuples
- drained effect reports split into named owner request batches that retain the
drained plugin identity, so editor-effect and status request vectors are not
separated by tuple position
- active-update setup, task-resource authority, and adapter-local update
resource splits return named boundary structs for captured snapshots,
update handles, resource-table authority, and guest borrows
- a private-field Wasmtime observe-task schedule error payload that keeps the
unpublished owner-work proof and the retryable task enqueue error paired
after a successful update, instead of exposing those fields as a public enum
construction convention
- private-field Wasmtime observe-task enqueue failures with a closed public kind
and accessors for lifecycle, instance-state, batch-identity, queue, retry,
discard, and redacted operational reporting, so callers cannot construct
source and batch mismatches by convention. Instance-state and batch-identity
mismatch accessors return named borrowed identity pairs instead of positional
tuples.
- Wasmtime observe-task enqueue failure debug output reports the closed public
kind, relevant identity proofs, queue rejection class when present, and
retained task count without formatting the retryable sealed batch
- scheduled-update and observe-task enqueue failures expose the same redacted
operational event projection as runtime failures, so owner-loop callers do
not need to destructure private scheduling payloads for diagnostics
- persistent Wasmtime workspace observation task resources retain the
authorizing workspace path and revalidate it against the current update
snapshot before poll or take can reach task queue state; denied revalidation
tombstones the resource without freeing the table rep and returns the typed
authorization rejection
- Wasmtime workspace observation task resource resolution and drop reject
resource-table/tracker divergence as a typed resource-handle failure in
release builds. If a new task resource would reuse a table rep that the
tracker still records, the stale tracked resource is tombstoned, the new
table entry is removed, and the start import fails closed. Table
lookup/delete errors tombstone the tracked resource before returning unless
drop already freed the table slot, and diagnostics do not expose table reps,
paths, or task payloads.
- Wasmtime update setup tombstones workspace observation task resources still
marked as started by a prior abandoned update before accepting fresh update
resources
- closed workspace I/O worker queue limit field and rejection-class vocabulary
- closed workspace observation task poll and take result shapes that distinguish
pending, completed, and unknown or already-consumed task ids without exposing
paths or filesystem error detail; poll results carry only redacted outcome
shape, while take remains the consuming byte-delivery path
- a separate workspace observation task result vocabulary for inert task ids,
owned identity-scoped task handles, queue keys, internal handle-borrowed
lookup matching, shared closed task state, payload-free queue state queries,
payload-free poll results, consuming take results, shared redacted poll/take
result shapes, and `PluginWorkspaceObserveTaskCompletionShape`, so Wasmtime
resource adapters can encode task results without owning queue mutation
- redacted operational events for load, unload, revocation, denied import,
update setup rejection, non-authorization host import rejection, timeout,
guest trap, runtime setup/fuel failure, intent queue saturation, workspace
I/O queue saturation, workspace observation task queue saturation, and
proposal lane saturation
- explicit stable text for operational queue, revocation-reason, handle-kind,
resource-handle rejection, host-state mismatch, and host-import rejection
classes
- redacted plugin runtime trace vocabulary for drained effects, discarded
updates, workspace I/O completions, workspace I/O cancellations, workspace
observation task completions with identity-scoped completion shapes,
workspace observation task cancellations, operational events, and proposal
receipts
- checked-in runtime trace replay golden coverage over line-oriented
`PluginRuntimeTraceEvent` display output
Not implemented:
- host imports beyond `status.publish`, `buffer.observe`,
`buffer.propose_edit`, task-based `workspace.observe`, and
`workspace.artifact_write`
- plugin event subscriptions
- background workspace I/O worker threads
- guest-driven scheduling and subscriptions
- synchronous guest-visible `workspace.observe`; public workspace reads use
task resources
- automatic background execution of pending workspace observation tasks
Non-goals for v1:
- remote plugin downloads or marketplace discovery
- runtime permission prompts
- process execution, shell access, or environment access
- raw filesystem paths in the guest API
- raw ECS access or Bevy system registration from plugins
- synthetic user input
- arbitrary config mutation
- unrestricted clipboard access
- lifecycle shutdown authority
- unbounded or long-running guest tasks on the Bevy update thread
## Dataflow
Plugins add one explicit stage between interpreted intent and owner mutation:
```text
Input -> Intent -> PluginIntent -> Edit -> Layout -> Shape -> Render
```
Guest code runs only in `PluginIntent`. Host imports can observe bounded data or
queue discardable effects. A successful guest return seals the batch. Draining
publishes status requests and routes buffer edit proposals into the proposal
lane. Per-plugin config policy chooses whether buffer edit proposals auto-apply
through the existing buffer owner or remain pending until an explicit apply or
reject request arrives. Id-bearing proposals produce bounded receipts when the
proposal lane rejects them or the buffer owner accepts or rejects them.
Intent queue saturation is retry-safe: a rejected sealed effect batch stays
paired with the closed queue rejection until the caller retries it or discards
it deliberately.
Host imports do not mutate `EditorBuffer`, `EditorView`, `VimModalState`,
filesystem state, or render state. They return bounded observations or append
to the pending per-update batch.
The component-model boundary carries three separate invariants. WIT defines the
public shape, resources carry editor view and buffer authority, and Wasmtime
store/session state defines lifetime. Resource reps are not part of Alma's
public API.
Generated-to-Alma decode accepts only closed guest-decode field labels. Adapter
call sites choose from that vocabulary instead of passing ad hoc diagnostic
strings, so oversized, malformed, or invalid guest fields cannot drift by
caller convention. Decode limits derive from validated runtime policy and carry
non-zero byte/count caps before adapters can bound guest strings, payloads, or
returned buffer snapshots.
Workspace authority is deliberately not an ambient update resource. Workspace
host imports must create typed read or write authority at the import boundary
from the requested operation kind, validated workspace-relative path, bounded
payload, explicit filesystem context when bytes are returned synchronously, and
effective grants captured in the host import session. Deferred requests become
workspace I/O; failed guest updates discard them before filesystem policy
execution. Direct observations spend the same per-update request cap before
filesystem access even though they do not enter the deferred worker queue.
The existing direct workspace observation helper is a host-session policy path,
not a guest-visible Wasmtime import. It proves the result shape reused by the
task-based `workspace.observe` ABI: bounded bytes or one closed rejection, with
no workspace paths, display paths, filesystem error detail, or diagnostic text.
Do not expose a synchronous Wasmtime host import unless filesystem work has an
enforceable host-side deadline or cancellation path. Wasmtime epoch
interruption can stop guest Wasm, but it cannot preempt Rust host code blocked
in filesystem I/O.
The workspace observation task queue is the host-side shape for public
workspace reads. It treats task ids as inert lookup keys, requires an
identity-scoped handle for polling or taking results, retains only
`PluginWorkspaceObserveOutcome`, and cleans both pending tasks and retained
results on revocation. The host-import session has a separate pending task
batch and sealed task batch, so task filesystem work cannot be published before
successful guest return. Pending task batch insertion owns plugin-identity
validation before charging the shared workspace request budget or retaining the
task proof. The retained task proof also carries the update's non-zero read
byte cap into queue execution. The start import reserves both pending capacity
and a non-reused identity-scoped task handle before returning an opaque task
resource; failed updates release the pending-capacity slot and discard the
filesystem work, but they do not roll the id space back because guest memory
may already contain the resource. Sealed batch enqueue consumes those reserved
handles, slots, and read caps. Reservation accounting remains safe for
scheduler or worker handoff through an explicit RAII slot counter owned by the
queue token.
The queue exposes a payload-free closed state query, payload-free polling, and
a consuming take result for adapter use: `pending`, `completed`, and `unknown`.
Completed poll/take shapes carry only the redacted guest-delivery outcome
shape, retained completion shapes carry the owning plugin identity with the
task id, and only `take` carries the byte-bearing guest-delivery outcome. A
pending task cannot be consumed, a completed task can be consumed once, and ids
that are stale, evicted, already taken, or owned by another plugin collapse to
`unknown`.
The shared task-state projection is payload-free, and both pending and retained
queue records match through an internal lookup borrowed from the identity-scoped
task handle. Public Rust callers poll, take, or query state with the owned
handle rather than constructing arbitrary identity/task-id pairs.
The public ABI exposes the start/poll/take group together. `start` validates and
authorizes the path during an active update, returns a bounded host-owned task
resource, and keeps filesystem work behind the successful-return boundary. The
host-session boundary pairs the reserved task handle with the authorized path in
one proof before Wasmtime can persist the resource. If the guest drops that
resource before the update commits, the host session removes the pending request
instead of sealing later filesystem work for an unreachable task handle.
The resource stores the authorizing workspace path, so `poll` and `take`
revalidate that path against the active update snapshot before reading queue
state. Denied revalidation tombstones the resource and returns the typed
authorization rejection while keeping the table rep occupied until guest drop.
A later canonical drop of that invalidated task resource is an idempotent
cleanup no-op. `poll` is payload-free and reports only pending, unknown, or a
redacted completed outcome shape. `take` is the only byte-bearing guest
delivery path and consumes completed outcomes at most once.
Production enqueueing into the host-owned task queue accepts sealed
successful-return batches, not raw read proofs from adapters, and requires the
matching active `PluginInstanceState`. The direct queue push remains a focused
test helper for queue behavior. Execution uses the same active-state gate, so
revocation blocks both late enqueue of a caller-held sealed batch and later
filesystem reads from queue-owned pending work.
Successful-return aggregate debug output reports identity and work counts
instead of formatting nested sealed effect, workspace I/O, or observe-task
batches.
Failed sealed-batch admission returns both the closed queue rejection and the
still-sealed batch. The reservation slots remain live while the returned batch
is live, so a scheduler can retry on the owning queue without losing task ids,
or explicitly discard the batch and get a redacted cleanup report while
releasing capacity.
The WIT metadata ties each task function name to `workspace.observe` and a
stable operational import class. That metadata is not runtime authority; it
keeps capability checks, generated bindings, diagnostics, and drift tests in
lockstep.
## Module Map
- `src/plugin/policy/config/mod.rs`: static config facade and public re-exports
- `src/plugin/policy/config/registry.rs`: registry uniqueness validation and
enabled load-entry proofs
- `src/plugin/policy/config/entry.rs`: untrusted static config entries and
effective manifest grant projection
- `src/plugin/policy/config/identity.rs`: stable plugin identity grammar
- `src/plugin/policy/config/world.rs`: current WIT-world proof
- `src/plugin/policy/config/component.rs`: component path shape validation
- `src/plugin/policy/config/proposal.rs`: proposal review policy schema
- `src/plugin/policy/config/tests.rs`: config-boundary tests and property
coverage
- `src/plugin/policy/capability.rs`: capability grants, capability atoms,
authorization-ref path arity, and host-import query shapes
- `src/plugin/policy/workspace.rs`: workspace-relative grants and path refs,
not filesystem authority
- `src/plugin/policy/manifest.rs`: untrusted manifest parsing and effective
grant projection
- `src/plugin/policy/scheduler.rs`: registry-level publication burst policy
- `src/plugin/runtime/component.rs`: policy-opened component bytes
- `src/plugin/runtime/limits.rs`: bounded execution and ECS publication limits
- `src/plugin/runtime/instance.rs`: runtime specs, loaded instance lifecycle,
and revocation policy
- `src/plugin/runtime/wasmtime/mod.rs`: feature-gated Wasmtime adapter facade
- `src/plugin/runtime/wasmtime/adapter.rs`: runtime and instance orchestration
- `src/plugin/runtime/wasmtime/error.rs`: redacted Wasmtime failure and
observe-task enqueue error vocabulary
- `src/plugin/runtime/wasmtime/execution.rs`: fuel and epoch-deadline guards
- `src/plugin/runtime/wasmtime/resources.rs`: typed update-resource table reps
- `src/plugin/runtime/wasmtime/schedule.rs`: scheduled-update and revocation
proof shapes
- `src/plugin/runtime/wasmtime/store.rs`: store-local host-import state and
generated host import adapters
- `src/plugin/runtime/wasmtime/workspace_observe.rs`: workspace observe-task
queue/resource state and guest ABI projections
- `src/plugin/runtime/wasmtime/tests.rs`: Wasmtime adapter and component
fixture coverage
- `src/plugin/host/context.rs`: per-plugin authorization context and shared
host authority proof
- `src/plugin/host/import/mod.rs`: host-import boundary facade and re-export
surface
- `src/plugin/host/import/snapshot.rs`: per-update authority and handle-store
capture
- `src/plugin/host/import/session.rs`: active import-session mutation methods,
direct workspace observation policy path, and discardable work collection
- `src/plugin/host/import/batches.rs`: successful-return owner/task batches
and failed update discard reports
- `src/plugin/host/import/resource.rs`: observe-task resource-authority proofs
and component-resource rejection vocabulary
- `src/plugin/host/import/error.rs`: layered host-import rejection types and
host-import rejection projection
- `src/plugin/host/effect/mod.rs`: effect boundary facade and re-export
surface
- `src/plugin/host/effect/limit.rs`: non-zero effect admission limit proof
and stable limit-field vocabulary
- `src/plugin/host/effect/error.rs`: effect admission rejection classes and
commit error vocabulary
- `src/plugin/host/effect/proposal.rs`: internal effect payload storage,
status shapes, and snapshot-derived buffer edit proposals
- `src/plugin/host/effect/batch.rs`: pending and sealed effect batches,
successful-return sealing, and typed admission methods
- `src/plugin/host/effect/report.rs`: discard evidence, drained owner request
reports, named owner request splits, and redacted drained request shapes
- `src/plugin/host/handles.rs`: per-plugin typed handle table and short-lived
resolved proofs
- `src/plugin/host/workspace_io/mod.rs`: workspace I/O facade and re-export
surface
- `src/plugin/host/workspace_io/batch.rs`: pending and sealed deferred
workspace I/O batch ownership
- `src/plugin/host/workspace_io/error.rs`: shared workspace I/O commit
rejection classes and identity-mismatch source vocabulary
- `src/plugin/host/workspace_io/budget.rs`: workspace I/O limit proofs and
shared per-update request accounting
- `src/plugin/host/workspace_io/access.rs`: workspace read/write access
proofs, internal filesystem-policy tokens, and operation-specific
filesystem-policy errors
- `src/plugin/host/workspace_io/report.rs`: owner-facing workspace I/O
execution reports, operation-typed completions, explicit success accessors,
and guest-delivery read projections
- `src/plugin/host/workspace_io/observe_result.rs`: task ids, owned
identity-scoped task handles and queue keys, internal handle-borrowed lookup
matching, shared closed task state, redacted poll/take result shapes,
payload-free poll results, consuming take results, and identity-scoped
`PluginWorkspaceObserveTaskCompletionShape` for guest-visible workspace
observation resources
- `src/plugin/host/workspace_io/observe_tasks/mod.rs`: workspace observe-task
facade and re-export surface
- `src/plugin/host/workspace_io/observe_tasks/batch.rs`: pending and sealed
observe-task batches plus successful-return sealing and explicit discard
- `src/plugin/host/workspace_io/observe_tasks/queue.rs`: host-owned task queue,
queue limits, non-reusing task ids, FIFO execution, retained outcomes,
state, poll, take, and cancellation
- `src/plugin/host/workspace_io/observe_tasks/error.rs`: reserve/enqueue
errors, closed queue rejection classes, limit-field vocabulary, and
reservation mismatch vocabulary
- `src/plugin/host/workspace_io/observe_tasks/report.rs`: redacted discard,
enqueue, and cancellation reports
- `src/plugin/host/workspace_io/observe_tasks/reservation.rs`: identity-scoped
task reservations and RAII pending-slot accounting
- `src/plugin/host/workspace_io/worker.rs`: sealed workspace I/O FIFO worker
queue, retryable queue admission, queue limit, revocation or shutdown
cancellation, and saturation diagnostics
- `src/plugin/trace/`: redacted replay/telemetry facade split by event
envelope, effect/status payloads, workspace payloads, proposal receipts, and
shared display adapters
- `src/plugin/abi/wit.rs`: stable hand-written ABI vocabulary and host-import
metadata for default builds, including task-style workspace observe names,
capability, and operational classes
- `src/plugin/abi/decode/mod.rs`: generated-to-Alma decode facade and re-export
surface
- `src/plugin/abi/decode/limits.rs`: decode limits projected from validated
runtime policy
- `src/plugin/abi/decode/field.rs`: closed guest-decode diagnostic field
vocabulary
- `src/plugin/abi/decode/error.rs`: redacted guest-decode error vocabulary
- `src/plugin/abi/decode/scalar.rs`: bounded guest string, payload, count, and
text-range proofs
- `src/plugin/abi/decode/workspace_path.rs`: normalized workspace path decode
proof
- `src/plugin/abi/decode/capability.rs`: WIT capability references decoded into
Alma-owned authorization refs
- `src/plugin/abi/decode/buffer_edit.rs`: guest buffer edits decoded into
bounded owner-facing edit requests
- `src/plugin/abi/decode/tests.rs`: decode-boundary field, limit, redaction,
and owner conversion tests
- `src/plugin/abi/bindings.rs`: private generated component bindings behind
`plugin-runtime`
- `src/plugin/operational.rs`: redacted operational event vocabulary
- `src/ecs/events/plugin.rs`: ECS diagnostic message for redacted plugin
operational events
- `src/ecs/plugin.rs`: ECS queue, paired owner-publication helper, and drain
adapter for sealed plugin effects
## Commit Points
Plugin work has three commit points:
1. Guest return succeeds.
Pending effects and workspace I/O may become sealed batches.
2. Sealed effects drain.
The host publishes status requests and creates typed pending buffer edit
proposals.
3. Proposal policy, ECS owners, and filesystem owners apply or reject.
Buffer, status, layout, and filesystem policy remain authoritative.
Id-bearing plugin proposals produce a receipt after this decision boundary.
Trap, timeout, interruption, decode failure, denied capability, malformed data,
stale handle, or exceeded limit before successful return discards the pending
batch. Draining is not mutation. A pending or auto-applied buffer edit can still
be rejected by the buffer owner.
When one successful update carries both editor effects and deferred workspace
I/O, owner publication treats them as one proof until both target queues accept
admission. The paired admission proof carries the validated queue borrows
through publication, and a saturated intent queue or workspace I/O worker queue
returns the paired owner work without mutating either queue.
Deferred workspace I/O follows the same first commit point. Host imports queue
bounded read/write requests, failed guest updates discard them, and only sealed
batches may enter `PluginWorkspaceIoWorkerQueue`. Direct observations are owned
by the pending workspace I/O ledger, spend the same per-update request cap, and
bypass the queue, but they are not a public Wasmtime import because synchronous
host filesystem work is not preemptible by guest timeout machinery. Task-style
workspace observations also follow the first commit point: task read proofs are
pending during the update, failed updates discard them, successful updates seal
them, and the task queue enqueues sealed batches all-or-nothing before
filesystem policy runs. Task resources returned before a failed update are
tombstoned, leaving their table reps occupied until guest cleanup so stale
handles cannot alias later resources. Revocation cancels queued batches by
plugin identity before filesystem work. The current worker executes through
typed workspace policy tokens and `fs_utils` in FIFO order.
Worker queue saturation returns the still-sealed workspace I/O batch with the
closed queue rejection, so scheduler code can retry after capacity frees or
explicitly discard the batch and retain redacted cleanup evidence.
Both workspace queues can cancel all queue-owned work for shutdown or broad
teardown, grouping redacted cancellation reports by plugin identity in
deterministic cleanup order. Retryable sealed batches held outside the queues
remain caller-owned and must still be retried or explicitly discarded by that
caller.
The Wasmtime shutdown cleanup hook applies the same rule to runtime-owned
workspace observation task state: it removes uncommitted active-update task
requests, cancels queue-owned work, and tombstones persistent task resources
without touching caller-held sealed batches.
Execution reports may retain owner-facing success data behind explicit
accessors. Debug and future replay diagnostics must use redacted operation
shapes and byte counts rather than host paths or file bytes.
## Lifecycle And Cancellation
`PluginInstanceState` owns runtime spec, host context, handles, and lifecycle
state for one plugin generation. Scheduling first checks the lifecycle gate,
then creates one active-update proof containing the owned host import snapshot
and update handles. Snapshot construction rejects any host context and handle
store pairing that does not share the same validated plugin identity.
The Wasmtime adapter retains the first host-import rejection for an active
update as a single `{ import, source }` envelope. That keeps redacted
operational attribution and the typed rejection cause together through guest
trap handling and canonical ABI cleanup. The typed `source` owns its
non-authorization operational rejection class, so runtime adapters attach
import attribution without reclassifying host-import causes. Revocation stops
future scheduling, invalidates handles, drops pending effects, and exposes an
explicit `PluginRevocationReport`-gated cleanup path for queue-owned workspace
observation tasks and their persistent task resources. The Wasmtime
observe-task scheduler methods also require the matching active state; a
revoked state denies enqueue, single-task execution, capped batch execution,
and drain-all execution, while failed enqueue still returns the sealed batch
for explicit discard. The drain-all runtime method is named
`execute_all_workspace_observe_tasks`; the bounded owner-loop methods remain
`execute_next_workspace_observe_task` and
`execute_workspace_observe_tasks_up_to`.
The preferred Wasmtime revocation path is `revoke_state`: it rejects
runtime/state identity mismatches before mutating the provided state, then
returns lifecycle revocation and runtime-owned observe-task cleanup together.
Host shutdown can call `cancel_workspace_observe_tasks_for_shutdown` on the
runtime instance without a revocation proof; it is cleanup of authority already
owned by that instance, not guest lifecycle authority.
The v1 unload policy is conservative: every revocation reason unloads the
runtime instance. Reuse after config reload requires an explicit policy change
with tests proving unchanged authority.