--- id: SMH-PLAN-XRJS3NMU type: plan title: "Durable Plugin State and Recovery Resources" spec: SMH-SPEC-PLUG0001 status: draft depends_on: [SMH-PLAN-SLXZ2R9V] --- # Durable Plugin State and Recovery Resources ## Outcome Ordinary components retain authorized state across instance replacement and process reopen without owning storage or forging work/effect outcomes. Recovery preserves execution pins, grants, effect evidence, and branch semantics; missing prerequisites block rather than silently rebind. ## Scope and coordination Implement Durable resources and related acceptance in [Plugin System](../../specs/SMH-SPEC-PLUG0001-plugin-system/index.md). Consume shared commit/work/state/recovery mechanisms from [Durable Submissions, Recovery, and Observation](../SMH-PLAN-QL9EGZAT-durable-submissions-recovery-and-observation/index.md); do not implement a second persistence authority. No generic guest task-definition engine, background workflow API, JSON document database, or persisted wasm stack. [Plugin authority](../SMH-PLAN-SLXZ2R9V-plugin-tool-authority-and-run-settlement/index.md) supplies request/caller authority, round pins, structured children, budgets, and settled lifecycle. [Harness](../SMH-PLAN-PLUG0001-plugin-harness/index.md) supplies ordinary loading, grants, effects, and complete-generation publication. Cross-spec prerequisites are explicit interface handoffs, not `depends_on` entries. Approved harness plan stays unchanged; this plan does not reopen its delivery scope. The shared runtime plan's B1–B3 and authority plan do not depend on this resource extension, preventing a dependency cycle. Current `wit/smith-plugin.wit` and `smith-harness/src/wasm.rs` lack these resources; new interface/module names must earn their shape through consumers. Candidate ownership: shared state/work identities in `smith`; validated records and projections in `smith-core`; grants, resource table, generations, and invocation mediation in `smith-harness`; declarations in `wit/` and ordinary guests in `plugins/`. No Wasmtime types or function callbacks cross core/WIT boundaries. ## Dependencies Solid edges order local delivery and same-spec prerequisite; dashed edges identify cross-spec behavior handoffs. ```mermaid flowchart TB authority["SLXZ2R9V: authority and lifecycle"] --> p1["P1: state survives reload"] harness["PLUG0001: component host"] -.-> p1 kernel["QL9EGZAT B3: atomic state and work"] -.-> p1 p1 --> p2["P2: isolated bounded resources"] p2 --> p3["P3: pinned recovery"] p3 --> p4["P4: historical state and forks"] fork["QL9EGZAT B6: fork isolation"] -.-> p4 ``` ## Behaviors Each slice runs through ordinary loaded components and shared runtime observation, not direct engine calls alone. Use two real stateful consumers: a bounded workspace-review progress tool and a session-scoped operation-summary tool. Their distinct state and read/update operations must be useful through eval/RPC; conformance-only stubs do not satisfy world discovery. Guests use raw `wit-bindgen`; every new interface has two consumers plus naming/glossary audit. ### P1 · Update state, replace guest instance, observe the same committed value Let each consumer read/update owned bounded state through invocation resources, returning observable content after durable acknowledgement. Touch WIT resource/value/error declarations, harness wasm/resource/dispatch owner, shared state identity, core state/commit codecs, runtime inspection, and two guest packages. - Declare state owner, version, item/value bounds, retention, and branch/fork policy with each contribution; validate before publication. - Resolve state independently of guest memory/instance affinity; resource acquisition binds authorized scope and active invocation. - Guest submits bounded typed update requests; host records state and corresponding work checkpoint in one shared change. - Use canonical CBOR only for arbitrary state payloads, typed metadata for core identity/version/ownership; retain raw unsupported state without executing it. - Return committed value/revision and publish dependent guest result only after durable acknowledgement. - Pre-admission failure changes nothing; later guest failure preserves prior committed state and completed effects. Proof: built eval/RPC invokes both tools, replaces their instances/reloads compatible code between calls, and reopens process; committed values persist with no guest-local authority. Inject commit rejection, uncertain storage failure, and guest trap after commit; inspect prior/committed state and effect evidence consistently. No direct guest filesystem storage or additional state file is permitted. ### P2 · Reject another invocation's resources and accumulated quota excess Enforce resource scope, stale-handle rejection, version validation, and aggregate state/work accounting at host mediation. Touch resource tables, grants/budgets/generation owner, WIT faults, core admission limits, and hostile ordinary guest fixtures. - Durable IDs are references, not capabilities; validate scope/caller for every acquisition and operation. - Expire handles when invocation ends, including cancellation/trap/close; reopening reacquires fresh handles to permitted durable data. - Reject another session/branch/owner's identifier and stale or forged handles before mutation or external effects. - Bound item/byte totals across repeated state writes and calls, not only each payload; charge admission before commit. - Reuse shared live-work count/depth limits and parent budgets; no detached child or wider delegated authority. - Reject unsupported versions without deleting payloads or silently migrating historical state through current code. Proof: both real consumers retain their own state; adversarial guests attempt cross-owner access, reuse after return/reload, malformed payload depth, accumulated quota growth, and child budget escape. Built binary exposes precise typed diagnostics; denied state/files stay unchanged; observer reads schedule no guest work. Property tests prove scope narrowing and rejected-change invariance; boundary tests exercise exact quota and one-over values. ### P3 · Reopen blocked work without selecting same-named replacement code Restore a recoverable ordinary component invocation from shared work records, or report why required execution prerequisites are unavailable. Touch harness loader/registry/generation/resource reconstruction, shared provenance, core work/receipt inspection, and component fixtures. - Record component/generation identity and required authority at work checkpoint boundaries; continuation consumes recorded pins rather than current same-name lookup. - Verify available artifact and current authorization satisfy the recorded continuation; do not restore revoked grants merely because history names them. - Missing component, incompatible world/state version, or unavailable authority yields inspectable blocked work and preserves bytes/evidence. - Reacquire fresh invocation handles only after validation; no restoration of raw resource indices or VM stacks. - Resume only a checkpoint with no unresolved prior effect; uncertain effects stay unknown under shared recovery policy. - Same artifact restored under valid authority permits explicit continuation; a same-named different generation does not. - Existing provider-round pin retention remains unchanged; do not promise indefinite artifact retention or invent a general migration/rebinding policy. Proof: kill after acknowledged state/checkpoint before the next undispatched effect, replace installed artifact or revoke grant, reopen, and inspect blocked receipt with no invocation/effect. Restore exact prerequisite and explicitly continue; one next effect runs and previous state remains intact. Kill after effect before completion; even restored code cannot auto-retry unknown effect. Close and parent cancellation invalidate resources and preserve committed state; singular settlement consumes authority-plan semantics. ### P4 · Fork historical plugin state without inheriting live ownership Exercise declared branch/fork policy through shared fork facade and both stateful tools. Touch core state history/fork projections, harness resource acquisition, CLI/RPC session inspection, and ordinary guest behavior. - Reconstruct state at selected historical point from recorded values; current configuration/code cannot rewrite history. - Apply declared copy/fresh policy to new fork-owned state; source live work and admission keys remain source-attributed evidence. - Do not import later source state/completions; retain historical unknown effects without making them runnable. - Missing state definition preserves raw payload and prevents incompatible typed access, not fork data loss. - Bound fork acquisition/materialization and active state quotas; reject excess without partially published fork or source mutation. Proof: update state twice, fork at earlier point while source work is paused, then finish source. Copied state matches historical value; fresh state follows declaration; no source work executes in fork; new fork invocation acquires independent resources. Reopen with consumer missing, inspect preserved state, restore valid consumer, and observe the same historical values. ## Interface handoff Arrows show mediated operations, not library imports. ```mermaid flowchart TB guests["Two ordinary stateful guests"] --> wit["Granted invocation resources"] wit --> host["Host scope, pin, budget checks"] host --> changes["Shared committed changes"] changes --> history["Existing binary session authority"] history --> views["Receipt and state inspection"] ``` ## Verification and stops - Test headers name `SMH-SPEC-PLUG0001`; shared persistence tests also identify their owning Smith spec contracts. - Run fresh scoped host/guest `cargo x check`, `cargo x test`, `cargo x e2e`, docs and architecture gates after slices; final relevant workspace gates before completion. - Use real files/components/binary, explicit barriers and deadlines, deterministic event traces, reviewed snapshots, property tests, exact size/allocation bounds, and scoped mutation tests for resource/authority guards. - Preserve unknown records and existing instruction pins; no silent format change, perf re-pin, or dependency/config edit. - Stop if an interface lacks two real consumers or needs raw database access, mutable core-task writes, ambient effects, detached work, or restored VM handles. - Stop for unresolved per-state lifetime/fork policy, unavailable provenance, unsupported version semantics, or ambiguous authorization. - No implementation, approval, general migration engine, or background-work authority is implied by this draft.