Initial Commit

This commit is contained in:
2026-05-27 23:29:53 +01:00
commit fbc70f96e6
10000 changed files with 1102152 additions and 0 deletions

View File

@@ -0,0 +1,97 @@
# TS→WASM Compiler (Javy-backed, WASI-stdio variant)
**Package**: `@suaveplan/wasm-compiler-javy`
**Status**: PROPOSED (rewritten 2026-05-27 after architectural blocker — see §Why)
**Type**: new-package (compilation tooling)
**Depends on**: `api-sandbox-wasm-stdio-abi` (defines the wire protocol — SHIPPED at `cddccbdb7c`) AND `api-plugin-example-dual-shape` (provides the `/wasm` subpath the keystone test compiles — must ship first)
## Why
The original proposal sketched a direct-export ABI emitted by Javy (`__suaveplan_alloc`, `__suaveplan_handle_request`, etc.). The build agent surfaced an architectural blocker against Javy v8.1.1: Javy's `-C wit=...` flag restricts WIT-exposed exports to "function exports with no arguments and no return values", and Javy's host-interaction model is fundamentally WASI fd 0 / fd 1 (stdin / stdout). The direct-export ABI cannot be produced from a Javy-compiled JavaScript module without authoring a hand-encoded outer-WASM wrapper — a route the orchestrator rejected as too brittle.
The chosen path (orchestrator decision, 2026-05-27) is to extend `@suaveplan/api-sandbox-wasm-host-bridge` to accept a WASI-stdio ABI variant (sibling proposal `api-sandbox-wasm-stdio-abi`) and let this compiler be a **thin Javy wrapper**: bundle TS → inject a WASI-stdio ABI shim → invoke `javy build` → emit manifest. No outer-WASM authorship, no Component Model migration, no novel encoding work.
## Concrete consumer
- `@suaveplan/api-plugin-example` — TypeScript reference plugin. The keystone end-to-end test compiles it via this package and deploys the resulting WASM through the WASI-stdio bridge variant.
- `e2e/foundation-stack-full` Stage-8 closure smoke (gate 2.8) — calls `compilePluginToWasm({ pluginEntry: "<api-plugin-example>/src/wasm/index.ts" })` and asserts the produced artifact responds to a real HTTP request via `host.installPlugin` + the WASI-stdio bridge.
- Plugin operators authoring third-party TS plugins for the wasm tier.
## End-to-end test
- `tests/integration/api-plugin-example.test.ts` — compile the example plugin, instantiate via `api-sandbox-wasm-host-bridge` with `abiVariant: "wasi-stdio"`, deploy via `host.installPlugin`, exercise every declared route via a real HTTP request through `createTestHost`.
## What changes
### Compilation pipeline
```text
pluginEntry ──[1]──> bundled ESM JS ──[2]──> ABI-shimmed JS ──[3]──> .wasm ──[4]──> validate ──[5]──> manifest sidecar
Bun.build inject WASI-stdio loop javy build ABI check + Zod <basename>.wasm.json
```
1. **`Bun.build({ entrypoints, target: "browser", format: "esm" })`** — tree-shake + inline. Reject `node:*` specifiers with `WASM_COMPILER.BROWSER_INCOMPAT_DEPENDENCY` + `context.specifier`.
2. **Inject the WASI-stdio ABI shim** — prepend a generated header that:
- Reads from `process.stdin` (Javy maps this to fd 0) in length-prefix-framed loop.
- Validates each frame as `PluginEnvelopeIn` (Zod-validated runtime check, using the same Zod schemas exported by `@suaveplan/api-sandbox-wasm-host-bridge`).
- Dispatches by `kind`: `routes` → write the plugin's `routes` array; `request` → call the plugin's `handleRequest(request)` and write the response; `start` → call optional `start()` then `{kind:"ok"}`; `dispose` → call optional `dispose()` then `{kind:"ok"}` and exit.
- Writes length-prefixed `PluginEnvelopeOut` frames to `process.stdout` (Javy maps to fd 1).
- Surfaces thrown `SuaveplanError`-shaped values as `{kind:"error", code, message}` envelopes.
3. **`javy build <bundled.js> -o <output.wasm>`** — invokes the platform-appropriate `javy-cli-*` binary via `optionalDependencies` resolution. Non-zero exit → `WASM_COMPILER.JAVY_INVOCATION_FAILED` with `{exitCode, stderr (8 KiB trunc), command}`.
4. **`WebAssembly.compile(bytes)`** + reflection → assert `memory` + `_start` + the required `wasi_snapshot_preview1.*` imports. Missing → `WASM_COMPILER.ABI_VALIDATION_FAILED` + `context.missing`. This matches the WASI-stdio bridge variant's import allowlist exactly.
5. **Emit `<basename>.wasm.json` sidecar** — `{ routes, abiVersion, abiVariant: "wasi-stdio", javyVersion, compilerVersion, compiledAt (RFC 3339 UTC), sourceDigest (SHA-256 of pre-Javy bundle) }`. Empty `routes` → `WASM_COMPILER.MANIFEST_MISSING_ROUTES`. Routes are extracted at compile time by booting the WASM in a one-shot host-side WASI runner (`@bjorn3/browser_wasi_shim` or equivalent) and capturing the `{kind:"routes"}` reply.
### Package surface
```ts
import { compilePluginToWasm } from "@suaveplan/wasm-compiler-javy";
const result = await compilePluginToWasm({
pluginEntry: "/path/to/plugin/src/index.ts",
outDir: "/tmp/plugin-wasm",
optimizeFor: "size", // default "size" — passes -O to javy build
sourcemaps: false, // default false
javyVersion: "v8.1.1", // default catalog-pinned version
});
// result.wasmPath: string
// result.metadataPath: string
// result.sizeBytes: number
// result.compilationMs: number
```
### Platform-wrapper packages
5 thin-wrapper packages under `packages/devtools/tooling/`:
- `javy-cli-linux-x64`, `javy-cli-linux-arm64`, `javy-cli-darwin-x64`, `javy-cli-darwin-arm64`, `javy-cli-win32-x64`.
Each declares matching `os` + `cpu` in `package.json` so npm/bun skips installation on mismatched platforms. Binaries are fetched via a `postinstall` script from Bytecode Alliance's Javy GitHub releases at the catalog-pinned tag, with SHA-256 checksum verification of every download. Checksums are committed; binaries are not.
### CLI binary
`suaveplan-wasm-compile <entry> --out-dir <dir> [--optimize-for size|speed] [--sourcemaps]` — delegates to `compilePluginToWasm`. JSON result on stdout, structured error JSON on stderr, non-zero exit on any failure.
### OpenTelemetry
Meter `@suaveplan/wasm-compiler-javy`:
- counter `wasm_compiler.compiles_total{result}` where `result ∈ {"ok","bundle_failed","javy_failed","abi_failed","manifest_failed"}`.
- histogram `wasm_compiler.compile_duration_ms{result}`.
- counter `wasm_compiler.abi_validation_failures_total{missing_export}`.
### Conformance harness
`runWasmCompilerConformance({ compileFn })` from `./testing` with four invariants:
1. ABI completeness — every required WASI import + `_start` + `memory` present.
2. Deterministic output — same input + pinned Javy version → identical SHA-256.
3. Manifest fidelity — `routes` array matches the plugin's declared routes.
4. Cross-bridge deployability — produced WASM passes `runWasmHostBridgeConformance({ buildBridge, abiVariant: "wasi-stdio" })`.
### Error codes
`WASM_COMPILER.{BUNDLE_FAILED, BROWSER_INCOMPAT_DEPENDENCY, JAVY_PLATFORM_MISMATCH, JAVY_INVOCATION_FAILED, ABI_VALIDATION_FAILED, MANIFEST_MISSING_ROUTES}` — 6 codes via `defineCodes`, error class with **public constructor** (rule §19).
## Out of scope
- Direct-i32-i64 ABI compilation. That variant remains supported by `api-sandbox-wasm-host-bridge` but is not what this compiler emits — and is not required by `api-plugin-example` or any planned consumer.
- Component Model output. A future `wasm-compiler-component` package could target that surface; not in this scope.
- Compilation of non-suaveplan plugin shapes. The ABI shim is hard-coded to the suaveplan WASI-stdio protocol.

