alma 0.1.1

A Bevy-native modal text editor with Vim-style navigation.
Documentation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
# Plugin Security

The plugin security model is complete mediation plus small proof types. Every
value crossing a boundary is untrusted input, a proof produced by one owner, or
a proposal to a later owner.

The Wasm sandbox is one layer. The host boundary is the trust boundary.
Protected assets include buffer text, register and undo text, workspace files,
raw host paths, editor configuration, user-visible diagnostics, ECS topology,
UI responsiveness, and host process stability.

Primary adversaries are malicious components, compromised packages, buggy
plugins with accidental unbounded behavior, manifests that overstate identity
or capability needs, stale handles retained after editor state changes, and
crafted guest paths, text, or serialized payloads.

## Invariants

- A plugin never holds editor authority directly. It holds borrowed WIT
  resources and configured grants that the host revalidates at each import.
- Workspace authority is not a borrowed ambient resource. It is created per
  workspace import from operation kind, normalized path, bounded payload, and
  effective grants. Direct byte delivery also requires an explicit filesystem
  policy context and spends the per-update workspace request budget before
  filesystem access. Guest-visible delivery also needs an enforceable host-side
  timeout or cancellation model before it can cross the Wasmtime boundary.
- Capability authorization is necessary but not sufficient for filesystem
  access. Workspace I/O must still pass through `fs_utils`.
- Generated WIT types stay at the adapter edge and convert into Alma-owned
  types before policy decisions. WIT resources carry authority shape, not raw
  host identifiers.
- Pending work is observable only after a successful guest return.
- Queue capacity is spent only on actionable sealed work. Empty successful
  update batches are valid commit-boundary evidence, but effect, workspace I/O,
  and workspace observe-task schedulers admit them as no-ops rather than
  letting empty work exhaust bounded queues.
- Workspace observation task requests are pending work. Failed guest updates
  discard them; successful updates seal them before the host task queue can
  publish filesystem-policy work. If the guest drops a task resource before
  successful return, the pending request is removed and cannot trigger later
  filesystem work.
- Production task queue enqueueing accepts sealed successful-return batches
  only. Runtime adapters must not push raw read proofs directly into the queue,
  because that would bypass the session request ledger and discard boundary.
  Wasmtime enqueue first requires the task batch identity to match the runtime
  instance, and enqueue, single-task execution, capped batch execution, and
  drain-all execution also require the matching active `PluginInstanceState`,
  so revocation closes late scheduling even when a caller still holds a sealed
  batch.
- The Wasmtime helper that runs an update and schedules observation tasks is an
  owner-loop convenience over the same successful-return batch. If task
  scheduling fails after guest return, the error retains the unscheduled
  owner-work proof plus the retryable task enqueue failure in one private-field
  payload, so external callers cannot construct a mismatched post-update
  schedule error by convention. Its operational-event projection is derived
  from the typed update or enqueue failure, keeping reporting redacted without
  requiring callers to inspect unpublished owner work. Retrying that paired
  schedule error rebuilds a `WasmtimePluginScheduledUpdate` proof after task
  scheduling succeeds; abandoning it consumes both unpublished owner work and
  unscheduled task work into one redacted discard report whose debug output is
  count-shaped. Public split APIs return named boundary structs rather than
  positional tuples. Callers split owner work only when handing it to the
  separate owners.
- Owner publication of that proof validates the intent queue and workspace I/O
  worker queue into private admission proofs before mutating either queue. Each
  paired admission proof retains the exact target queue borrows through
  publication, and each owner queue admission owns its sealed batch until
  publication, so admitted pushes are not raw convention calls. If one owner
  queue is saturated, neither owner observes partial work and the paired proof
  remains retryable or explicitly discardable. Successful publication returns a
  named report with admitted owner-work counts. The retryable proof stays behind
  typed accessors, and its consuming split names the queue rejection and owner
  work instead of relying on a single work-only consuming accessor. Debug output
  exposes only identity, closed rejection class, and counts.
