Merge pull request 'Rust parity: cargo green, lane parity unfalsifiable — plus core rust build was broken (plan §6A)' (#124) from fix/rust-build-env-and-parity-report into main

This commit is contained in:
Joshua Matthew-Catudio Shay 2026-07-26 20:20:16 +00:00
commit 9d9fa340df
4 changed files with 262 additions and 3 deletions

View file

@ -33,9 +33,22 @@ from core.cli_test import TEST_SUITES as _TEST_SUITES # noqa: E402
def _run(*args: str, check: bool = False, cwd: Path | None = None) -> int:
"""Run a child command and return its exit code."""
completed = subprocess.run(args, check=check, text=True, cwd=cwd)
def _run(
*args: str,
check: bool = False,
cwd: Path | None = None,
env: dict[str, str] | None = None,
) -> int:
"""Run a child command and return its exit code.
``env`` is part of the ``CommandRunner`` contract that ``core/cli_rust.py``
and ``core/cli_test.py`` are written against; omitting it here made
``core rust build`` raise ``TypeError`` unconditionally, because
``cli_rust.cmd_rust_build`` passes ``env=rust_build_env()`` to carry
``PYO3_USE_ABI3_FORWARD_COMPATIBILITY``. The injected runner has to accept
everything the injection sites pass.
"""
completed = subprocess.run(args, check=check, text=True, cwd=cwd, env=env)
return int(completed.returncode)

View file

@ -13,6 +13,7 @@ from typing import Protocol
TEST_SUITES: dict[str, tuple[str, ...]] = {
"fast": (
"tests/test_cli_test_suites.py",
"tests/test_cli_runner_contract.py",
"tests/test_runtime_config.py",
"tests/test_core_semantic_seed_pack.py",
"tests/test_intent_proposition_graph.py",
@ -27,6 +28,7 @@ TEST_SUITES: dict[str, tuple[str, ...]] = {
"tests/test_cognitive_turn_pipeline.py",
"tests/test_audit_ledger_r7.py",
"tests/test_architectural_invariants.py",
"tests/test_cli_runner_contract.py",
# Audio sensorium lane — part of the smoke.yml PR gate (compiler,
# CRDT merge, eval gates, pack manifest, mount, teachers; ~3s).
# Listed explicitly so the local-first pre-push gate (AGENTS.md

View file

@ -0,0 +1,157 @@
# 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`.

View file

@ -0,0 +1,87 @@
"""The injected `CommandRunner` must accept everything its call sites pass.
`core/cli.py::_run` is injected into `cli_rust.cmd_rust_build` and
`cli_test`'s runner. Both are typed against a `CommandRunner` Protocol carrying
`check`, `cwd` and `env`. `_run` was missing `env`, so `core rust build` raised
`TypeError: _run() got an unexpected keyword argument 'env'` on every
invocation the documented Rust activation path had never worked.
Nothing caught it because the runner is only exercised through subprocess-y
commands that tests avoid calling for real. So the pin is on the SIGNATURE,
checked against the Protocol rather than against a hand-written list, so a
future keyword added to one side cannot drift from the other.
"""
from __future__ import annotations
import inspect
import pytest
from core.cli import _run
from core.cli_test import CommandRunner, run_command
def _keywords(fn: object) -> set[str]:
sig = inspect.signature(fn) # type: ignore[arg-type]
return {
name
for name, p in sig.parameters.items()
if p.kind in (p.KEYWORD_ONLY, p.POSITIONAL_OR_KEYWORD)
and name not in ("args", "self")
}
def test_injected_runner_satisfies_the_command_runner_protocol() -> None:
"""Derived from the Protocol, so it cannot fall behind it."""
protocol_kwargs = _keywords(CommandRunner.__call__)
assert protocol_kwargs, "CommandRunner.__call__ has no keywords — protocol changed?"
missing = protocol_kwargs - _keywords(_run)
assert not missing, (
f"core.cli._run is missing {sorted(missing)} — it is injected into "
"cli_rust.cmd_rust_build, which passes env=rust_build_env(). A runner "
"that cannot accept what its call sites pass raises TypeError at runtime."
)
def test_default_runner_and_injected_runner_agree() -> None:
"""Both runners are used interchangeably; their keywords must match."""
assert _keywords(_run) == _keywords(run_command)
@pytest.mark.parametrize("keyword", ["check", "cwd", "env"])
def test_runner_accepts_each_documented_keyword(keyword: str) -> None:
assert keyword in _keywords(_run)
def test_rust_build_passes_env_so_the_runner_must_accept_it() -> None:
"""Pins the actual call site that broke, not just the signature.
Runs `cmd_rust_build` with a recording fake runner: it must reach the
maturin invocation and carry an env, rather than raising TypeError.
"""
import argparse
from core import cli_rust
seen: list[dict[str, object]] = []
def fake_run(*args: str, check: bool = False, cwd: object = None,
env: dict[str, str] | None = None) -> int:
seen.append({"args": args, "env": env})
return 0
args = argparse.Namespace(skip_auditwheel=False)
rc = cli_rust.cmd_rust_build(
args, run=fake_run, fail=lambda m, code=2: (_ for _ in ()).throw(SystemExit(code)),
python_executable="python3",
)
assert rc == 0
maturin = [c for c in seen if "maturin" in c["args"]]
assert maturin, f"maturin was never invoked; calls={seen}"
env = maturin[-1]["env"]
assert isinstance(env, dict)
assert env.get("PYO3_USE_ABI3_FORWARD_COMPATIBILITY") == "1", (
"the env is the whole reason the keyword exists — PyO3 0.21 supports "
"Python through 3.12 and needs the forward-compatibility escape hatch"
)