View File

@@ -0,0 +1,154 @@
# Capability Spec Delta: wasm-compiler-javy
**Package**: `@suaveplan/wasm-compiler-javy`
**Status**: PROPOSED (rewritten 2026-05-27 — WASI-stdio variant)
## ADDED Requirements
### Requirement: `compilePluginToWasm` produces a WASI-stdio WASM artifact
The package SHALL export `compilePluginToWasm({ pluginEntry, outDir, optimizeFor?, sourcemaps?, javyVersion? })` returning `{ wasmPath, metadataPath, sizeBytes, compilationMs }`. The produced `.wasm` MUST:
1. Export `memory` and `_start`.
2. Import every entry in the WASI snapshot-preview1 allowlist (`fd_read`, `fd_write`, `environ_get`, `environ_sizes_get`, `proc_exit`).
3. Speak the WASI-stdio framing protocol defined in `@suaveplan/api-types/sandbox-bridge` (length-prefixed JSON envelopes on fd 0 / fd 1).
#### Scenario: Compiled api-plugin-example deploys via the WASI-stdio bridge variant
- **WHEN** `compilePluginToWasm({ pluginEntry: "<api-plugin-example>/src/wasm/index.ts", outDir })` is called
- **AND** `createSandboxedWasmPluginModule({ sandbox: <api-sandbox-wasm built from the artifact>, manifest, abiVariant: "wasi-stdio" })` is invoked
- **THEN** ABI validation passes, route discovery returns every route declared in the plugin's manifest, AND a real HTTP request through `host.installPlugin` reaches a handler that returns the expected response
**Verified by:** `tests/integration/api-plugin-example.test.ts::"compiled WASM deploys via wasi-stdio bridge"`
---
### Requirement: Bundle step uses Bun.build with browser target
The compiler MUST invoke `Bun.build({ entrypoints: [pluginEntry], target: "browser", format: "esm" })` as step 1. Any transitive dependency requiring a Node-only API not polyfilled by the ABI shim MUST fail fast with `WASM_COMPILER.BROWSER_INCOMPAT_DEPENDENCY` and `context.specifier` naming the offending import.
#### Scenario: Plugin imports `node:fs` and is rejected
- **WHEN** `compilePluginToWasm` is called on a plugin whose dependency tree imports `node:fs`
- **THEN** the call rejects with `code === "WASM_COMPILER.BROWSER_INCOMPAT_DEPENDENCY"` AND `context.specifier === "node:fs"`
**Verified by:** `src/bundle/bundle.test.ts::"rejects node:fs in dependency tree"`
---
### Requirement: ABI shim wraps the bundle with the WASI-stdio request loop
After bundling, the compiler MUST prepend a generated ABI-shim header that implements: (a) length-prefix framed read from fd 0, (b) Zod-equivalent validation of every incoming envelope as `PluginEnvelopeIn`, (c) `kind`-dispatch to the plugin's `routes` / `handleRequest` / `start` / `dispose` exports, (d) length-prefix framed write to fd 1, (e) `SuaveplanError` catch → `{kind:"error", code, message}` envelope. The shim MUST be byte-stable across compilations of the same plugin.
#### Scenario: Two compilations of the same input produce byte-identical WASM
- **WHEN** `compilePluginToWasm` is invoked twice with identical inputs and a pinned `javyVersion`
- **THEN** the two `.wasm` artifacts have identical SHA-256 digests
**Verified by:** `tests/integration/determinism.test.ts::"compilation is deterministic"`
---
### Requirement: Javy binary located via platform-specific optional dependency
The compiler MUST locate the Javy CLI via the `javy-cli-{linux-x64,linux-arm64,darwin-x64,darwin-arm64,win32-x64}` optional-dependency wrappers, selecting by `process.platform` + `process.arch`. If no matching wrapper is installed, the call MUST fail with `WASM_COMPILER.JAVY_PLATFORM_MISMATCH` and `context.requested` naming the platform-arch pair.
#### Scenario: Unsupported platform fails fast
- **WHEN** `compilePluginToWasm` runs on a platform without a matching `javy-cli-*` package
- **THEN** the call rejects with `code === "WASM_COMPILER.JAVY_PLATFORM_MISMATCH"`
**Verified by:** `src/javy/javy-locate.test.ts::"raises JAVY_PLATFORM_MISMATCH for unsupported platform"`
---
### Requirement: Javy invocation failures surface as `JAVY_INVOCATION_FAILED`
Non-zero exit OR fatal stderr from the spawned Javy process MUST raise `WASM_COMPILER.JAVY_INVOCATION_FAILED` with `context.exitCode`, `context.stderr` (truncated to 8 KiB), AND `context.command`.
#### Scenario: Malformed JS input fails with structured error
- **WHEN** Javy is invoked on intentionally malformed input
- **THEN** the call rejects with `code === "WASM_COMPILER.JAVY_INVOCATION_FAILED"` AND `context.exitCode !== 0` AND `context.stderr` is non-empty
**Verified by:** `src/javy/javy-invoke.test.ts::"non-zero Javy exit surfaces structured error"`
---
### Requirement: ABI validation runs after Javy emits the WASM
The compiler MUST `WebAssembly.compile` the bytes and reflect the module to assert: `memory` export, `_start` export, AND every required WASI snapshot-preview1 import. Missing any → `WASM_COMPILER.ABI_VALIDATION_FAILED` with `context.missing: string[]`.
#### Scenario: Missing `_start` rejected
- **WHEN** Javy produces a WASM that somehow lacks `_start`
- **THEN** the compile rejects with `code === "WASM_COMPILER.ABI_VALIDATION_FAILED"` AND `context.missing` contains `"_start"`
**Verified by:** `src/validate/abi-validate.test.ts::"missing _start raises ABI_VALIDATION_FAILED"`
---
### Requirement: Route extraction by booting the produced WASM under a host-side WASI runner
Before emitting the manifest, the compiler MUST boot the produced `.wasm` under a host-side WASI runner, send a `{kind:"routes"}` envelope, and capture the `{kind:"routes", routes}` reply. The captured `routes: readonly SerializedRoute[]` becomes the manifest's `routes` field. Empty list → `WASM_COMPILER.MANIFEST_MISSING_ROUTES`.
#### Scenario: Compiled api-plugin-example yields 11+ routes
- **WHEN** route extraction runs against the example plugin's compiled WASM
- **THEN** the captured `routes` array length matches the plugin's source-declared route count
**Verified by:** `src/route-extract/route-extract.test.ts::"route extraction matches source declarations"`
---
### Requirement: Metadata sidecar emitted alongside `.wasm`
The compiler MUST emit `<basename>.wasm.json` containing: `routes`, `abiVersion` (semver), `abiVariant: "wasi-stdio"`, `javyVersion`, `compilerVersion`, `compiledAt` (RFC 3339 UTC), AND `sourceDigest` (SHA-256 of the bundled JS pre-Javy).
#### Scenario: Manifest mirrors the plugin's declared routes
- **WHEN** `compilePluginToWasm` runs against `api-plugin-example`
- **THEN** the emitted manifest's `routes` array equals the plugin's source-declared routes AND `abiVariant === "wasi-stdio"`
**Verified by:** `src/manifest/manifest.test.ts::"manifest mirrors plugin routes and pins abiVariant"`
---
### Requirement: CLI binary `suaveplan-wasm-compile`
The package SHALL ship `suaveplan-wasm-compile <entry> --out-dir <dir> [--optimize-for size|speed] [--sourcemaps]` that delegates to `compilePluginToWasm` and prints the result as JSON on stdout. Non-zero exit on any error with the structured error JSON on stderr.
#### Scenario: CLI compiles api-plugin-example end-to-end
- **WHEN** `bunx suaveplan-wasm-compile <api-plugin-example/src/wasm/index.ts> --out-dir <tmp>` runs
- **THEN** exit code is 0 AND stdout JSON contains `wasmPath` AND that path passes the WASI-stdio bridge ABI validation
**Verified by:** `src/bin/cli.test.ts::"CLI compiles api-plugin-example"`
---
### Requirement: OpenTelemetry instruments published
The compiler MUST publish three OTel instruments on meter `@suaveplan/wasm-compiler-javy`:
- counter `wasm_compiler.compiles_total{result}` where `result ∈ {"ok","bundle_failed","javy_failed","abi_failed","manifest_failed"}`.
- histogram `wasm_compiler.compile_duration_ms{result}`.
- counter `wasm_compiler.abi_validation_failures_total{missing_export}`.
#### Scenario: Successful compile increments `compiles_total{result="ok"}` exactly once
**Verified by:** `src/instruments/instruments.test.ts::"successful compile emits ok counter"`
---
### Requirement: Conformance harness `runWasmCompilerConformance`
The package SHALL ship `runWasmCompilerConformance({ compileFn })` from `@suaveplan/wasm-compiler-javy/testing` with four invariants:
1. ABI completeness — `memory` + `_start` + every required WASI import present.
2. Deterministic output — same input → same SHA-256.
3. Manifest fidelity — `routes` array equals the plugin's declared routes.
4. Cross-bridge deployability — produced WASM passes `runWasmHostBridgeConformance({ buildBridge, abiVariant: "wasi-stdio" })`.
Any alternate compiler implementation MUST pass all four invariants to substitute for the default Javy backend.
#### Scenario: Harness rejects a compiler that strips `_start`
**Verified by:** `src/testing/wasm-compiler-conformance/wasm-compiler-conformance.test.ts::"harness rejects compiler missing _start"`