- Once a scheduled update has admitted observe-task work to the runtime queue,
  owner publication returns a named success report carrying both owner
  publication evidence and that scheduled-task report, while owner-queue
  publication failures keep the task report paired with the retryable
  owner-queue failure. Callers cannot accidentally drop the fact that task work
  is already scheduled while deciding whether to retry or discard unpublished
  editor/workspace I/O owner work. Retrying that owner-publication failure
  consumes the paired error and returns either the named success report or the
  same paired failure shape; abandoning it returns a named discard report that
  retains the already-scheduled task report. Scheduled-task
  evidence is named as already admitted at this boundary, and debug reports
  expose counts instead of retained batch internals, nested discard reports, or
  task handles.
- Failed sealed workspace observation task enqueue preserves the sealed batch
  with the closed queue rejection. Explicitly discarding the returned batch
  releases reservations and returns a redacted cleanup report; retrying it on
  the owning queue preserves task ids and pending capacity. Wasmtime rejects a
  batch from another plugin before queue admission and exposes enqueue failures
  through a private-field error with a closed public kind and source-specific
  accessors, so external callers cannot construct a mismatch between lifecycle
  state, runtime identity, queue rejection, and retryable task batch.
  Runtime/state and runtime/batch identity mismatch accessors return named
  borrowed identity pairs instead of positional tuples.
  The low-level queue error split returns named fields, so callers do not
  separate rejection evidence from retryable work by tuple position.
  Queue admission itself retains the validated pending queue storage through
  enqueue, so all-or-nothing reservation validation and publication are one
  proof-mediated operation rather than a validate-then-push convention.
- Failed sealed workspace I/O worker enqueue preserves the sealed batch with
  the closed queue rejection. Explicitly discarding the returned batch returns
  a redacted cleanup report; retrying it after capacity frees preserves the
  accepted successful-return work. Its consuming split returns named fields.
- Queue-owned workspace I/O and observation task state can be canceled by one
  identity or by all identities for shutdown. All-identity cleanup groups
  reports by plugin identity in deterministic cleanup order and exposes counts
  only. Retryable sealed batches outside queues remain caller-owned.
- Wasmtime workspace observation task cleanup at the runtime boundary requires
  a `PluginRevocationReport` for the same identity, then clears queue-owned
  task state and persistent task resources. A report for another identity fails
  closed as an instance/state mismatch.
- Wasmtime shutdown cleanup clears only runtime-owned workspace observation
  task state. It cancels queued work, removes uncommitted active-update task
  reservations, and tombstones persistent resources, while retryable sealed
  batches already returned to callers remain caller-owned.
- The Wasmtime helper that revokes host state and clears runtime-owned
  workspace observation tasks first proves the runtime and state identities
  match. A mismatch returns the closed instance/state rejection before the
  provided state is mutated. Its consuming split returns named lifecycle
  revocation and runtime-owned task cleanup fields instead of a positional
  tuple.
- Persistent Wasmtime task resources retain their authorizing workspace path.
  The host-session boundary returns the reserved handle and authorized path as
  one proof, so the Wasmtime adapter does not reconstruct resource authority
  from parallel local state. Its consuming split names the task handle and
  authorizing path before the runtime persists them. Poll and take revalidate
  that path against the current update snapshot before resource-table lookup or
  queue access; denied revalidation tombstones the resource without freeing its
  table rep and returns the typed authorization rejection. The occupied-resource
  cap is a non-zero proof derived from the same queue limits as task scheduling.
  Later guest or canonical drops of host-invalidated task resources are cleanup
  no-ops. If the Wasmtime table and runtime authority tracker diverge, start,
  resolve, and drop fail closed with the existing resource-handle rejection
  vocabulary instead of relying on debug-only assertions. A reused table rep
  that is still tracked tombstones the stale tracker entry and removes the new
  table entry before returning. Table lookup/delete errors tombstone the tracked
  resource before returning unless drop already freed the table slot.
- Deferred workspace I/O, direct host-session observations, and task-style
  observation reservations spend one shared per-update request ledger. No path
  may bypass that accounting by choosing a different commit path.
- Deferred workspace I/O does not maintain an independent mutable request
  counter. Its charged request count is the pending batch's retained operation
  count, while the shared ledger tracks only non-deferred charges.
