# run-wasm-conformance _(no submodules)_ ## Purpose Exports `runWasmSandboxConformance(label, makeSandbox)` — the conformance harness every WASM-tier sandbox host (this package's own, or any future implementation) MUST pass. The harness pins the observable contract: preopens reflect `policy.fs[]`, the outbound allowlist reflects `policy.fetch[]`, the `rw:` prefix turns a preopen read-write, `dispose()` is idempotent, and the instrument registry exposes the canonical `plugin.permission_denied_total` counter. The harness is exported from the `./testing` subpath so adapters consume it as a normal import. The in-package fixture sandbox passes every scenario; the harness is self-tested via `run-wasm-conformance.test.ts`. ## Features - Six pinned scenarios covering the spec delta's observable behaviour. - Uses the host's `describe`/`it` from `@suaveplan/testing/runner` so adapter test reports show nested suites under the host's tree. - `WasmSandboxFactory` signature lets adapters pass a minimal builder rather than re-implementing the full `createWasmSandbox` surface. ## Usage: Basic ```ts // In an adapter package's test file: import { runWasmSandboxConformance } from "@suaveplan/api-sandbox-wasm/testing"; import { makeMyAdapterSandbox } from "./my-adapter.js"; runWasmSandboxConformance("my-adapter", makeMyAdapterSandbox); ``` ## Usage: Advanced ```ts runWasmSandboxConformance("with-cache", async (input) => { const cached = sandboxCache.get(JSON.stringify(input)); if (cached !== undefined) return cached; const handle = await createWasmSandbox({ /* ... */ }); sandboxCache.set(JSON.stringify(input), handle); return handle; }); ``` ## API Reference - `runWasmSandboxConformance(label: string, makeSandbox: WasmSandboxFactory): void` - `WasmSandboxFactory = (input) => Promise` where `input` is `{ fsRules, fetchRules, denyCapability }`. ## Implementation Notes The harness consumes the adapter's `WasmSandboxHandle` via its public surface only — `preopens`, `outbound`, `instruments`, and `dispose()`. Adapters that wrap or proxy the handle must preserve those properties identically. The harness deliberately uses `dispose()` after every scenario rather than letting GC handle it, because a WASM-runtime under load can pin memory longer than the test budget allows. Adapters that hold open OS resources MUST close them in `dispose()` for the harness to pass on constrained CI runners.