# Refactor-plan benchmark policy
The reproducible harness lives in `tools/benchmarks`. It gates correctness before latency and keeps four result classes separate: cached legacy validation, JSON parse plus legacy validation, end-to-end validation/fingerprinting, and cached validated fingerprint lookup.
The direct predecessor is public npm `weavatrix-refactor@0.1.5`. Its validator is a useful common-subset baseline, but its `planHash` removes `createdAt` and hashes insertion-order `JSON.stringify` output. That hash is retained only as migration context; it is not byte-equivalent to the Rust JCS contract and is never included in an equal-contract speed claim.
The fingerprint reference is pinned Node `canonicalize@3.0.0`. A correctness run must prove byte-for-byte canonical JSON equality and equal domain-separated SHA-256 digests before any timing is recorded. The end-to-end Node row includes npm validation, canonicalization, and hashing; the Rust row calls `validate_consumer_plan`. Because Rust additionally validates the new evidence/operation contract, that row is descriptive and speed-claim ineligible. Cached digest lookup is measured separately with equal semantics. An unchecked canonicalize/hash-only row is omitted because the crate intentionally exposes no such route. Adversarial validation also checks bounds, path aliases, overlaps, unsafe numbers, and duplicate member names.
Publication-quality rows use warmed persistent processes, in-worker timing, seeded interleaving, five warmups, 30 recorded samples, at least 250 ms of adaptive inner loops per sample, raw sample retention, and 95% bootstrap median intervals. A 2x statement is allowed only for an individual row whose conservative `JavaScript p25 / Rust p75` ratio is at least 2.0. There is no universal product ranking, and the stronger validated Rust JCS operation is not labeled equal-cost to the Node canonicalization reference.
Windows and Ubuntu CI execute the short smoke profile solely to verify portability and correctness. Publication performance is run only after source/machine freeze and with no concurrent full benchmark.