- Task-style observation reservations pair the pending task batch, authorized
  read proof, and shared request ledger by `PluginIdentity` before charging the
  ledger or reserving a task id.
- Pending effect commits, workspace I/O commit failures, worker queue
  failures, and observe-task queue failures expose closed error classes. Their
  field, identity, and sealed-reservation details also carry closed source
  vocabularies, so callers can distinguish access-proof, request-ledger,
  identity, queue-capacity, and queue reservation failures without parsing
  presentation text.
  For host queue zero-limit failures, the field vocabulary is part of the error
  value rather than a presentation-only projection.
- Workspace read and write execution accept non-zero byte cap proofs, not raw
  integers. Validated budgets produce read proofs for deferred reads, direct
  host-session observations, and task-style observations, and write proofs for
  deferred artifact writes.
- Host queues, handle stores, ledgers, and pending batches consume validated
  limit and budget proofs directly. Zero-limit diagnostics stay at the proof
  constructors, and constructors that already receive proof types are
  infallible.
- Paired successful-return, owner-work, post-update schedule, and scheduled
  owner-publication proofs enforce same-plugin identity in release builds
  before constructing a proof value. A mismatched pair is an internal invariant
  violation, not a representable cross-plugin proof.
- Workspace request-budget, pending-effect, intent queue, proposal lane,
  observe-task pending-capacity, workspace worker, and operational queue
  saturation diagnostics retain non-zero cap proofs from validated limits, so
  rejected capacity diagnostics cannot represent a zero cap by convention.
- Runtime limit, workspace I/O budget, and workspace observation task queue
  zero-limit errors carry closed field vocabularies, not arbitrary diagnostic
  strings.
- Guest decode errors carry closed field vocabulary, not adapter-supplied
  strings.
- Workspace observation task requests retain the producing update's non-zero
  read byte cap. Queue execution uses the retained cap, not a later caller
  parameter, so scheduling cannot widen guest-visible bytes.
- Runtime task execution APIs make unbounded work explicit: the drain-all path
  is named `execute_all_workspace_observe_tasks`, while owner-loop callers can
  use `execute_next_workspace_observe_task` or the non-zero capped
  `execute_workspace_observe_tasks_up_to` path.
- Task ids returned before an update commits are not reused. A failed update
  may burn reserved ids, but it releases reserved queue capacity and must not
  publish filesystem work or let a stale id observe a later task.
- Polling and taking workspace observation tasks require an identity-scoped
  lookup and return closed state shapes. Polling carries only redacted outcome
  shape, and taking is the only task-result path that carries the byte-bearing
  guest-delivery outcome. Queue records and retained completions own an
  identity-scoped task key, so internal task state cannot carry an inert task
  id without its plugin owner. The queue also exposes the same payload-free
  state projection for adapters that do not need bytes. Pending tasks cannot
  be consumed; completed outcomes can be consumed once; unknown, evicted,
  already-taken, or cross-plugin ids are indistinguishable.
- Task reservation accounting must preserve `Send` and `Sync` host-owned batch
  shapes and use explicit RAII queue-slot accounting, so future runtime
  scheduling cannot depend on thread-local state or raw shared-owner counts.
  Reservation counter underflow is an internal invariant violation in all
  builds, not a debug-only check.
- Task result vocabulary is not queue authority. Task ids, owned
  identity-scoped task handles, queue keys, internal handle-borrowed lookup
  matching, payload-free state queries, payload-free poll states, consuming
  take states, redacted poll/take result shapes, and
  `PluginWorkspaceObserveTaskCompletionShape` may be handed to adapters, but
  queue mutation, retention, and revocation cleanup stay behind the host queue
  owner. Wasmtime exposes that cleanup only through a matching
  `PluginRevocationReport`, so runtime resource invalidation stays tied to
  lifecycle revocation. Poll/take resource resolution also carries the original
  workspace path provenance and tombstones resources whose path is no longer
  authorized by the current update snapshot. Drops of already-invalidated task
  resources are idempotent cleanup, and tombstoned reps remain occupied until
  guest drop. Drops of uncommitted task resources also remove the matching
  pending request before it can become sealed work. Runtime cancellation also
  removes matching uncommitted task requests and releases their reservations
  before they can become sealed work. Starting a new Wasmtime update tombstones
  any task resources still marked as started by a prior abandoned update before
  fresh resources are accepted.
