From b31d6fdee12ae89b3b63b6b9ac7bc8e4ee5ea1c8 Mon Sep 17 00:00:00 2001 From: Shay Date: Fri, 17 Jul 2026 19:59:05 -0700 Subject: [PATCH] =?UTF-8?q?feat(adr-0244):=20Phase=205d=20=E2=80=94=20ADR-?= =?UTF-8?q?0245=20=C2=A73=20acceptance=20gate=20(f32=20speedup=20+=20colli?= =?UTF-8?q?sion)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Close the two missing §3 acceptance legs. tests/test_adr_0245_acceptance_gate.py: - ≥10× f32 speedup: the Rust core_rs.geometric_product f32 fast path vs the pure Python kernel. Rust-guarded (skips with reason where core_rs is unbuilt); includes a parity sanity check so the speedup can't come from skipped work. Measured on Apple M-series this run: rust 2.86 us/op vs python 1340 us/op = 467× (assert a conservative ≥10× for CI timing robustness). - _content_id collision-resistance: full 256-bit digest (len 64, not 16-hex), type/structure-faithful (int≠str, bool≠int, nested-sensitive, key-order- invariant), fails closed on non-serializable input (no default=str collapse); _psi_digest full + sub-epsilon sensitive + deterministic. - coverage manifest test maps all four §3 legs (parity f64/f32, 0-LAPACK-on- repeat, f32 speedup, collision) to their home test files. The other two legs (parity, 0-LAPACK) were already green; this makes the §3 gate complete and legible. Test-only. Verified: 6 new tests pass (speedup ran with a local core_rs build). Full smoke + fast lane at Phase 5 close. --- tests/test_adr_0245_acceptance_gate.py | 125 +++++++++++++++++++++++++ 1 file changed, 125 insertions(+) create mode 100644 tests/test_adr_0245_acceptance_gate.py diff --git a/tests/test_adr_0245_acceptance_gate.py b/tests/test_adr_0245_acceptance_gate.py new file mode 100644 index 00000000..61715ce5 --- /dev/null +++ b/tests/test_adr_0245_acceptance_gate.py @@ -0,0 +1,125 @@ +"""ADR-0245 §3 — mechanical-sympathy + semantic-rigor acceptance gate. + +The §3 gate has four assertions. Two were already covered before D4: + + * **Parity** (Rust GP bit-identical to Python) — `test_geometric_product_f64_parity.py` + (f64, N=10,000 bit-identical) + `test_geometric_product_rust_parity.py` (f32, + component-exact). + * **0 LAPACK on repeat** (`_cached_eigh` memoization) — + `test_adr_0244_mechanical_sympathy.py`. + +This file closes the two that were missing (D4 Phase 5): + + * **≥10× f32 speedup** of the Rust `geometric_product` fast path over the pure + Python kernel (Rust-guarded: skips with a reason where `core_rs` is unbuilt). + * **`_content_id` collision-resistance** — full 256-bit digest, type-faithful, + fail-closed on non-serializable input (no `default=str` collapse). +""" + +from __future__ import annotations + +import importlib.util +import time + +import numpy as np +import pytest + +from core.physics.cognitive_lifecycle import _content_id, _psi_digest + +_HAS_RUST = importlib.util.find_spec("core_rs") is not None + + +# --- ≥10× f32 speedup (Rust-guarded) -------------------------------------- + + +@pytest.mark.skipif(not _HAS_RUST, reason="core_rs not built (Rust f32 kernel unavailable)") +def test_rust_f32_geometric_product_is_at_least_10x(): + import core_rs + + from algebra.cl41 import geometric_product as py_gp + + rng = np.random.default_rng(0) + A = rng.standard_normal(32).astype(np.float32) + B = rng.standard_normal(32).astype(np.float32) + + # parity sanity: the speedup must not come from skipping work. + r_rust = np.asarray(core_rs.geometric_product(A, B), dtype=np.float64) + r_py = np.asarray(py_gp(A, B), dtype=np.float64) + np.testing.assert_allclose(r_rust, r_py, atol=1e-5) + + for _ in range(200): # warmup (JIT-free, but stabilizes caches/branch pred.) + core_rs.geometric_product(A, B) + py_gp(A, B) + + def _best(fn, n): + best = float("inf") + for _ in range(3): + t0 = time.perf_counter() + for _ in range(n): + fn(A, B) + best = min(best, time.perf_counter() - t0) + return best + + n = 200 + t_rust = _best(core_rs.geometric_product, n) + t_py = _best(py_gp, n) + speedup = t_py / t_rust + # Real measured speedup on Apple M-series is ~400-500×; assert a conservative + # ≥10× so the gate is robust to CI timing noise while still failing loudly if + # the fast path regresses to the Python order of magnitude. + assert speedup >= 10.0, f"Rust f32 GP only {speedup:.1f}× faster than Python (< 10×)" + + +# --- _content_id collision-resistance ------------------------------------- + + +def test_content_id_is_full_256_bit_no_truncation(): + cid = _content_id({"kind": "x", "n": 1}) + assert len(cid) == 64 # 256-bit, not a 16-hex (2^32) truncation + assert all(c in "0123456789abcdef" for c in cid) + + +def test_content_id_is_type_and_structure_faithful(): + # distinct payloads that a weak/str-collapsed digest could conflate: + assert _content_id({"a": 1}) != _content_id({"a": "1"}) # int vs str + assert _content_id({"a": True}) != _content_id({"a": 1}) # bool vs int + assert _content_id({"a": {"b": 1}}) != _content_id({"a": {"b": 2}}) # nested + # key order must NOT matter (canonical sort_keys), but content must: + assert _content_id({"a": 1, "b": 2}) == _content_id({"b": 2, "a": 1}) + + +def test_content_id_fails_closed_on_non_serializable(): + # No default=str: a non-serializable payload raises instead of silently + # collapsing distinct objects onto one id (ADR-0245 §2.3 semantic rigor). + with pytest.raises(TypeError): + _content_id({"x": object()}) + + +def test_psi_digest_is_full_and_sensitive(): + p1 = np.zeros(32, dtype=np.float64) + p1[1] = 1.0 + p2 = np.zeros(32, dtype=np.float64) + p2[1] = 1.0 + 1e-12 # a sub-epsilon perturbation must still change the id + assert len(_psi_digest(p1)) == 64 + assert _psi_digest(p1) != _psi_digest(p2) + assert _psi_digest(p1) == _psi_digest(p1.copy()) # deterministic + + +# --- coverage manifest (legibility of the 4-assertion gate) --------------- + + +def test_acceptance_gate_coverage_manifest(): + """The four §3 criteria and where each is proven — a failing import here + means an acceptance leg lost its home.""" + import pathlib + + tests_dir = pathlib.Path(__file__).parent + coverage = { + "parity_f64": tests_dir / "test_geometric_product_f64_parity.py", + "parity_f32": tests_dir / "test_geometric_product_rust_parity.py", + "zero_lapack_on_repeat": tests_dir / "test_adr_0244_mechanical_sympathy.py", + "f32_speedup_ge_10x": pathlib.Path(__file__), + "content_id_collision_resistance": pathlib.Path(__file__), + } + for name, path in coverage.items(): + assert path.exists(), f"acceptance leg {name!r} missing its test file {path}"