core/docs/research/rust-parity-measurement-2026-07-26.md
Shay 808f3d32c4 fix(cli): core rust build was broken; report Rust parity as unfalsifiable
Plan §6A, report-only per DIVISION-OF-WORK §4. Both halves ran. The cargo half
is real evidence; the LANE half is vacuous, and saying so is most of the point.

cargo test (PYO3_PYTHON=/opt/homebrew/bin/python3.12, --offline): 43 passed,
0 failed across 7 suites including test_crdt_hash_parity.rs. The plan's read
was right — cargo 1.97.1 and the registry cache are present locally and the
cloud session was blocked only by sandbox network policy.

Lane parity: 11/11 pinned SHAs match under both backends. That number means
nothing. Sabotaging EVERY core_rs callable to raise and re-running under
CORE_BACKEND=rust still gives `lanes: 11/11 match pinned SHAs`, exit 0. Three
sufficient reasons:

- The hot path bypasses the dispatch. algebra.cga.cga_inner is NOT
  algebra.backend.cga_inner; 69 call sites import the hot functions from
  algebra.cga/algebra.cl41 directly vs 24 through algebra.backend. The ~34k
  cga_inner->geometric_product calls/turn that plan §6C calls ~73% of turn
  time never reach the dispatch.
- The dtype gates reject the runtime workload. versor_condition IS imported
  from algebra.backend by pipeline.py:24, and still falls through: the Rust
  arm requires f32 and the wave-field workload is f64.
- Every dispatch arm ends in `except (..., Exception): pass`, so a broken,
  garbage-returning, or absent kernel falls back to Python SILENTLY. That is
  what makes the first two unfalsifiable by lane hashes.

Instrumented under CORE_BACKEND=rust: zero Rust calls in the whole
deductive_logic lane (pure ROBDD, no CGA), and exactly ONE
(versor_apply_with_closure_f64) in a full pipeline turn. CORE_BACKEND=rust is
today a one-call switch.

So §6B ("if parity holds, consider Rust default") rests on a measurement that
cannot fail, and §6C is the real blocker and is upstream of the backend. NOT
acted on — §6.4 says a parity/determinism finding is escalated, not fixed.
Recorded three follow-ups in dependency order: make the dispatch fail loudly,
add a parity test that fails when the Rust path is not TAKEN, only then route
the hot path.

The one thing fixed here is a plain defect blocking the measurement.
`core rust build` — the activation path print_rust_status() itself recommends —
raised `TypeError: _run() got an unexpected keyword argument 'env'` on every
invocation. core/cli.py::_run is injected into cli_rust.cmd_rust_build, which
passes env=rust_build_env() to carry PYO3_USE_ABI3_FORWARD_COMPATIBILITY, and
_run lacked the keyword the CommandRunner Protocol declares. One keyword, plus
tests/test_cli_runner_contract.py deriving the expected keywords FROM the
Protocol so the two cannot drift apart again. Verified end-to-end: `core rust
build` now builds and installs.

[Verification]: in-worktree on canonical CPython 3.12.13 with `uv sync
--locked`: smoke 575 (569 + 6), deductive 291 (unchanged). New tests fail
under mutation (revert the env keyword -> 3 red). Registered in `fast` AND
`smoke`. Installing core_rs does not activate it (_ALLOW_RUST requires
CORE_BACKEND), verified: extension present + no env var -> "rust backend:
inactive", so no default behaviour moves.
2026-07-26 11:50:32 -07:00

157 lines
7.3 KiB
Markdown