- Draining a sealed batch is the only commit point from plugin effects into ECS
  messages.
- Drained effect reports split into named owner request batches with the
  drained plugin identity retained, so buffer proposal requests and status
  requests are not separated by tuple-position convention.
- Failed `PluginIntentQueue` admission preserves the sealed effect batch with
  the closed queue rejection. Explicitly discarding the returned batch produces
  a redacted cleanup report; retrying it after capacity frees preserves the
  successful-return work. Its consuming split returns named fields.
- Owner systems remain the only commit point for authoritative mutation.
- Stale handles, wrong-kind handles, missing ECS targets, denied capabilities,
  invalid ranges, malformed strings, and exceeded limits are normal rejected
  outcomes with closed reason enums.
- User-facing diagnostics expose stable identity and reason shape, not raw
  paths, buffer text, register text, guest payloads, OS strings, or Bevy
  entities.
- Runtime state that survives an update has an owner and a generation. The
  owner can revoke it, and the generation makes stale values fail closed.
- Wasmtime update-scoped `ResourceTable` reps are typed by resource kind before
  they are stored for guest-call borrows or cleanup, so view and buffer resource
  authority cannot be swapped by raw table-index convention.
- Host grant authorization is implemented once by a plugin-scoped authority
  proof. Live contexts and per-update snapshots may reuse it, but adapters do
  not own parallel denial or workspace-token projection rules.
- Host import snapshots pair effective grants with handle stores only when
  both carry the same validated plugin identity.
- Workspace read/write access proofs retain the plugin identity that authorized
  them. Filesystem-policy tokens stay internal to `workspace_io`, and pending
  workspace I/O, direct observations, and observation task batches reject access
  proofs from another plugin identity instead of relying on caller convention.
- Pending workspace artifact writes retain a bounded payload proof with the
  non-zero write cap that admitted it, so sealed write work cannot carry an
  over-budget payload by convention.
- The Wasmtime adapter stores a host-import rejection and its redacted import
  class in one envelope. A source error without attribution, or attribution
  without a source error, is not representable.
- `PluginHostImportError` owns the closed rejection class for
  non-authorization import failures. Authorization failures deliberately have
  no rejection class and map to denied-import events.
- Interior mutability is not authority. Tables that use `Mutex`, `RwLock`,
  `RefCell`, or atomics still expose APIs that preserve generation checks,
  bounds, and revocation ordering.

## Proof Types

Authority-bearing Rust values have private fields and one validating
constructor. Accessors expose only what the next boundary needs.

Important proofs:

- `PluginIdentity`: stable ASCII identity
- `PluginWitWorld`: current supported WIT world proven at the enabled
  config/manifest boundary
- `ValidatedPluginConfig`: registry entry after identity validation
- `EnabledPluginConfig<'_>`: enabled registry view with loadable-entry proofs
- `PluginComponentPath`: normalized relative component path shape only
- `ValidatedPluginRuntimeLimits`: non-zero runtime limits bounded by host caps,
  with host collection caps retained as host-sized proofs after config
  validation
- `PolicyOpenedPluginManifest`: manifest bytes read through `fs_utils` before
  parsing
- `AuthorizedPluginManifest`: manifest identity and WIT world matched the
  enabled config
- `AuthorizedPluginComponent`: component bytes read through `fs_utils` before
  Wasmtime construction
- `PluginProposalPolicy`: static per-plugin proposal review policy with
  explicit `auto_apply` and `manual_review` modes
- `WorkspacePathGrant`: normalized grant prefix, with explicit broad grants
- `WorkspacePath` and `WorkspacePathRef`: owned and borrowed validated guest
  path vocabulary
- `CapabilityAtom`: stable policy capability spelling, path arity,
  authorization-ref construction, and redacted shape projection shared by
  config, manifests, WIT adapters, and host authorization
- `GuestDecodeField`: stable generated-to-Alma field vocabulary for decode
  errors at host-import boundaries
