Complete wasm-embedded-inference spike with wazero integration - #164
Conversation
Compile the plan-64 pure-Go classifier to a wasip1 reactor module (-buildmode=c-shared) and host it via wazero v1.11.0. Guest exports alloc/free/classify; host initializes, writes input into guest linear memory, reads a JSON result back. Measured against the plan-64 and plan-63 (yzma) spikes on the same six-sample corpus. Captured on Linux amd64, Go 1.25.8, ROUNDS=4000: - determinism: 1 unique hash across 5 in-process + 5 cross-process runs (digest 7a1dc22...) - avg latency 2,022 us (p50 1,952 us, p95 2,464 us); ~600x go-native, ~25x faster than yzma - RSS post-bench 109 MB; guest cold-compile 1,699 ms - binary-size delta +4,174,718 B (wasm 3,993,759 B + wazero 181 KB) Recommendation: reject for the current classifier size. The pure-Go classifier (plan 64) already ships the same deterministic output in 480 B, 3 us avg latency, and 7.8 MB RSS; wasm adds no capability the Go path lacks. Reopen this path only if a future classifier is not practically authorable in pure Go or requires the wazero sandbox. Mark plan 65 complete. https://claude.ai/code/session_01FJ96zwAGrCK76WKt1szp1F
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #164 +/- ##
=======================================
Coverage 88.03% 88.03%
=======================================
Files 110 110
Lines 14106 14106
=======================================
Hits 12418 12418
Misses 1228 1228
Partials 460 460 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
There was a problem hiding this comment.
Pull request overview
Completes plan 65’s WASM-embedded inference spike by adding a WASI/wasip1 guest module, a wazero-based host benchmark harness, build automation, and documentation of performance/determinism/size findings (with a recommendation to reject WASM for this use case).
Changes:
- Added a WASM guest (wasip1) exposing
alloc,free, andclassify, plus a host harness that embeds and executes the artifact via wazero for determinism/latency/memory measurement. - Added a build+benchmark script and build-tag-gated linker hooks to measure mdsmith binary-size deltas when force-linking wazero + the embedded wasm artifact.
- Updated spike documentation and plan status to record results and mark the plan complete.
Reviewed changes
Copilot reviewed 9 out of 11 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| plan/65_spike-wasm-embedded-inference.md | Marks tasks/acceptance criteria complete and links to spike findings. |
| internal/rules/concisenessscoring/wasmclassifier/embed.go | Build-tag-gated embed + force-link package for artifact + wazero/WASI size measurement. |
| cmd/mdsmith/spike_wasm_classifier.go | Build-tag-gated init hook to keep embedded wasm reachable for binary-size delta measurement. |
| docs/research/conciseness/spikes/wasm-embedded-inference/wasm/main.go | WASM guest implementation exporting alloc/free/classify over linear memory. |
| docs/research/conciseness/spikes/wasm-embedded-inference/main.go | Host harness that embeds the wasm artifact, instantiates via wazero, and benchmarks/digests outputs. |
| docs/research/conciseness/spikes/wasm-embedded-inference/run.sh | Automation to build the guest, run determinism/bench, and measure mdsmith size delta. |
| docs/research/conciseness/spikes/wasm-embedded-inference/README.md | Documents methodology, metrics, and recommendation to reject WASM path. |
| go.mod / go.sum | Adds wazero dependency for the spike artifacts/size measurement path. |
| PLAN.md | Updates plan table to show plan 65 complete. |
| .gitignore | Ignores generated wasm artifact copies and the .tmp/ output directory used by the spike. |
Address Copilot review comments on PR #164: - Guest classify(): return 0 when length>0 but ptr==0 so a bad host call cannot hit unsafe.Slice on a null pointer in wasm linear memory. - Guest classify(): check encoded JSON length before copying into the static 4 KB outputBuf. On overflow, return -1 so the host can raise rather than silently decoding a truncated buffer. - Host Classify(): skip alloc/free and memory.Write when the input is empty; call classify(0, 0) directly. Matches the guest's length==0 fast path. - Host Classify(): detect the guest's new negative sentinel and return a "guest signaled output truncation" error. Rebench confirms determinism digest is unchanged (7a1dc22...) and all per-sample risk scores are identical. Binary delta shifts by 24 bytes (new guard code). No change to the spike's conclusions. https://claude.ai/code/session_014iGcShL7oVcZVoYk4JSPpq
|
🟢 Merge Queue — picked up This PR is in the queue and will be batched with other Next: No action needed — you'll get another comment when CI starts on the batch. View merge queue run. |
|
🔵 Merge Queue — CI running Merged into batch branch Next: No action needed — you'll be notified when CI completes. |
|
✅ Merge Queue — merged This PR landed on Next: Done — nothing more to do here. |
Summary
This PR completes the WASM-embedded-inference spike (plan 65), implementing a proof-of-concept that embeds a WebAssembly classifier artifact using
go:embedand hosts it with the wazero runtime. The spike evaluates whether WASM can provide a viable inference path for mdsmith with no runtime dynamic library dependencies.Key Changes
WASM guest implementation (
wasm/main.go): A minimal WASI reactor module that reuses the plan-64 linear classifier package verbatim, exposing three wasmexport functions (alloc,free,classify) for host-guest communication via linear memory.Host harness (
main.go): A comprehensive benchmark and determinism-verification tool that:go:embedBuild infrastructure (
run.sh): Automated script that:GOOS=wasip1 GOARCH=wasm -buildmode=c-sharedspike_wasm_classifiertagbench.txtandsize.txtSize-measurement hooks (
internal/rules/concisenessscoring/wasmclassifier/embed.go,cmd/mdsmith/spike_wasm_classifier.go): Build-tag-gated stubs that force-link the embedded wasm artifact and wazero runtime so binary-size impact can be measured in isolation.Comprehensive documentation (updated
README.md): Detailed findings including:Plan status update (
plan/65_spike-wasm-embedded-inference.md): Marked complete with all acceptance criteria met.Notable Implementation Details
Module loading strategy: One module instance is reused for all calls; re-instantiating per call would incur the ~1.7 s wazero compile cost repeatedly. The host calls
_initializeexplicitly after instantiation (reactor-module semantics).Memory safety: Host-guest communication uses linear memory with explicit
alloc/freecalls. The guest returns a packed int64(outPtr<<32)|outLenpointing to a static 4 KB output buffer containing JSON results.Determinism: Outputs are byte-for-byte identical across in-process repeats and process restarts, with SHA256 digest pinning recommended for integrity checks.
Fallback boundaries: Documented recommended guards (compile-time build tag, runtime instantiation with fallback to heuristic on error, per-call timeout wrapper, verbose diagnostics).
Artifact update workflow: Safe path defined with SHA256 pinning, version tracking, and determinism validation before shipping.
Rationale for Rejection
The spike conclusively demonstrates that while wasm provides deterministic, sandboxed execution with no external dynamic
https://claude.ai/code/session_014iGcShL7oVcZVoYk4JSPpq