README · Get started · Migration · Security · Performance · CFG/SSA hardening
Status markers: ✅ Done · ◐ Partial · ⬜ Not started · ⛔ Release blocker. Priority principle: security correctness > semantic correctness > real-world evidence > DX > performance > benchmark scores.
Last updated 2026-09-02.
The 2026-08-22 top-10 priorities are all done:
- ✅
docs/security.md+ threat model established (component trust boundaries, object taxonomy, Proxy/Symbol/SAB/Atomics/Intl policies) - ✅ Audit findings 1–4 fixed; skipped security tests activated and permanent regressions added
- ✅ Two compiler bugs fixed: the
$v1_30cross-block inline-guard reference (region-stack visibility checks) and the giant-literal scalability bug (four sub-issues: SCCP O(V²), frontend table dedup O(n²), O2 const-scope chunking, constant array-literal folding) — Kraken imaging restored, 14/14 - ✅ Differential fuzzing:
test/differential/fuzz.js(generator + three-engine comparison + failure saving + ddmin), 16,000 cases with zero mismatches - ✅ NavierStokes / Crypto sandbox-tax profile:
createInstance({ profileBoundary: true })counters +--profile-boundarydriver; five-suite table in Performance - ✅ Sandbox-tax statistics automated in
benchmark/release.js(sandboxTaxJSON + table) - ✅ Real-world workloads: 8 ES5.1 workloads + four-backend driver (sandbox/trusted/quickjs/native) with cross-backend result verification
- ✅ Worker helper:
sablejs/worker(createSandboxClient/handleSandboxMessages, timeouts, termination, message validation) + Worker isolation - ✅ README positioning (versus eval/iframe/QuickJS, ES5.1 core strategy)
- ✅ ES5.1 strategy documented (README + Security)
- Security: a full boundary audit (Security, Historical audit record) found no usable escape; the zero-skipped adversarial regression battery lives in
test/unit/security.test.js, now including the boundary-internals sweep, the clone-shape sweep (P0-S1–S4), the provenance-v2 write fast-path pins, the arity-specialized dispatch pins, and the object-literal folding pins. Vulnerability disclosure is defined in the repositorySECURITY.md. - Performance: the historical V8 Benchmark Suite 7 measurements are sandbox 2,202 and trusted 2,783 (three-run medians, Performance). The 2026-08-23/24 optimization batch (items 1–19, fully recorded in the Optimization history) shipped guest-provenance v2, arity-specialized call/NEW dispatch, literal folding, local promotion, slot-provenance write stamps, the inline guest-stamp write path, the literal-init fast path and its inlined/deep-folded successors, the sandbox-only host-intrinsic call inlines, frame-stack sync simplification, and branch-test round-trip elimination; item 16 measured flat and was rolled back. Cumulative Octane A/B vs the pre-items HEAD: +37% geomean across 8 suites (Splay 2.25×, EarleyBoyer 2.14×, RayTrace 1.67×, NavierStokes 1.48×; Richards −12% unattributable). These figures describe the then-current corpus and harness, not O2 production readiness or CFG/SSA-only gains. Held-out, dynamic-input, lifecycle-symmetric revalidation is tracked in the CFG/SSA hardening plan. Measurement protocol: all in-session A/Bs are pinned to one core (
taskset -c 11) — the machine runs other projects' benchmark jobs, so unpinned numbers are unreliable. - Semantics: the pinned Test262 gate passes 14,293/14,293 variants with zero host failures, but the 2026-09-01 optimizer audit found two deterministic P0 wrong-code cases outside that coverage. DSE now converges with a reverse worklist and fails closed on a diagnostic budget. Completion-aware CFG plus independent reuse verification fix the GVN defect in its supported private-local domain; real catch/with/eval and protected LICM/DSE/provenance retain safe bailouts. The implicit default is now O1. The remaining semantic proofs and validation gates still block O2/Os production approval; details are in the CFG/SSA hardening plan.
- Debuggability: opt-in Source Map v3 output is implemented for all optimization levels, including inline/external maps, Node and browser integration evidence, and virtual sources for static
eval/Functionbodies.
- ⛔ CFG/SSA correctness hardening — containment, convergent DSE, completion-aware CFG, and independent GVN reuse proofs are implemented; next complete the remaining annotation proofs, directed corpus, and held-out evidence. See the implementation plan.
- ◐ Facet fuzzing — semantics and sandbox-boundary facets plus generated-code syntax validation are in CI; parser/capability-serializer expansion and a nightly campaign remain.
- ⬜ Benchmark methodology and reporting — make backend lifecycles symmetric, fail on skips/errors, separate static from dynamic input, freeze a held-out corpus, generate the performance markdown, and archive benchmark JSON with environment info.
- ⬜ Fuel-budget prototype — implement and measure the research design before committing to a public API.
- ✅ DSE convergence containment: the fixed 256-iteration partial commit is replaced by a reverse worklist with atomic commit, fail-closed diagnostic budget, bailout statistics, generated reference-solver tests, and the old-boundary family through 1,024 blocks.
- ◐ Exceptional/abrupt CFG: labelled semantic edges, inspection dumps, and an independent dominance/no-clobber verifier now protect GVN. Catch-free
try/finallyis re-enabled on that graph; real catches/with/eval still bail out, and LICM/DSE/provenance remain gated until their own proof contracts land. - ✅ The implicit default is O1 across compiler, docs/types/examples, Worker/build/cache evidence, Test262, and benchmark entry points. Explicit O2/Os remain non-production until every release gate in the CFG/SSA hardening plan passes.
- ✅ New O2/Os throughput work is frozen until the correctness gates pass.
- ✅ Guest-invisible boundary markers: the
HOST_TARGETsymbol tag was removed entirely (audit finding 4) and replaced with a module-private WeakMap. The sweep (enumeration and introspection paths —getOwnPropertySymbols,getOwnPropertyDescriptors,Reflect.ownKeys— plus proxy-trap observation and trap-steering probes) pins that no boundary marker can be observed, forged, or recovered. Details in Security, Historical audit record. - ✅ Sandbox write-path TOCTOU analysis:
writeTargetresolves and asserts in one trap-free pass; focused tests (trap steering, protected writes from inside traps) and documentation added. - ✅ Boundary tests for sparse arrays, huge object graphs, deep nesting (100k levels, iterative clone), and exotic prototypes (null-prototype data, class instances, specials nested in plain data).
- ✅
Map/Set/ typed arrays / Buffer focused boundary tests: key/member identity across the clone graph, cyclic containers, typed-array subclass stripping, DataView bytes, and guest→host round trips. Buffer clones arrive as plainUint8Array. - ◐ Dedicated security regression corpus directory (currently embedded in
security.test.js; split when it grows). - ✅ Proxy / Symbol / SharedArrayBuffer / Atomics / Intl policies are documented in Security.
- ✅ Worker helper, timeouts, message validation, force termination:
sablejs/worker+ Worker isolation. - ✅ Source-size / input-size / output-size budget examples (Worker isolation, Budgets beyond time).
- ◐ Fuel-budget research and design are complete; implementation is pending.
- ✅ Protection for long-blocking or infinite async capabilities: timeout-wrapper pattern documented (Worker isolation, Timeout-wrapping long or never-ending capabilities) —
Promise.racewrapper for async capabilities (guest-visible sanitized timeout error, AbortSignal for real cancellation, wrapper timeout below workertimeoutMs), and the explicit rule that sync-blocking capabilities can only be enforced by the Worker timeout. - ◐ Compile-time loop instrumentation and instruction/fuel budgets are designed but not implemented — see fuel-budget.md:
FUELCHECKops on natural-loop headers (fromcfg.loops) + call sites,hostclassification so no pass can eliminate them, zero default-path cost, and the catch-retry hole with the uncatchable-sentinel fix in theTRY/ENDTRYcatch lowering. A prototype and measurement come before any public API commitment.
- ◐ Pinned Test262 runs continuously and its current O2 gate passes, but that corpus did not expose either 2026-09-01 P0 optimizer finding. The release gate must run the eligible corpus at O0/O1/O2/Os and reject optimization-level drift.
- ◐ Differential testing compares O0/O1/O2/Os against native, with both security modes covered. The boundary oracle also checks observable input mutations, own descriptors, key order, collection size, and capability-call traces. Dedicated deep-CFG/nested-completion families, AST-aware reduction, four permanent corpus cases, six metamorphic families, and verifier mutations are in CI. Feature quotas and the nightly/release-scale campaigns remain.
- ✅ Archive Test262 pass/fail counts and failure lists per release (
npm run test262:archive→archives/test262/); the release workflow archives the completed gate and attaches the full report pluslatest.jsonto the GitHub release. - ✅ The ES5.1-contract exclusion list is documented (Compatibility): corpus selection (
es5id), the token-based dynamic-code policy exclusion, the pinned ES5.1 expectation adjustments, the Babel downlevel path, and the native A/B failure attribution.
- ✅ Program generator, three-engine comparison, failure saving, ddmin minimization (details); CI smoke:
npm run test:differential. - ✅ Sandbox-boundary facet fuzzer (details): contract programs (plain data + capability calls) must agree with the native oracle across trusted/sandbox/QuickJS; proxy-crossing "exotic" cases get a relaxed classification; every compiled artifact is acorn-parsed for generated-code syntax. Found two real sandbox bugs (stack-exhaustion error corruption; raw receiver TypeErrors from Proxy-wrapped branded containers), both fixed with regressions in
test/unit/security.test.js. CI smoke:npm run test:differential:boundary. - ✅ Generated-code syntax validation (acorn over the compiled output, in the boundary facet fuzzer; any generated artifact that does not parse is saved and reported as a syntax failure).
- ⬜ Nightly full campaign (100k → million-scale differential cases).
- ◐ V8 Benchmark Suite 7 + Octane/SunSpider/Kraken are pinned in
tools/upstreams.js, with multi-backend comparison, distribution statistics, size reporting, and environment notes. QuickJS workload source is prepared outside warm samples; SunSpider/Kraken reject incomplete cases.benchmark:releasehas explicit cold/warm protocols and replayable raw JSON, while correctness artifacts are archived by releases. Existing ratios remain historical until all suites are rerun and archived. - ◐ A hashed manifest separates tuning, held-out, and adversarial groups; workloads default to runtime-provided varying input and retain explicit
--input-mode=static. The held-out group is intentionally empty, and its release command fails closed until at least 20 licensed programs land. - ⬜ Measured runs 3 → 10–20, warmup tuning.
- ◐
benchmark:releaseseparates cold (compile/load/run) from warm (prepared repeated calls); the external-suite and workload reports still need the same complete raw protocol. - ⬜ Peak memory reporting.
- ◐ Raw release/correctness JSON includes commit, dirty state, Node/V8/QuickJS, CPU/OS/affinity, options, manifest hash, samples/results/errors/suite counts; automatic Markdown generation and external-suite parity remain.
- ✅ Tax formula automated in
benchmark/release.js; NavierStokes/Crypto profiled (write-guard dominated) and Richards/DeltaBlue/RayTrace profiled (call/construct dominated). - ✅ Pure-intrinsic call fast path + shared intrinsic graph (2026-08-22): call-heavy workloads gained 3–9x and now beat QuickJS-WASM across the board (7 of 8 on the freshest measurements, mini-parser at parity);
createInstancedropped from 387 µs to 33.6 µs. - ✅ Guest-provenance write fast path (2026-08-22, the local-safe IR distinction v1): O2/Os provenance pass after the last SSA pass marks GETLOCAL outputs that are provably guest-created; sandbox
SETPROP/SETPROP_Sinto them lower to a slim$setGuesthelper (sandbox write minuswriteTarget;secureValueand strict/sloppy writer dispatch kept). Marked ⇒ guest-created ⇒ never a wrapper, capability token, or protected intrinsic ⇒writeTargetprovably a no-op. On the V8 suite the 36 fast-path sites are all one-time setup writes (harness config, class enums,Klass.prototype = ...); the write-dominated suites' hot loops writethis-targeted fields andnewresults, so the per-iteration counters are unchanged to 4 significant digits (A/B with the fast path disabled) and the sandbox median re-measured 1,387 vs the documented 1,395 (within sample spread). Regression battery:security.test.jsadversarial cases at all four levels + differential smokes. - ✅ Write-guard levers v2 (2026-08-23) — provenance v2 (Optimization history item 1:
new-result marks + the per-callthisIsGuestframe stamp; Richards −82.7%, DeltaBlue −21.5% per-call writes, +7.6%/+2.7% scores) and slot-provenance write stamps (item 9: per-store classification, NavierStokes +49.7%, Crypto +23.4%, full-suitewriteTargets210.4M → 10.0M); item 10 inlined the classified write natively (full-suite A/B +9.9%). Remaining levers: provenance through property-read chains, the array-index fast path, construct-onlyTHISprovenance. Never break sandbox invariants for a score. - ✅ Call fast path v2 (2026-08-23) — arity-specialized guest-call dispatch (item 2: Richards +6.3%, DeltaBlue +8.4%) and NEW dispatch (item 8: RayTrace's constructions 99.99% on the fast path). The identity-guard and per-site-memo designs measured as negative results in the plan.
- ✅ Object-literal folding (2026-08-23) — item 3: V8 suites flat, but a 2,000-property data literal compiles to 27.9 KB instead of 205.6 KB (7.4× generated-code reduction).
- ✅ Local promotion, phases 1 + 2 + 3 (2026-08-23) — item 6: locals compile out of
$f.localsinto$execprologue variables (strict-mode parameters in phase 2, sandbox in phase 3); trusted NavierStokes +45%, sandbox +47.6%, suite score 2,256 → 2,451. - ✅ Slot-provenance write stamps (2026-08-23) — item 9; see the write-guard entry above.
- ✅ Literal-init fast path (2026-08-23) — item 11: json-transform 1.89×/1.93×, pricing-rules 2.53×/2.63×, 0 slow-path hits across all 8 workloads; the remaining-levers scout after items 17+18 closed at item 19.
- ✅ Frame-stack sync simplification (2026-08-23) — item 12: json-transform 1.97×/2.13×, data-aggregation 1.78×/1.88× after the honest re-measurement (the clobbered-baseline lesson).
- ✅ 8 workloads in
benchmark/workloads/with a four-backend driver, native-oracle correctness probes, default varying runtime JSON input, explicit static-input mode, and per-workload optimizer coverage/bailout reporting. - ⬜ 10k-scale pricing rules, AI-generated data transforms, UI decision logic, repeated execution, many-short-programs, cold Worker startup, compiled artifact cache reuse.
- ✅
benchmark/size.jsmeasures raw CJS + minified IIFE for every level × security and gates CI on recorded budgets (npm run benchmark:size -- --check, +5% tolerance); reproducible Pareto data: O2 per-scope factories cost +55% raw CJS over shared at sandbox (1,225.7 vs 789.5 KB) for the deliberate speed-for-size trade, Os picks shared (617.1 KB sandbox); sandbox O2 min IIFE 593.4 KB (81.5 KB gzip) — full tables in Performance. - ⬜ Factory safe-sharing (emit shared factories only when frame layouts provably match — could recover most of the O2 per-scope premium), helper dedup, descriptor table sharing, literal pooling, common guard factoring.
- ✅ Size regression CI covers O0/O1/O2/Os in both security modes. Per-suite generated-code budgets remain a possible extension.
- ✅
frontend -> ir -> backend -> compiler -> runtimeone-way dependencies. - ✅ Giant-literal superlinearity fixed (four sub-issues) with regressions in
test/unit/compiler.test.js. - ✅ IR explicitly distinguishes local-safe from boundary-sensitive operations (2026-08-22, v1): the guest-object provenance pass (
src/backend/guest-provenance.js, after the last SSA pass, O2/Os) writesguestObjectOutputmarks onto the HIR; codegen replays them as temporary origins and picks the slim$setGuestwrite helper only for provably guest-created targets. Soundness: marked values are never folded/DCE'd/copy-propagated, so the mark cannot go stale; unmarked operands keep today's guarded path. Follow-ups: provenance through property-read chains andnewresults, INITPROP fast path. - ✅ Each optimization pass documents its semantic invariants (2026-08-22): every pass in
src/backend/optimizer.jscarries a contract note — what it proves, what it preserves, and which instruction fields it may write; the security-sensitive guest-object-provenance pass documents its mark soundness and has adversarial regression tests at all four optimization levels plus differential coverage. - ✅ IR dump / generated-code inspection mode (2026-08-22):
compile({ dumpDir })writeshir.txt(annotated optimized HIR),mir.txt(MIR blocks/phis/operations), andcode.js;includeHIR/includeMIR/dumpIR: "hir"|"mir"|"all"attach the graph objects (dumpIR: "all"now includes both forms). The text printer lives insrc/ir/print.js; covered intest/unit/compiler.test.js. - ✅ Backend optimization batch (2026-08-23/24): strict-mode parameter propagation, guest-provenance v2, intrinsic-read LICM (validated out), local promotion (frame-shape specialization, all three phases), dead-store elimination, dense
JCASEswitch lowering, leaf-frame pooling, the NEW-dispatch arity specialization, slot-provenance write stamps, the inline guest-stamp write path, the literal-init fast path, the frame-stack sync simplification, the inlined literal-init fast path, and the sandbox-only host-intrinsic call inline shipped (plan items 4, 1, 5, 6, 7a, 7b, 7c, 8, 9, 10, 11, 12, 13, 14); the entry-counter investigation was closed (already gated) — full designs, soundness arguments, and per-item evidence gates in Optimization history. - ◐ Productization hardening: the canonical opcode/MIR contract, completion-aware control flow, executable analysis-generation contracts, transactional pass rollback, and independent verification for
reuse, LICM, elided stores, branch facts, and guest provenance have landed. CFG edges are source-reconstructed; MIR checks edge/Phi/definition/effect/use identities, HIR mapping, and edge stack signatures. Corpus, held-out evidence, and canary gates remain open; see the CFG/SSA hardening plan.
- ✅ Minimal
compile → createInstance → run → disposeexample, capability example, Worker helper + Worker isolation. - ✅ Source map support for generated code (2026-08-25): statement-level v3 maps at all four optimization levels, inline/external modes, logical filenames,
sourcesContentopt-in,dumpDirintegration, byte-for-byte map-off stability, Node engine remapping evidence (node --enable-source-maps, both security modes, caught and uncaught), browser in-page inline-map evidence (Playwright, chromium/firefox/webkit), and virtual sources for static eval/Function bodies (<sourceFile>#eval-N/#dynamic-Nwith offset translation; runtime-dynamic eval unmapped);test/unit/source-map.test.js(22 tests) +test/unit/source-map-e2e.test.js(3 tests) +test/e2e/browser.test.js. Expression-level columns and host-facingguestLocationon stackless sandbox errors stay explicitly deferred (decision record in source-maps.md). - ✅ TypeScript declarations (including capability types), browser/Worker/Node/Bun/Deno examples, error handling, precompile-at-build-time, compiled artifact cache examples (2026-08-25):
types/index.d.ts+sablejs/runtime+sablejs/workerdeclarations withtypes/typecheck/usage fixtures (CJS and ESM contexts) gated bycheck:types; examples underexamples/for Node, Browser (esbuild bundle + inline map), Worker, Deno, Bun, trusted mode, precompile-at-build-time, and the artifact cache — all verified by theexamplesCI job; error handling docs in README;check:examplesgates releases.
- ✅
docs/architecture.md,docs/performance.md,docs/security.md(with threat model),docs/worker-isolation.md, and the active CFG/SSA hardening plan. - ◐ O0/O1/O2/Os design goals (brief version in Architecture; expand).
- ✅ Dedicated compatibility contract with a user-facing support summary.
- ✅ V1-to-v2 migration guide and execution-model comparison.
- ◐ A separate capabilities reference remains optional if the current README/security/Worker material outgrows its sections.
- ✅ Documented (README + Security): keep the ES5.1 core stable, recommend modern JS → Babel/SWC → ES5.1 → sablejs; add modern features natively only when the benefit is clear and the implementation boundary is clean; no native Proxy semantics beyond the guest, module loaders, or generator/async runtimes. The limited language surface is a security and maintainability advantage.
- ✅ Release pipeline: tags must match
package.jsonand point intomaster; a read-only job runs unit/adversarial, Test262, differential, benchmark, size, Node/Deno/Bun, browser/compiler/Worker, build, and third-party-license gates. Only its uploaded artifact reaches the separate OIDC publish job. All Actions are pinned to full commit SHAs; Test262 evidence ships with the release. - ◐ Remaining release reporting automation: archive benchmark JSON + environment info, auto-generate the performance markdown, and flag security-sensitive changes in generated release notes.
- Boundary facet fuzzer: stack-exhaustion error corruption — an infinite recursion inside a mediated call exhausted the host stack; the exception sanitizer then ran its boundary-message check on the exhausted stack, so the guest saw
SyntaxError: Invalid regular expression: ... Maximum call stack size exceededinstead of the engine'sRangeError. The sanitizer now tags boundary errors in a module-privateWeakSet(identity check, no regex) and rethrows the original error if evensafeErrorfails on a degraded stack. Regression: recursive mediated calls surface the sameRangeErrorin sandbox and trusted across O0/O1/O2/Os. - Boundary facet fuzzer: Proxy-wrapped branded containers leaked raw receiver TypeErrors — a guest passing
new Proxy(new Set(...))to a capability reached the clone internals' branded methods, which threw unlabeled receiver TypeErrors instead of the documented boundary rejection. Every branded clone path (Date/RegExp/ArrayBuffer/typed arrays/Map/Set/Error) now converts receiver-identity failures intosablejs sandbox boundary: <path> is a Proxy-wrapped <tag>; only plain data or explicit capabilities cross; proxies over plain data still clone as the data they present. Regressions cover all branded shapes. - Bundled guests keep ES5 sloppy
argumentssemantics — esbuild hoists"use strict"from any strict module to the top of the bundle, which turns the runtime's sloppyarguments-capture helper strict: its Arguments object then carries PoisonPillcallee/calleraccessors (non-configurable), and the runtime's mapped-parameter defines threwCannot redefine property: callee. The runtime now detects a strict capture and, for sloppy guest frames, routes the exposed Arguments object through a Proxy withcallee/callerin closure cells, soarguments.callee === fand legacycallerreads keep working in bundled artifacts. This also fixed the shippeddist/runtime.js(same bundle shape). E2E regression: the bundled build test now probesarguments.length/ mapped parameters /calleeidentity (test/e2e/build.js). - Guest-invisible wrapper mapping (audit finding 4) — the
HOST_TARGETsymbol tag on wrappers could be observed by guest proxy get traps during write-target resolution and byReflect.ownKeysenumeration, and a trap returning a wrapper could steer resolution toward that wrapper's host target. Replaced with a module-privatewrapperTargetsWeakMap:WeakMap.getis trap-free, unforgeable, and unobservable, so write-target resolution is single-pass and guest traps cannot influence it. The boundary-internals sweep (P0-S1/S2) pins the fix with trap-observation, trap-steering, and enumeration regressions. - Iterative value clone + per-node checks —
cloneValuewas rewritten with an explicit work stack (depth bounded by memory instead of the host call stack: 100k-deep graphs clone without stack overflow), and the entry-level checks (ambient objects, capability records, functions, primitives) now run per node so nested values keep their specific boundary messages. The zero-skipped P0 clone sweep (P0-S3/S4) covers sparse arrays, huge graphs, deep cycles, null-prototype data, Map/Set identity, typed-array subclass stripping, and DataView bytes. $v1_30cross-block inline-guard bug — trusted sunspiderstring-unpack-codefailed with$v1_30 is not defined: an inlined identity guard referenced a closure temporary emitted in a sibling region block. Fix:temporaryRegionsrecords each temporary's emission region stack; inline guards fall back to the runtime call when the temporary is invisible, and the reuse optimization gets the same check. Sunspider trusted restored, 23/23.- Giant-literal superlinearity — Kraken's ~1.8 MB imaging literals hit four scaling bugs: SCCP post-pass O(V²) linear lookup →
Mapindex (25.2s→1.0s at 8,000 objects), frontend number/string tableindexOfdedup → parallelMap(400k elements 58.0s→0.76s), O2 scope overflow → 200-constblock chunking (visibility checks aware of block boundaries), and codegen constant array-literal chains now fold into native literals (47.6 MB→1.8 MB generated code per test). Kraken imaging restored, 14/14. - Audit findings 1/2/3 — fixed with permanent regressions; see Security, Historical audit record.
- Boundary fast paths — profiling the real-world workloads showed two dominant costs: the per-call guard checks on pure intrinsics (call-mediation dominated form-validator, template-logic, mini-parser) and the per-instance intrinsic graph walk (48% of
createInstance, dwarfing form-validator's 12 boundary calls per run). Fixes: a lazily classified pure-intrinsic fast path plus a monomorphic identity cache inboundary.call, and a module-level shared intrinsic graph (contract: the host must not extend intrinsic prototypes after the first instance — documented in Security). Sandbox now beats QuickJS-WASM on every workload and every suite where it previously lost at the time (Octane 1,613→1,772, Kraken 28.6 s→20.8 s, form-validator 2,546→22,114 ops/sec; the freshest 2026-08-22 measurements put mini-parser at parity).