- `GuestDecodeLimits`: non-zero guest string, payload, and scalar count caps
  derived from validated runtime policy before adapter decode or return-size
  checks
- `WitHostImport`: exposed host-import metadata tying WIT function names to
  capability atoms and redacted operational classes
- `WitWorkspaceObserveTaskImport`: start/poll/take metadata for the
  guest-visible workspace read task surface, tying WIT function names to
  `workspace.observe` and redacted operational classes
- `PluginHostAuthority`: plugin identity and effective capability grants after
  policy projection, reused by live host contexts and update snapshots
- `AuthorizedWorkspaceReadAccess` and `AuthorizedWorkspaceWriteAccess`:
  identity-bearing capability proofs, not filesystem authority
- `PluginWorkspaceIoBudget`, `PluginWorkspaceReadByteLimit`,
  `PluginWorkspaceWriteByteLimit`, and the internal request ledger: non-zero
  per-update workspace limits, byte-cap proof projection, and shared request
  accounting across deferred I/O, direct observations, and task-style
  observation reservations, with deferred request counts derived from pending
  batch storage rather than duplicated in the ledger
- `PluginWorkspaceIoCommitErrorKind` and
  `PluginWorkspaceIoIdentityMismatchSource`: closed commit-failure class and
  identity-pairing source for access-proof and request-ledger mismatches at
  workspace admission
- `PluginEffectBatchLimitField` and `PluginEffectCommitErrorKind`: closed
  pending-effect batch diagnostics for host-import effect admission failures
- internal `PluginWorkspaceReadToken` and `PluginWorkspaceWriteToken`: typed
  bridges into `fs_utils` after capability authorization. Token construction
  and filesystem execution stay inside `workspace_io`; public callers retain
  access proofs rather than raw policy tokens.
- `PluginWorkspaceWritePayload`: bounded deferred write payload proof, retaining
  the non-zero write cap that admitted the bytes and exposing only byte length
  in debug shapes.
- `PluginWorkspaceIoWorkerQueueLimitField` and
  `PluginWorkspaceIoWorkerQueueErrorKind`: closed worker-queue diagnostics for
  sealed workspace I/O admission failures
- `PluginWorkspaceIoWorkerEnqueueError`: retry-safe sealed workspace I/O
  admission failure that keeps the closed queue rejection paired with the
  still-sealed batch
- `PendingPluginWorkspaceIoBatch::observe_existing`: direct read projection
  through the shared request ledger and `fs_utils`, returning only the
  guest-delivery outcome while rejecting cross-plugin access proofs before
  charging budget or touching filesystem policy. The host-import session
  helper that calls it is plugin-internal; public guest reads use the
  task/result ABI.
- `PluginWorkspaceIoCompletion`: operation-typed execution result, with read
  and write variants that cannot pair one operation with another operation's
  success payload
- `PluginWorkspaceReadSuccess`, `PluginWorkspaceWriteSuccess`,
  `PluginWorkspaceReadError`, and `PluginWorkspaceWriteError`:
  operation-specific filesystem-policy outcomes
- `PluginWorkspaceObserveOutcome` and `PluginWorkspaceObserveBytes`:
  guest-delivery projection for `workspace.observe`, carrying only bounded
  bytes or one closed rejection and no path metadata
- `PluginWorkspaceObserveOutcomeShape`: redacted diagnostic and adapter shape
  for guest-delivery outcomes, carrying only byte length or closed rejection
- `PluginWorkspaceObserveTaskId`, `PluginWorkspaceObserveTaskHandle`, owned
  queue task keys, internal handle-borrowed lookup matching,
  `PluginWorkspaceObserveTaskState`, `PluginWorkspaceObserveTaskResultShape`,
  `PluginWorkspaceObserveTaskQueue`, `PluginWorkspaceObserveTaskPoll`,
  `PluginWorkspaceObserveTaskTake`, `PluginWorkspaceObserveTaskCompletion`, and
  `PluginWorkspaceObserveTaskCancellationReport`: host-owned task model for
  guest-visible workspace reads, with inert task ids, owned identity-scoped
  handles and queue records, identity-scoped state, payload-free poll, and
  consuming take queries, shared closed pending, completed, and unknown result
  state, shared redacted poll/take result shapes, identity-scoped enqueue and
  retained completion shapes, pending and retained-result bounds, retained read
  byte caps, FIFO filesystem-policy execution,
  pending-capacity plus non-reused id reservation before guest-visible return,
  explicit RAII queue-slot accounting, redacted saturation events, and
  revocation or shutdown cleanup