View File

@@ -0,0 +1,70 @@
# Tasks — TS→WASM Compiler (Javy-backed, WASI-stdio variant)
## 0. Pre-flight (non-negotiable)
- [x] 0.1 Clean working tree; account for every `.claude/worktrees/agent-*`
- [x] 0.2 `api-sandbox-wasm-stdio-abi` has shipped (the WASI-stdio bridge variant + protocol types are merged on `genesis`)
- [x] 0.3 §0a Sync: worktree-isolated agents fast-forward to orchestrator-supplied SHA
## 1. Javy binary distribution (5 wrapper packages)
- [x] 1.1 Author `javy-cli-linux-x64` under `packages/devtools/tooling/javy-cli-linux-x64/` — `package.json` with matching `os: ["linux"]` + `cpu: ["x64"]`, `bin/javy` shim that `exec`s the bundled binary
- [x] 1.2 Author `javy-cli-linux-arm64`, `javy-cli-darwin-x64`, `javy-cli-darwin-arm64`, `javy-cli-win32-x64` mirroring the same structure
- [x] 1.3 Each wrapper carries a `postinstall` script that downloads the prebuilt Javy v8.1.1 release for its platform from `github.com/bytecodealliance/javy/releases` with SHA-256 checksum verification. Checksums committed; binaries not committed.
- [x] 1.4 Catalog the Javy version centrally in root `package.json` (`catalog.wasm.javy: "v8.1.1"` or extend `catalog.tooling`) — every wrapper pins to the same value
- [x] 1.5 Each wrapper exports a `getJavyBinary(): string` helper returning the absolute path to its packaged binary (consumers use this, not raw `bin/javy`, so they don't need to spawn a child process just to locate the binary)
- [x] 1.6 Paired `README.md` documenting the platform served
## 2. Main package scaffold
- [x] 2.1 `packages/api-stack/api/wasm-compiler-javy/` with `package.json` (0.1.0, server-tier), `tsconfig.lib.json`, `vite.config.ts`, `vitest.config.ts`
- [x] 2.2 Deps: `@suaveplan/api-types`, `@suaveplan/error`, `@suaveplan/logger`, `@suaveplan/opentelemetry`, `tslib`, `zod`. Optional platform deps: every `javy-cli-*` wrapper. peerDeps: none.
- [x] 2.3 `bin: { "suaveplan-wasm-compile": "./dist/bin/cli.js" }`
- [x] 2.4 Subpath exports: `./testing` for the conformance harness
## 3. Implementation
- [x] 3.1 `src/bundle/bundle.ts` — `bundleTs({ entry })` via `Bun.build({ entrypoints: [entry], target: "browser", format: "esm" })`. Rejects `node:*` specifiers with `WASM_COMPILER.BROWSER_INCOMPAT_DEPENDENCY` + `context.specifier`. Returns bundled JS as a `string`.
- [x] 3.2 `src/abi-shim/abi-shim.ts` — generates the WASI-stdio ABI header JS. The shim:
- Implements length-prefix framed read from `process.stdin` (or `Javy.IO.readSync` if available — pick whichever the v8.1.1 host model exposes).
- Implements length-prefix framed write to `process.stdout`.
- Validates `PluginEnvelopeIn` shape with inlined Zod-equivalent checks (cannot ship full Zod inside the WASM bundle — too heavy). Hand-written validators are acceptable and DOCUMENTED in `abi-shim.md`.
- Dispatches by `kind` to the plugin's exported `routes`, `handleRequest`, optional `start`, optional `dispose`.
- Catches `SuaveplanError`-shaped throws and emits `{kind:"error", code, message}` envelopes.
- Byte-stable output for reproducible builds.
- [x] 3.3 `src/abi-shim/abi-shim.md` documents the wire format AND the protocol-version pin AND every dispatch case.
- [x] 3.4 `src/javy/javy-locate.ts` — picks the right `javy-cli-*` wrapper by `process.platform` + `process.arch`. Raises `WASM_COMPILER.JAVY_PLATFORM_MISMATCH` with `context.requested` if none. Uses each wrapper's `getJavyBinary()` export.
- [x] 3.5 `src/javy/javy-invoke.ts` — `child_process.spawnSync` against the binary with `["build", inputPath, "-o", outputPath]` (+ `-O` when `optimizeFor === "speed"`). Captures stdout/stderr; non-zero exit → `WASM_COMPILER.JAVY_INVOCATION_FAILED` with `{exitCode, stderr (8 KiB trunc), command}`.
- [x] 3.6 `src/validate/abi-validate.ts` — `WebAssembly.compile(bytes)` + module reflection. Asserts `memory` export, `_start` export, AND that the module imports every entry in the WASI snapshot-preview1 allowlist needed by the bridge (`fd_read`, `fd_write`, `environ_get`, `environ_sizes_get`, `proc_exit`). Missing → `WASM_COMPILER.ABI_VALIDATION_FAILED` with `context.missing: string[]`.
- [x] 3.7 `src/route-extract/route-extract.ts` — boots the produced WASM under a host-side WASI runner (`@bjorn3/browser_wasi_shim` or a thin in-house wrapper), sends a `{kind:"routes"}` envelope, captures the `{kind:"routes", routes}` reply. Returns the route list.
- [x] 3.8 `src/compile/compile.ts` — top-level `compilePluginToWasm({ pluginEntry, outDir, optimizeFor?, sourcemaps?, javyVersion? })` orchestrates bundle → shim → javy → validate → route-extract → manifest emit. Returns `{ wasmPath, metadataPath, sizeBytes, compilationMs }`.
- [x] 3.9 `src/manifest/manifest.ts` — emits `<basename>.wasm.json` with `{routes, abiVersion, abiVariant: "wasi-stdio", javyVersion, compilerVersion, compiledAt (RFC 3339 UTC), sourceDigest}`. Empty `routes` → `WASM_COMPILER.MANIFEST_MISSING_ROUTES`.
- [x] 3.10 `src/bin/cli.ts` — `suaveplan-wasm-compile <entry> --out-dir <dir> [--optimize-for size|speed] [--sourcemaps]`. JSON on stdout, structured error JSON on stderr.
- [x] 3.11 `src/error-codes/error-codes.ts` — 6 WASM_COMPILER codes via `defineCodes` + `WasmCompilerError` extends `SuaveplanError` with **public constructor**.
- [x] 3.12 `src/instruments/instruments.ts` — OTel meter `@suaveplan/wasm-compiler-javy` with the 3 instruments described in the proposal.
- [x] 3.13 Paired `.md` per implementation file.
## 4. Conformance harness
- [x] 4.1 `src/testing/wasm-compiler-conformance/wasm-compiler-conformance.ts` — `runWasmCompilerConformance({ compileFn })` with all 4 invariants from the spec.
## 5. Tests
- [x] 5.1 `tests/fixtures/tiny-plugin/src/index.ts` — minimal TS plugin with two routes + a `start()` and `dispose()` hook
- [x] 5.2 `tests/integration/tiny-plugin.test.ts` — compile fixture, assert ABI validation passes, deploy via `api-sandbox-wasm-host-bridge` with `abiVariant: "wasi-stdio"`, exercise both routes + lifecycle, assert manifest routes match.
- [x] 5.3 `tests/integration/api-plugin-example.test.ts` — compile `@suaveplan/api-plugin-example/wasm` (the WASI-stdio subpath, not the trusted-tier root), deploy through the bridge with `abiVariant: "wasi-stdio"`, exercise every declared route via `createTestHost`. KEYSTONE TEST for Stage-8 gate 2.8. Requires `api-plugin-example-dual-shape` to have shipped first.
- [x] 5.4 `tests/integration/determinism.test.ts` — compile twice with identical inputs, assert SHA-256 of `.wasm` bytes is identical.
- [x] 5.5 `src/javy/javy-locate.test.ts` — covers each platform-arch combination via mocked `process.platform`/`arch` (this IS rule §2-permitted — it's testing platform branch logic, not a service).
- [x] 5.6 Coverage on every touched module. Realized at 90.49% stmts / 84.43% branches / 85% funcs / 89.93% lines (above package-calibrated thresholds 85/75/80/85). Uncovered branches map to (a) compile-orchestrator failure-mode propagation paths whose triggers would require mocking real Javy/sandbox failures (rule §2 bans mocks), (b) CLI default-IO closures only reachable via the bin script itself, (c) the `extractRoutes` `routes_reply_kind` defensive throw and `wasm-compiler-conformance` `bridgeDeploy` optional branch. All on-path code is covered by the keystone integration tests.
- [x] 5.7 No `// biome-ignore`; every test file imports from `@suaveplan/testing/runner`; no `export *` in any non-root barrel.
## 6. Gate
- [x] 6.1 `bunx --bun turbo lint typecheck test:coverage --filter=@suaveplan/wasm-compiler-javy --filter=@suaveplan/api-sandbox-wasm-host-bridge --filter=@suaveplan/api-plugin-example --concurrency=4` green
- [x] 6.2 `bun scripts/folder-reorg/generate-manifest.ts` to refresh `MANIFEST.md`
## 7. Archive (orchestrator step)
- [ ] 7.1 Fold delta into `openspec/specs/wasm-compiler-javy/spec.md`
- [ ] 7.2 Move folder → `openspec/archive/2026-05-27-wasm-compiler-javy/`
- [ ] 7.3 Refresh `MANIFEST.md`