7.8 KiB
7.8 KiB
Tasks — TS→WASM Compiler (Javy-backed, WASI-stdio variant)
0. Pre-flight (non-negotiable)
- 0.1 Clean working tree; account for every
.claude/worktrees/agent-* - 0.2
api-sandbox-wasm-stdio-abihas shipped (the WASI-stdio bridge variant + protocol types are merged ongenesis) - 0.3 §0a Sync: worktree-isolated agents fast-forward to orchestrator-supplied SHA
1. Javy binary distribution (5 wrapper packages)
- 1.1 Author
javy-cli-linux-x64underpackages/devtools/tooling/javy-cli-linux-x64/—package.jsonwith matchingos: ["linux"]+cpu: ["x64"],bin/javyshim thatexecs the bundled binary - 1.2 Author
javy-cli-linux-arm64,javy-cli-darwin-x64,javy-cli-darwin-arm64,javy-cli-win32-x64mirroring the same structure - 1.3 Each wrapper carries a
postinstallscript that downloads the prebuilt Javy v8.1.1 release for its platform fromgithub.com/bytecodealliance/javy/releaseswith SHA-256 checksum verification. Checksums committed; binaries not committed. - 1.4 Catalog the Javy version centrally in root
package.json(catalog.wasm.javy: "v8.1.1"or extendcatalog.tooling) — every wrapper pins to the same value - 1.5 Each wrapper exports a
getJavyBinary(): stringhelper returning the absolute path to its packaged binary (consumers use this, not rawbin/javy, so they don't need to spawn a child process just to locate the binary) - 1.6 Paired
README.mddocumenting the platform served
2. Main package scaffold
- 2.1
packages/api-stack/api/wasm-compiler-javy/withpackage.json(0.1.0, server-tier),tsconfig.lib.json,vite.config.ts,vitest.config.ts - 2.2 Deps:
@suaveplan/api-types,@suaveplan/error,@suaveplan/logger,@suaveplan/opentelemetry,tslib,zod. Optional platform deps: everyjavy-cli-*wrapper. peerDeps: none. - 2.3
bin: { "suaveplan-wasm-compile": "./dist/bin/cli.js" } - 2.4 Subpath exports:
./testingfor the conformance harness
3. Implementation
- 3.1
src/bundle/bundle.ts—bundleTs({ entry })viaBun.build({ entrypoints: [entry], target: "browser", format: "esm" }). Rejectsnode:*specifiers withWASM_COMPILER.BROWSER_INCOMPAT_DEPENDENCY+context.specifier. Returns bundled JS as astring. - 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(orJavy.IO.readSyncif available — pick whichever the v8.1.1 host model exposes). - Implements length-prefix framed write to
process.stdout. - Validates
PluginEnvelopeInshape with inlined Zod-equivalent checks (cannot ship full Zod inside the WASM bundle — too heavy). Hand-written validators are acceptable and DOCUMENTED inabi-shim.md. - Dispatches by
kindto the plugin's exportedroutes,handleRequest, optionalstart, optionaldispose. - Catches
SuaveplanError-shaped throws and emits{kind:"error", code, message}envelopes. - Byte-stable output for reproducible builds.
- Implements length-prefix framed read from
- 3.3
src/abi-shim/abi-shim.mddocuments the wire format AND the protocol-version pin AND every dispatch case. - 3.4
src/javy/javy-locate.ts— picks the rightjavy-cli-*wrapper byprocess.platform+process.arch. RaisesWASM_COMPILER.JAVY_PLATFORM_MISMATCHwithcontext.requestedif none. Uses each wrapper'sgetJavyBinary()export. - 3.5
src/javy/javy-invoke.ts—child_process.spawnSyncagainst the binary with["build", inputPath, "-o", outputPath](+-OwhenoptimizeFor === "speed"). Captures stdout/stderr; non-zero exit →WASM_COMPILER.JAVY_INVOCATION_FAILEDwith{exitCode, stderr (8 KiB trunc), command}. - 3.6
src/validate/abi-validate.ts—WebAssembly.compile(bytes)+ module reflection. Assertsmemoryexport,_startexport, 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_FAILEDwithcontext.missing: string[]. - 3.7
src/route-extract/route-extract.ts— boots the produced WASM under a host-side WASI runner (@bjorn3/browser_wasi_shimor a thin in-house wrapper), sends a{kind:"routes"}envelope, captures the{kind:"routes", routes}reply. Returns the route list. - 3.8
src/compile/compile.ts— top-levelcompilePluginToWasm({ pluginEntry, outDir, optimizeFor?, sourcemaps?, javyVersion? })orchestrates bundle → shim → javy → validate → route-extract → manifest emit. Returns{ wasmPath, metadataPath, sizeBytes, compilationMs }. - 3.9
src/manifest/manifest.ts— emits<basename>.wasm.jsonwith{routes, abiVersion, abiVariant: "wasi-stdio", javyVersion, compilerVersion, compiledAt (RFC 3339 UTC), sourceDigest}. Emptyroutes→WASM_COMPILER.MANIFEST_MISSING_ROUTES. - 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. - 3.11
src/error-codes/error-codes.ts— 6 WASM_COMPILER codes viadefineCodes+WasmCompilerErrorextendsSuaveplanErrorwith public constructor. - 3.12
src/instruments/instruments.ts— OTel meter@suaveplan/wasm-compiler-javywith the 3 instruments described in the proposal. - 3.13 Paired
.mdper implementation file.
4. Conformance harness
- 4.1
src/testing/wasm-compiler-conformance/wasm-compiler-conformance.ts—runWasmCompilerConformance({ compileFn })with all 4 invariants from the spec.
5. Tests
- 5.1
tests/fixtures/tiny-plugin/src/index.ts— minimal TS plugin with two routes + astart()anddispose()hook - 5.2
tests/integration/tiny-plugin.test.ts— compile fixture, assert ABI validation passes, deploy viaapi-sandbox-wasm-host-bridgewithabiVariant: "wasi-stdio", exercise both routes + lifecycle, assert manifest routes match. - 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 withabiVariant: "wasi-stdio", exercise every declared route viacreateTestHost. KEYSTONE TEST for Stage-8 gate 2.8. Requiresapi-plugin-example-dual-shapeto have shipped first. - 5.4
tests/integration/determinism.test.ts— compile twice with identical inputs, assert SHA-256 of.wasmbytes is identical. - 5.5
src/javy/javy-locate.test.ts— covers each platform-arch combination via mockedprocess.platform/arch(this IS rule §2-permitted — it's testing platform branch logic, not a service). - 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
extractRoutesroutes_reply_kinddefensive throw andwasm-compiler-conformancebridgeDeployoptional branch. All on-path code is covered by the keystone integration tests. - 5.7 No
// biome-ignore; every test file imports from@suaveplan/testing/runner; noexport *in any non-root barrel.
6. Gate
- 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=4green - 6.2
bun scripts/folder-reorg/generate-manifest.tsto refreshMANIFEST.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