- `WasmtimePluginInstance::cancel_workspace_observe_tasks_for_revocation`:
  runtime-owned cleanup hook that requires a matching revocation proof before
  canceling task state and tombstoning persistent task resources
- `WasmtimePluginInstance::cancel_workspace_observe_tasks_for_shutdown`:
  runtime-owned shutdown cleanup hook for task state still held by the
  instance
- `WasmtimePluginInstance::enqueue_workspace_observe_tasks`: task scheduler
  admission for sealed successful-return batches.
- Wasmtime workspace observation task execution hooks:
  `execute_next_workspace_observe_task`,
  `execute_workspace_observe_tasks_up_to`, and
  `execute_all_workspace_observe_tasks` require matching active instance state
  before filesystem-policy execution. The drain-all path is explicit by name.
- `PendingPluginWorkspaceObserveTaskBatch`,
  `SealedPluginWorkspaceObserveTaskBatch`,
  `PluginWorkspaceObserveTaskResourceAuthority`, and
  `PluginWorkspaceObserveTaskDiscardReport`: successful-return commit boundary
  for task-style workspace reads, carrying reserved identity-scoped handles and
  read byte caps while rejecting cross-plugin read proofs or request ledgers
  before charging budget, pairing resource handles with their authorized
  revalidation paths, and keeping task filesystem work discardable until the
  guest update returns successfully.
- `PluginWorkspaceObserveTaskQueueErrorKind` and
  `PluginWorkspaceObserveTaskReservationMismatch`: closed task-queue failure
  class and sealed-reservation mismatch source for identity and queue ownership
  failures before task enqueue
- `PluginRuntimeSpec`: runtime input after policy projection and validation,
  with identity derived from `AuthorizedPluginComponent`
- `PluginInstanceState`: active or revoked lifecycle gate for one loaded
  runtime instance
- `PluginActiveUpdate`: crate-private proof pairing one import snapshot with
  update handles after lifecycle gating
- `WasmtimeUpdateResources`: private adapter proof retaining typed view and
  buffer resource-table reps for one update call and its cleanup
- `PluginHostImportSnapshot`: validated update-scoped pairing of effective
  grants and live handles for one plugin identity
- `PluginBufferSnapshot`: bounded text and revision observed when a buffer
  handle is issued
- `PluginBufferEditProposal`: snapshot-derived edit proposal with identity,
  capability, target, and base revision provenance
- `PluginBufferProposalCapability`: proposal-specific wrapper over
  `CapabilityAtom`, so proposal receipts do not own independent capability
  spellings
- `PluginProposalId`: non-zero host proposal identifier
- `PendingPluginBufferEditProposal`: host-visible proposal retained until
  auto-apply, manual apply, or manual rejection
- `PluginBufferEditProposalReceipt`: id-correlated result of proposal-lane or
  buffer-owner decision
- `PluginRuntimeTraceEvent`: redacted replay/telemetry event adapted from
  owner-boundary reports, identity-scoped workspace observation task
  completion shapes, cancellations, and receipts
- `PluginProposalReceiptLog`: bounded in-session receipt retention
- `SealedPluginEffectBatch` and `PluginIntentQueueEnqueueError`: effects from a
  successful guest return, plus retry-safe ECS admission failure that keeps the
  sealed batch paired with the closed queue rejection
- `PluginHandleStore`: per-plugin view and buffer handle owner and revocation
  boundary
- `ResolvedPluginBuffer` and `ResolvedPluginView`: short-lived host proofs
  produced by handle resolution

Reusable configuration snapshots may implement `Clone` because they do not
represent live runtime authority by themselves. Guest-visible handles may
implement `Copy` because they are inert identifiers and must be resolved through
the owning `PluginHandleStore` on each use.