# Rust backend parity — measured, and why the instructed method cannot fail
**Date:** 2026-07-26 · **Arc:** curriculum-license-loop-2026-07 · **Unit:** plan §6A
**Instruction:** "`PYO3_PYTHON=/opt/homebrew/bin/python3.12`, `cargo test` in
`core-rs/`, then rerun the hash-pinned lanes under `CORE_BACKEND=rust`. **Report the
measurement; do not act on it.**" (`DIVISION-OF-WORK.md` §4)
Both halves ran. The first is a real signal. **The second is vacuous, and this note
exists mostly to say so** — run as instructed it produces "11/11 lanes match, parity
holds", which is true, and which would be read as evidence about the Rust kernels
when it is not evidence about them at all.
---
## 1. `cargo test` — 43 passed, 0 failed
```
PYO3_PYTHON=/opt/homebrew/bin/python3.12 cargo test --offline
```
| suite | tests |
|---|---:|
| unit (`src/`) | 7 |
| `test_arena.rs` | 10 |
| `test_cga.rs` | 5 |
| `test_cl41.rs` | 7 |
| `test_crdt_hash_parity.rs` | 6 |
| `test_vault.rs` | 4 |
| `test_versor.rs` | 4 |
| **total** | **43 passed / 0 failed** |
The plan's read was correct: cargo 1.97.1 and the registry cache are present
locally, and the cloud session was blocked only by sandbox network policy.
`--offline` needed no downloads. This half is genuine evidence — in particular
`test_crdt_hash_parity.rs` includes `parity_permutation_invariant_matches_python`
and `parity_signed_zero_distinct`.
## 2. Lane parity — 11/11 both ways, and the number means nothing
```
uv run python scripts/verify_lane_shas.py # lanes: 11/11 match
CORE_BACKEND=rust uv run python scripts/verify_lane_shas.py # lanes: 11/11 match
```
Identical, byte for byte, every lane. Then the check that matters:
> **Sabotaged every `core_rs` callable to raise, re-ran under `CORE_BACKEND=rust`:
> `lanes: 11/11 match pinned SHAs`, exit 0.**
A measurement that passes with the entire Rust backend replaced by exceptions is
not measuring the Rust backend. Three independent reasons, each sufficient:
**(a) The hot path bypasses the dispatch.** `algebra/backend.py` is the only place
that consults `CORE_BACKEND`, and `algebra.cga.cga_inner is not
algebra.backend.cga_inner`. Counting call sites for the hot functions:
| import route | call sites |
|---|---:|
| `from algebra.cga import …` / `from algebra.cl41 import …` (**bypasses** dispatch) | **69** |
| `from algebra.backend import …` (uses dispatch) | 24 |
So the ~34k `cga_inner``geometric_product` calls per turn that plan §6C
identifies as ~73% of turn time do not reach the dispatch at all.
**(b) The dtype gates reject the runtime workload.** `versor_condition`,
`cga_inner` and the f32 arm of `geometric_product` require
`_is_f32_workload(...)`. `core/cognition/pipeline.py:24` imports
`versor_condition` from `algebra.backend` — the dispatch IS consulted there — and
still falls through, because the wave-field workload is f64.
**(c) Every dispatch arm swallows every exception.** Each Rust branch is wrapped in
`except (AttributeError, TypeError, ValueError, Exception): pass`. A Rust kernel
that raises, returns garbage of the wrong type, or is missing entirely produces a
**silent** fallback to Python. That is what makes (a) and (b) unfalsifiable by lane
hashes: Python answers, the hash matches, the lane is green.
Instrumented call counts under `CORE_BACKEND=rust`, wrapping every `core_rs`
callable:
| workload | Rust kernel calls |
|---|---|
| `deductive_logic_v1` lane (whole lane) | **none** — the lane is pure ROBDD, no CGA |
| one full `CognitiveTurnPipeline.run` turn | **1** (`versor_apply_with_closure_f64`) |
One call per turn. `CORE_BACKEND=rust` is, today, a one-call switch.
## 3. What this means for the plan
- **§6A is answered narrowly.** `cargo test` is green, and the one dispatched f64
path a turn actually takes (`versor_apply_with_closure_f64`) is bit-identical —
lane hashes are unchanged with it live. Nothing broader was established.
- **§6B ("if parity holds: consider Rust default") rests on a measurement that
cannot fail.** Flipping the default today would change one call per turn and gain
approximately nothing, because the hot path does not route through the dispatch.
The premise needs to be re-earned before the decision is worth making.
- **§6C is the actual blocker, and it is upstream of the backend.** Accelerating
`cga_inner`/`geometric_product` requires routing their 69 call sites through
`algebra.backend` and giving the f64 workload a bit-identical f64 kernel. That is
a real change to a determinism-critical path, and it is exactly the kind of change
the lane pins exist to gate — but only once the pins can actually see it.
**Not acted on** — the instruction is report-only, and §6.4 is explicit that a
parity or determinism finding is escalated rather than fixed. Three things a future
unit should consider, in dependency order:
1. **Make the dispatch fail loudly.** Replace the blanket `except … Exception: pass`
with a narrow catch plus a one-time warning, or a strict mode that raises. While
fallback is silent, no parity measurement over lanes can be trusted, and this
note's conclusion would have to be re-derived by hand every time.
2. **A parity test that fails when the Rust path is not taken.** Assert a nonzero
Rust call count under `CORE_BACKEND=rust`, so "parity holds" cannot be satisfied
by never invoking Rust. Without it, §6A's exit criterion is unfalsifiable.
3. Only then: route the hot path through the dispatch (§6C).
## 4. One defect found and fixed here
`core rust build` — the documented activation path, named by
`print_rust_status()`'s own `activation: run \`core rust build\`` hint — raised
`TypeError: _run() got an unexpected keyword argument 'env'` on **every**
invocation. `core/cli.py::_run` is injected into `cli_rust.cmd_rust_build`, which
passes `env=rust_build_env()` to carry
`PYO3_USE_ABI3_FORWARD_COMPATIBILITY` (PyO3 0.21 supports Python through 3.12).
`_run` had no `env` parameter, while the `CommandRunner` Protocol both call sites
are typed against does.
Fixed (one keyword) and pinned by `tests/test_cli_runner_contract.py`, which
derives the expected keywords **from the Protocol** rather than from a hand-written
list, so the two cannot drift apart again. The build had to be driven with
`python -m maturin develop --release` directly to take the measurements above.
## 5. Reproduction
```bash
# 1. Rust unit + parity suites
cd core-rs && PYO3_PYTHON=/opt/homebrew/bin/python3.12 cargo test --offline
# 2. install the extension (needs the §4 fix, or call maturin directly)
PYO3_PYTHON=/opt/homebrew/bin/python3.12 uv run core rust build
# 3. activation is opt-in: importable is NOT active
uv run python -c "from core.cli_rust import print_rust_status; print_rust_status()"
# -> rust backend : inactive
CORE_BACKEND=rust uv run python -c "from core.cli_rust import print_rust_status; print_rust_status()"
# -> rust backend : active
# 4. lane hashes, both backends
uv run python scripts/verify_lane_shas.py
CORE_BACKEND=rust uv run python scripts/verify_lane_shas.py
# 5. the check that shows 4 proves nothing: sabotage every kernel, rerun 4.
# Still 11/11.
```
Installing `core_rs` does **not** activate it — `_ALLOW_RUST` requires
`CORE_BACKEND` in `{rust, core_rs, rs}`, so a stray local build cannot silently
change default behaviour. Verified: with the extension installed and no env var,
`rust backend : inactive`.