TL;DR: bun-sticky now embeds the Mk4 WASM engine โ the same Rust compiler that powers faf-cli, mcpaas.live, and builder.faf.one. One kernel interface. Rust today, Zig Cascade tomorrow. All engines produce identical scores. 284 microseconds per score.
The Problem
Four scoring engines. Same algorithm. Four implementations. Score divergence. A CLI tool scores 100% locally but 43% through WASM because the engines disagree on what counts.
The root cause: type-aware scoring lived in TypeScript. The WASM engine scored flat โ all 21 slots, always. A CLI project could never hit 100% through WASM because frontend slots dragged it down.
The Fix
Data-Driven Slotignore
The .faf file carries the truth. If your project doesn't use frontend slots, they're marked slotignored in the file itself โ not inferred at score time by TypeScript.
# CLI project โ non-applicable slots marked in the file
stack:
frontend: slotignored
css_framework: slotignored
ui_library: slotignored
state_management: slotignored
runtime: Bun
build: bun build Every engine reads the same file. Every engine skips the same slots. Every engine gets the same score.
The WASM doesn't care about types.
It counts. Populated, empty, slotignored. Fast.
faf-wasm-core โ The Kernel Router
faf-wasm-core is not a rewrite. It's a router. It wraps faf-wasm-sdk (the published, blogged, "compiler is the spec" WASM) behind a FafKernel interface. When Zig Cascade ships, it slots in โ same interface, no consumer changes.
import { init } from "faf-wasm-core";
const kernel = await init("rust"); // or "zig" when Cascade ships
const result = kernel.score(yaml); // Same interface. Any engine.
// result.score = 100
// result.populated = 11
// result.ignored = 10
// result.active = 11bun-sticky v2.0.0
Three new commands. Same zero dependencies.
bunx bun-sticky wasm-scoreScore via the Mk4 WASM kernel. Shows populated/active slots, powered-by line.
bunx bun-sticky benchBenchmark: 100 scores, average time per score. 284 microseconds on a 2017 iMac.
bunx bun-sticky badgeGet your mcpaas.live badge markdown. Drop it in your README.
init writes slotignored
bunx bun-sticky init my-cli now writes proper slotignored values for non-applicable slots based on project type. CLI projects get frontend/backend slots marked. Fullstack gets all 21 active. The file carries the scoring truth from birth.
Parity Proof
=== TS ===
๐ 100% Trophy
Filled: 11/11 slots
=== WASM ===
๐ 100% Trophy
Filled: 11/11 slots Same file. Same count. Same score. Same tier. Two engines, one truth.
WASM Roundup
The FAF WASM stack, top to bottom:
| Package | What | Size |
|---|---|---|
| faf-wasm-sdk | RustโWASM compiler (the engine) | 322KB |
| faf-wasm-core | Kernel router (wraps sdk, FafKernel interface) | 155KB npm |
| bun-sticky | Bun CLI (embeds core) | 185KB npm |
| xai-faf-zig | Zig ghost (scorer only, Cascade future) | 2.7KB |
sdk is the compiler. core wraps it behind an interface. bun-sticky embeds core. builder.faf.one runs both Rust and Zig WASM in the browser.
The Numbers
- faf-wasm-core v1.0.0 โ 36 tests passing
- bun-sticky v2.0.0 โ 369 tests passing
- 405 total โ across 2 packages, 0 failures
- 284ฮผs โ average WASM score (Mk4, Rust)
- 322KB โ embedded WASM binary
- 0 dependencies โ still zero