Short-lived transition proofs should be move-only unless cloning cannot extend
their lifetime or authority. This includes manifest authorization, effective
plugin projection, runtime specs, host contexts, workspace access proofs,
pending batches, sealed batches, drained reports, edit proposals, resolved
handles, and handle stores.

## Capability Rules

Default deny. Config and manifest are both authority ceilings. Effective
workspace grants are the narrowest overlapping prefixes, so either side can
reduce authority and neither side can widen it alone.

V1 capability atoms:

- `buffer.observe`
- `buffer.propose_edit`
- `workspace.observe`
- `workspace.artifact_write`
- `status.publish`

Reserved but unimplemented:

- `workspace.cache_write`
- `workspace.propose_patch`

Unknown config fields, unknown manifest fields, unknown WIT worlds, unknown
capabilities, unknown handles, malformed paths, and invalid limits fail closed.

## ABI Rules

`CURRENT_WIT_WORLD` is the only supported ABI world for v1.

Generated WIT types are private to the ABI boundary. Use `TryFrom` or narrow
decode functions whenever malformed, oversized, stale, unauthorized, or
unsupported guest data can appear. Use `From` only when conversion is
infallible and carries no new authority.
Decode functions must report one `GuestDecodeField` value, not arbitrary field
strings supplied by adapters.

Every exposed host import must map to:

- one named user authority
- one Rust capability variant
- one typed WIT host-import metadata variant
- one config and manifest spelling
- one authorization check
- one redacted error shape
- one deterministic drift test

`WitHostImport` is the default extension point for exposed imports. It keeps
the WIT function name, authorizing capability atom, and redacted operational
import class together so future imports cannot update one surface while
silently skipping another.

`CapabilityAtom` is the default extension point for capability vocabulary. WIT
capability values, authorization-ref path arity, and redacted capability shapes
should derive from the atom so a new capability cannot silently add a schema or
ABI spelling without an owned policy shape.

View and buffer authorities are host-owned, per-plugin scoped, and redacted in
diagnostics. Public WIT imports use borrowed resources instead of scalar ids.
The Wasmtime adapter maps resources through a store-local `ResourceTable` and
then through a captured `PluginHandleStoreSnapshot`; Wasmtime resource reps are
runtime machinery, not a public handle format. Host handle generations remain
an internal revocation invariant.

Workspace authority is narrower than a resource handle. A workspace host import
must decode and validate the path, check the requested operation against
effective grants, enforce payload and request budgets, then enqueue a typed
deferred workspace request. Internal policy tokens are constructed only inside
`workspace_io`. The host-session observation helper can perform a direct
bounded read through an explicit filesystem policy context, but only through
the pending workspace I/O ledger, and it is not guest-visible. Raw host paths
and filesystem access never enter guest-visible types.

Workspace access proofs are plugin-scoped. If a caller tries to queue a read or
write proof under another plugin identity, the host rejects the batch before
filesystem policy sees the request. Task resources keep the same rule: task ids
are not authority, and polling or taking a result must carry the owning
`PluginIdentity`.

Guest-visible `workspace.observe` is exposed only as a start/poll/take task
resource. It uses the bytes-or-rejected delivery projection before any read
bytes cross back into guest code. Owner-facing display paths and filesystem
error detail do not cross that boundary. Malformed paths and denied capability
remain host-import rejections; filesystem-policy read failures become the
closed guest-domain rejection. Synchronous Rust filesystem reads inside a
Wasmtime host import are not acceptable unless the host can enforce timeout and
cancellation without waiting for the read to return.
The task-based WIT shape moves as one group. A start import without poll/take,
or poll/take without matching start authority, would turn task resources into
an underspecified protocol surface. The WIT metadata owns the function names,
authorizing capability atom, and redacted operational import classes. Tests
prove the group is complete, the old blocking read import is absent, and
diagnostics cannot drift from the exposed import group.
The observation task queue provides bounded pending reads, bounded retained
results, identity-scoped polling, non-reused id reservation, pending-capacity
reservation, and revocation cleanup. The pending/sealed task batch proves that
task filesystem work stays behind successful guest return even when the task
resource and queue slot were reserved earlier in the update.
The queue state, poll, and take APIs use the public state shape: pending,
completed, and unknown. Poll and take also share one redacted result shape;
completed poll results expose only the guest-delivery outcome shape, retained
completion shapes carry the task's owning identity, and take is the only path
that consumes and returns the byte-bearing outcome.
This keeps stale, evicted, already taken, and cross-plugin task ids from
becoming distinguishable authority signals.

