Skip to main content
The heavy aggregation primitives — histogram and quantile, run over the score and cluster-size arrays of large results — have an optional Rust kernel, gated exactly like goldenmatch[native] / goldencheck[native]. Those two are the measured performance wins. The rest of the aggregation surface is now backed by the same analysis-core crate too — the frame-stat kernels (null_ratio_per_column / duplicate_row_ratio / distinct_count), the numeric reductions (mean / min / max), and the discrete cluster_size_histogram — but those were cut over for one source of truth across Python / native / WASM, not for speed (they’re already cheap). Each is parity-gated byte-identical to the pure reference; none is claimed as a perf win.
The pure-Python path stays the default and the byte-identical reference. The compiled kernel (analysis-core, a pyo3-free crate, plus the analysis-native abi3 wheel) mirrors core/aggregate.py value-for-value, reading input as a Float64 Arrow array (zero-copy). With the wheel installed, GOLDENANALYSIS_NATIVE=auto (the default) uses the native path automatically; GOLDENANALYSIS_NATIVE=0 forces pure.

Gate on the measured wall, not “it’s Rust”

In reference mode a primitive runs native wherever its kernel symbol is present; _native_loader._GATED_ON records which primitives cleared the two-gate sign-off: a parity test proves byte-identical output, and the wall-clock is measured to actually move on the target environment. The pure loops are tight, and the native path pays a list→Arrow conversion cost, so “it’s compiled” is never enough — the goldencheck composite-key kernel was once 2.5x slower than its baseline, and the gate caught it. histogram and quantile cleared both gates. The A/B harness (bench-analysis-native.yml, on Linux x86_64) measured the realistic dispatch — a Python list converted to Arrow, then the kernel, exactly what the call sites pay: The Arrow conversion turns out to be far cheaper than the pure-Python loops, so the native path wins decisively even including it.

How it stays honest

  • Two crates, mirrored. analysis-core (pyo3-free) holds the kernel logic so it can later back a SQL surface; analysis-native is the thin abi3 PyO3 + Arrow shim over it.
  • Parity is a CI gate. A dedicated lane builds the wheel and runs the parity suite under GOLDENANALYSIS_NATIVE=1, including end-to-end tests that the public dispatch for every covered primitive (histogram, quantile, the frame-stat kernels, mean/min/max, and cluster_size_histogram) is byte-identical to the pure path. Analyzers that stay pure on both surfaces are locked by shared cross-surface fixtures instead — the frame-kernel equality semantics (-0.0/NaN/null), cluster.distribution, quality.rollup, and the regression decision logic each have a byte-identical Python↔TS fixture.
  • No behavior change without the wheel. With no native extension installed, auto resolves to the pure path; results are identical whether or not native is present.
In-tree dev build (no maturin needed):

TypeScript: opt-in WASM (browser / edge / Node)

The TypeScript port (goldenanalysis on npm) reaches the same analysis-core crate via WebAssembly — the TS analogue of the Python native wheel. Same posture: pure-TS is the default and the byte-identical fallback; WASM is an explicit upgrade for large columns.
  • Covered ops: histogram, quantile, mean, min, max, and cluster_size_histogram — the numeric + cluster kernels, each crossing as a Float64Array zero-copy (the quantile sort runs in Rust). The frame-stat kernels (duplicate_row_ratio / distinct_count / null_ratio) stay pure-TS: they need value-interning that has no clean WASM boundary, so a browser dedup surface is consciously deferred. Everything else in aggregate stays pure-TS too.
  • Opt-in, edge-safe, parity-gated exactly like the scorer WASM backend in goldenmatch: pure-TS is the default + fallback, the .wasm is built in CI (never committed), and a CI lane asserts WASM ≈ pure-TS to 4 decimals. The plumbing is shared with goldenmatch via the goldenmatch-wasm-runtime package.
  • Build locally: bash packages/rust/extensions/analysis-wasm/build_wasm.sh (needs the rustup wasm32-unknown-unknown target + wasm-bindgen-cli).