Skip to content

The parity gate

Of the gates, gate 13 is the one unusual enough to need its own page: it asserts that the Rust and Python arms of every paired example agree to the bit.

What it asserts. Each pair listed in examples/parity.toml has a Rust arm and a Python arm. Both print a canonical atune-parity/1 block at the end of the run — study, seed, trial count, sampler, and the winning trial's number, value and parameters. The gate runs both and requires the blocks to match: the header byte-equal, the same keys in ascending order, string fields byte-equal, and float fields equal as raw f64 bits after parsing. That is atune's determinism contract, asserted across the binding boundary.

How to run it.

  • cargo dev check-parity runs both arms of every pair. It needs the wheel built, so run maturin develop --release -m crates/atune_py/Cargo.toml first.
  • cargo dev check-parity --rust-golden runs only the Rust arms and compares each against a committed golden file. No Python needed, which is why this half runs in the fast per-push gate.
  • cargo dev run-examples runs every example, paired or not.

When it reddens. The failure names the pair, the first differing key, and both values with their bit patterns. Work through these in order:

  1. You changed one arm of a pair. Change the other. The two programs are idiomatic in their own language but arithmetically identical: same operation order, and no fused multiply-add on either side, because f64::mul_add has no pre-3.13 Python counterpart and the fused and unfused spellings agree only for particular inputs.
  2. You changed a sampler, scheduler or seed derivation on purpose. Then every pair's numbers move together, and the Rust goldens are stale by design. Re-bless them with ATUNE_BLESS_PARITY=1 cargo dev check-parity --rust-golden and read the diff — that file is the record of the change in behaviour. Never bless without reading it.
  3. Only best.value differs, in the last bits, and you changed neither arm. Check that both arms ran on the same machine. f64::cos and math.cos both defer to the platform's C library, which is not required to be correctly rounded, so a cross-machine comparison is a statement about libm rather than about atune. The goldens name the platform they were blessed on.
  4. The trial count differs. Something is history-dependent and running in parallel. A parity example that uses a history-dependent sampler or scheduler must run with a parallelism of one: the interleaving decides the history, and the history decides the answer.
  5. Neither arm changed and neither of the above applies. That is a real determinism bug, and it is the outcome the gate exists for. Do not paper over it.

What you may not do. Do not add a tolerance to make a comparison pass. Do not delete a pair to make the gate quiet: every example under examples/ must appear in examples/parity.toml, either as a [[pair]] or as an [[unpaired]] entry with a reason, and a file in neither is a parse error. If an objective genuinely cannot be spelled identically in both languages, the pair downgrades to compare = "params-only" — parameters and trial number still bit-equal, the value to a declared tolerance — and that mode requires a reason too, which is rendered on the example's own page.