Prefer WIT algebraic types for public contracts: variants and enums for closed
operation cases, options for true absence, flags for independent booleans, and
results for expected domain failures where the guest may continue. Traps,
timeouts, fuel exhaustion, cancellation, malformed resource use, and host
failures abort the update and discard the session.

Use WIT worlds or linker construction for static authority profiles when plugin
classes diverge. Keep `PluginHostContext` for dynamic policy over specific
buffers, revisions, workspace grants, and runtime limits.

## Error And Diagnostics

Plugin errors stay concrete until an outer boundary maps them to diagnostics,
status, retry, or telemetry. Internal callers should be able to branch on exact
causes such as denied capability, stale handle, malformed guest data, resource
exhaustion, timeout, queue saturation, or owner rejection.

Host-import source errors expose redacted rejection classifiers for outer
diagnostics that do not need the full source enum. The Wasmtime adapter adds
redacted phase and import attribution, and its lower-level runtime failure
detail also uses a closed class vocabulary while dropping raw Wasmtime and OS
source text. Host-import rejection attribution is kept with the typed source
error until the operational event is built. These classifiers do not replace
typed source errors.

Operational diagnostics may include plugin identity, lifecycle hook, a closed
host-import name, closed rejection shape, closed runtime failure class, closed
revocation reason, closed handle kind, capability shape, queue name, closed
limit field name, and byte counts. They must not include guest payloads,
workspace bytes, raw paths, OS error strings, buffer text, register contents,
or Bevy entities.
Lifecycle hooks, host imports, runtime setup failures, canonical ABI
post-return cleanup failures, revocation reasons, handle kinds, and resource
handle rejection reasons use closed vocabularies before becoming operational
events. Closed queue, revocation-reason, handle-kind, resource-handle
rejection, host-state mismatch, and host-import rejection classes render
through explicit stable text, not Rust debug formatting.

Proposal lane diagnostics may expose proposal ids, source identity, capability
shape, target shape, base revision, redacted edit shape, and redacted diff byte
counts. They must not expose the proposed replacement text.

Proposal review policy is not plugin authority and does not let a guest bypass
the proposal lane. It chooses the post-drain handling for admitted buffer edit
proposals from the producing plugin's validated identity. Unconfigured proposal
sources use the inert compatibility default, `auto_apply`.

Proposal receipts may expose proposal ids, source identity, capability shape,
target shape, base revision, redacted edit shape, owner boundary, result
revision, or closed rejection reason. They must not expose proposed replacement
text or raw ECS ids.

Proposal capability attribution derives from `CapabilityAtom`. Proposal-specific
wrappers are acceptable when they constrain which atoms can appear at a given
proposal boundary.

Workspace I/O success values may expose escaped display paths and bounded bytes
only through explicit accessors for the owner/user surface that requested them.
Debug, operational events, and future replay traces must reduce those successes
to operation kind, byte counts, and closed outcome classes.
Observe-task queue and pending/sealed batch debug output is count-shaped; task
handles and per-task retained shapes stay behind explicit task-result and
enqueue-report accessors.
Successful-return aggregate debug output is also count-shaped. Host-import and
owner-batch proofs expose identity plus work counts rather than formatting the
nested sealed effect, workspace I/O, or observe-task batches by convention.
Guest-visible workspace observations use a narrower projection than owner/user
surfaces: success carries bounded bytes only, and failure carries a closed
rejection without raw paths or filesystem cause.

Runtime trace events are diagnostic artifacts, not authority. They may retain
plugin identity, capability spellings, non-zero host task ids, revisions, byte
counts, closed operational classes, and redacted edit shapes. They must not
retain raw ECS ids, workspace-relative paths, host paths, status text,
replacement text, buffer text, file bytes, OS errors, or guest payloads.