--- id: SMH-PLAN-SLXZ2R9V type: plan title: "Plugin Tool Authority and Run Settlement" spec: SMH-SPEC-PLUG0001 status: draft depends_on: [] --- # Plugin Tool Authority and Run Settlement ## Outcome Ordinary component tools remain callable only under request/caller authority, including nested composition. Lifecycle handlers can ensure one next request; cancellation/failure wins; one settled notification follows all run work without reentrant starts. ## Scope Implement the amended [Plugin System](../../specs/SMH-SPEC-PLUG0001-plugin-system/index.md): Tool visibility and authority; candidate/publication and request-pin rules; Budgets and failure; Event boundary → Continuation and settlement. Context-edit persistence, exact request reconstruction, physical routing, and usage aggregation belong to [Recorded Context and Dispatch Provenance](../SMH-PLAN-99TPLN9I-recorded-context-and-dispatch-provenance/index.md). Exclude a new scripting engine, MCP client/discovery backend, new provider operations, vendor/OAuth migration, full bundled-tool migration, and Brush/Nushell SDK design. Implement only host/WIT additions consumed by the slices below; no speculative hook inventory or capability hierarchy. Do not rewrite existing approved plans. ## Entry contracts The existing [harness plan](../SMH-PLAN-PLUG0001-plugin-harness/index.md) supplies ordinary trusted component loading, complete-generation publication, generic tool dispatch, grants, recorded effects, and shared invocation budgets. It is owned by `SMH-SPEC-SPEC0001`, so it is an external interface prerequisite, not a same-spec `depends_on` entry. Provider-codec/transport proof consumes the ordinary component contract from the [provider-plugin plan](../SMH-PLAN-AIAGD002-provider-and-oauth-plugins/index.md), not its full vendor/OAuth rollout. Inspected code has direct component declaration/invocation in `smith-harness/src/wasm.rs` and `plugins/echo/`, but no agent-connected plugin manager, grants, action dispatcher, or nested-call host surface. `wit/smith-plugin.wit` is tool-only and lacks schema, effect, and lifecycle contracts. `smith-core/src/tools.rs` still dispatches fixed native built-ins; `agent.rs` has queued delivery and `TurnSettled`, not the amended authority/settlement protocol. Prerequisite gaps must be resolved in their owning work before dependent proof; they are not permission to retain a native shadow dispatch path or invent an implemented interface. Plan/interface dependencies do not imply implementation completion. ```mermaid flowchart TB H["PLUG0001: ordinary sandbox and host contracts"] -.-> P["SLXZ2R9V: authority and lifecycle policy"] V["AIAGD002: component provider contract"] -.-> P E["99TPLN9I B1: atomic context edit"] -.-> P P -.-> L["99TPLN9I B3: pinned request loadout"] P -.-> U["99TPLN9I B5: causal child usage"] ``` ## Behaviors Each slice crosses ordinary component loading, host policy, core execution, and its public/binary observation where required. Use complete explicitly loaded guest packages, including separate composition and lifecycle consumers; never automatically discover documentation examples. Use raw `wit-bindgen`; each added world interface needs two real consumers and a naming/glossary audit. Missing basic host contracts block the slice rather than making a unit-only or native substitute count as acceptance. ### B1 · Invoke only the tool advertised by the originating request A built eval/RPC turn advertises a validated ordinary component tool, invokes its matching handler, records the result, and follows up under the same round generation. Touch `wit/smith-plugin.wit`, `smith-harness/src/wasm.rs`, the harness registration/runtime owner, `smith-core/src/tools.rs`, `agent.rs`, and real guest fixtures. - Connect validated contribution schemas/identities to generic dispatch; registration is not a hardcoded tool-name match. - Keep registration, activation, per-request advertisement, and caller authorization distinct in host-owned state. - Reject model-emitted disabled, absent, unadvertised, or schema-invalid calls before invocation or effects. - Return actionable typed diagnostics naming the tool, authority failure, and correction; do not drop the error or select an ambiguous short name. - Source definitions and executable handlers from one originating request pin through the complete tool batch. B1 consumes the entry harness's baseline request pin; B2 extends discovery/publication policy and proves reload/retry/failover retention. Proof: real component and scripted component provider through built eval/RPC; an advertised call succeeds, active-but-unadvertised model call fails, disabled call fails, and malformed arguments never enter the guest. Contributed names cannot fall through to native built-ins, including names matching old defaults. Direct `PluginInstance::invoke` tests support codec bounds but are not binary/plugin parity proof. ### B2 · Publish discoveries without changing an active round Validate a discovered contribution set while a request is stalled; the current response/tool batch uses its original definitions and handlers, while a later round sees the replacement. Touch harness generation/registry/runtime owners, `wasm.rs`, `smith-core/src/agent.rs`, and the shared request vocabulary. - Candidate registration/validation performs no operational effects, active mutation, or active subscriptions. - Publish one complete generation atomically; failed publication leaves the previous generation and handlers usable. - Discovery grants no invocation or effect authority; only validated publication makes a contribution eligible for future loadouts. - Pin catalog/provider contributions, advertised definitions, active-policy snapshot, handler bindings, and generation across establishment retries/failover and the resulting tool batch. - Preserve session/branch/queue/secrets/cancellation outside generation lifetime; release retired instances only after pinned work finishes. - Hand an immutable round loadout to companion B3; core must not independently resample live registries. Proof: explicit readiness/release signals around retry, response, and tool execution; publish a changed schema/handler and assert old work stays old, later work becomes new. A candidate attempting an effect or runtime mutation fails before publication; invalid reload retains old subscriptions and produces no candidate effect. Unknown/ambiguous discovered names fail deterministically with sorted candidates; no discovery protocol or remote-tool backend is required. ### B3 · Compose a hidden active tool under narrowing authority An ordinary component explicitly invokes an active unadvertised tool through the host; success requires caller invocation permission and the intersection of target grants and caller-delegated scopes. Touch WIT capability/resource surfaces, harness dispatch/effect/budget owners, `smith-core/src/tools.rs`, durable effect records, and complete composition fixtures. - The host creates and validates caller/request identities and delegated authority; guests cannot forge a caller by supplying another identity string. - Resolve nested targets inside the parent's generation pin; validate every target schema before execution. - Disabled targets remain unreachable; a target grant alone never authorizes its caller. - Scope intersection may only narrow at each hop; secrets follow the same explicit authorized-local-effect boundary. - Carry stable invocation/effect IDs, causal parents, generation, and usage references through the ordinary intent/completion ledger. - Share deadline, fuel, memory/table, host allocation, conversion, log, and output budgets across parent and structured children; fan-out cannot multiply ceilings. - Serialize per instance; orchestration cannot deadlock by reentering a busy instance or detaching child work. - Children finish or cancel before parent return; ordinary guest errors may be caught, but cancellation, exhausted budgets, sandbox violations, and recording failures escape as terminal failures. - Retain already-completed effect evidence on later parent failure; do not automatically retry uncertain child effects. Proof: two ordinary plugin consumers compose through a third target with a bounded real filesystem effect; delegated path A succeeds, target-only permission and path B fail before effects. Nested hop escalation, disabled targets, forged identities, budget-spinning children, conversion/output overflow, parent cancellation, and recording failure fail closed. Child usage/effect attribution feeds companion B5; separate evidence from parent success or durable plugin-state commit. Run the built binary with real files/components and assert denied paths are untouched and all completed child effects remain inspectable after parent failure. ### B4 · Ensure one continuation at an actionable boundary Turn-complete and pre-settlement handlers can request continuation or runtime changes; one validated boundary produces at most the required next request, not duplicate work. Touch WIT event/action records, the harness ordered handler/action owner, `smith-core/src/agent.rs`, companion context-edit APIs, and eval/RPC runtime wiring. - Deliver typed events in deterministic registration order under one shared bounded invocation budget. - Apply cancellation immediately; validate other mutations as one conflict-free batch and publish atomically only between requests after the stream and complete tool-result batch. - Route context-edit actions through companion B1 validation/publication; runtime prompt/tool/model/provider/config changes never persist user configuration implicitly. - Coalesce duplicate continuation requests; an already-eligible tool follow-up or queued-input request satisfies ensure-one-next-request. - Preserve queued input order and its original delivery mode; ending a run does not discard queued input without an accepted queue action. - Explicit stop, cancellation, terminal stream/run failure, or required-decision failure defeats continuation. - Disable a failed/over-budget handler only for its generation and emit one typed diagnostic. - Required-decision failure terminates without partial actions, duplicate terminal events, or erasing recorded effect evidence. Proof: two real handlers request continuation at the same boundary; scripted endpoint observes one request. Repeat with an eligible tool follow-up and each queue delivery mode; input appears once without splitting tool calls/results. Conflicting model/tool/context changes leave the prior runtime/projection intact; failed required decisions and hard exits retain queued input and prevent continuation. Built eval/RPC outputs and durable request sequence agree; no handler-owned alternate agent loop. ### B5 · Notify settlement only after all run work resolves A run settles once after continuation decisions and structured children finish/cancel; settled handlers cannot reopen it or observe a new run reentrantly. Touch `smith-core/src/agent.rs`, harness lifecycle/child-work owners, `smith-rpc/src/lib.rs`, and built-binary lifecycle tests. - Separate actionable pre-settlement from notification-only settled dispatch. - Reject and diagnose continuation for the completed run; do not let it schedule a provider request. - Preserve accepted queued input for a later run; new-run requests received during notification remain deferred until every settled handler returns. - Resolve cancellation/child cleanup and required decision outcomes before one terminal/settled notification; release generation pins only when their work permits. - Make RPC `wait`/`status` and eval completion reflect the same settled boundary after child cleanup and all settled handlers return, not merely arrival of a provider terminal event. - Worker/frontend input can enqueue during notification without starting a second run or blocking render/IO threads on guest work. Proof: a real settled handler uses a deadline-bounded synchronization fixture while another RPC client request queues a new run; no new provider request/event appears until all handlers finish. Rejected settled continuation yields one diagnostic, one terminal notification, and no reopened run. Cancellation with active child work cancels/joins it before `wait` reports settled; queued input remains available to the next run. Use explicit channels/readiness and injected time, never sleeps, polling waits, or retries. ## Behavior dependencies Local slices build observable policy; companion edges transfer contracts at the earliest consumer without whole-plan mutual dependencies. ```mermaid flowchart LR B1["B1: advertised model-call authority"] --> B2["B2: publication and round pins"] B2 --> B3["B3: authorized composition"] B3 --> B4["B4: one continuation"] B4 --> B5["B5: singular settlement"] E["99TPLN9I B1: atomic edit"] -.-> B4 B2 -.-> L["99TPLN9I B3: request loadout"] B3 -.-> U["99TPLN9I B5: usage attribution"] ``` ## Interface structure Core owns semantic run/queue/terminal state; harness owns plugin identity, grants, generation bindings, bounded kernels, child orchestration, and ordered handler dispatch. Typed boundary actions and round pins live in shared vocabulary; no Wasmtime types, futures, or harness dependencies leak into core/RPC. Candidate registration, authority checks, action validation, and effect intent publication precede guest operational effects. Names of new harness modules are chosen by their first real consumer, not a speculative manager hierarchy. ```mermaid flowchart TB W["Ordinary wasm components"] --> I["smith:plugin typed calls and actions"] I --> H["smith-harness: authority, pins, budgets, handlers"] H --> C["smith-core: run boundaries, queue, durable effects"] C --> R["smith-rpc: wait and status"] H --> CLI["smith-cli: shared eval runtime"] ``` Arrows show runtime handoffs, not imports. Harness drives core through its permitted dependency; core receives immutable shared records and returns semantic outcomes without importing harness types. ## Verification and stop conditions - Every new test file names `SMH-SPEC-PLUG0001`; persistence/accounting tests reference their owning `SMH-SPEC-SPEC0001` sentences. - Run fresh scoped host/guest `cargo x check`, `cargo x e2e`, docs and architecture gates after integrated slices; full relevant gates before completion. - Snapshot typed diagnostics, normalized lifecycle traces, and LF-only RPC lines; redact IDs, never authority-relevant fields. - Property tests prove scope intersection never widens, conflict validation is deterministic, and rejected action batches preserve state. - Exact size/allocation bounds cover shared handles, loadouts, action batches, child work, and error paths; scoped mutants target authorization, pin retention, coalescing, and settlement guards. - Two real consumers and the naming/glossary audit gate every world-shape change; prototype permits breaking changes, not relaxed sandbox laws. - Keep instruction budgets unchanged unless separately authorized; profile regressions rather than silently changing pins. - Stop if a guest can forge caller authority, operational work begins during candidate registration, or nested scopes/budgets can widen. - Stop if disabled/unadvertised model calls reach native fallback, handler failure publishes partial actions, or recording failure is catchable. - Stop if guest/child work outlives its parent/run, settlement starts reentrant work, or frontend status reports settled before cleanup and handlers finish. - Stop for missing prerequisite host contracts; do not expand this plan into general harness, provider/OAuth, scripting, or SDK-facility delivery. Draft creation proves no implementation state.