Files
rune/scripts/check_inference_trace_parity.py
Nick a3b6544be8 feat(inference_trace): close PARTIAL gaps — dichotomy wave
audit 4/6 PARTIAL -> 8/8 FULL (RUST). The landed FULL port (b5228ace +
e41562aa) left record_trace/read_traces as facade-side IO by its strangler
verdict; this close ports them name-preserving with the file IO itself in
the kernel (mkdir, I1 source-guard rotation replace chain, O_APPEND write,
file reads; path RESOLUTION stays the _trace_path seam the tests pin, and
the facade passes module rotation knobs read at call time so the
TRACE_ROTATE_BYTES monkeypatch contract survives). FFI it_record_trace /
it_read_traces + it_loader wrappers + byte-identical _py_record_trace /
_py_read_traces fallbacks (RUNE_IT_CORE=python pin).

Fix-first (proved by frozen truth): (1) serialize/format_record ensure_ascii
divergence — json.dumps escapes non-ASCII as \uXXXX (astral = surrogate
pairs), serde emitted raw UTF-8; py_escape emitter added for both shapes
(quirk #24, extends the context_broker pyDumpsSorted law). (2) limit=0 —
Python lines[-0:] keeps ALL lines, rev().take(0) returned none; read_select
+ cli_tail fixed (quirk #25). (3) malformed JSONL line silently skipped by
read_select where the oracle raises ValueError — now an Err through the FFI
envelope so the facade fallback re-raises the AUTHENTIC exception (quirk
#26; crash class pinned in truth).

Frozen truth: 17-case gap corpus via the shared freeze_truth.py harness +
scripts/it_freeze_seams rig (RUNE_IT_CORE=python, relative RUNE_HOME,
cwd-is-the-rig, row-private it_t stores; record/read branches incl.
rotation matrix + unicode line law + limit 0/2/99 + missing stores +
ValueError class + round-trip). gen x2 + --verify x2 byte-identical.
Battery: gap_battery.rs replays rows VERBATIM in a throwaway cwd (cargo
test 9/9: old 6 + new 3). Live parity scripts/check_inference_trace_parity
.py: seam 17/17 + FFI composites 17/17. Landed PARITY=1 flow preserved
(byte-identical modulo the original freeze's baked worktree root). cargo
build/clippy -D warnings/fmt clean. Python suite both pins 108/108 live +
108/108 RUNE_IT_CORE=python (p1_03 memory_selection failures pre-exist at
pristine HEAD, outside this port's cone). Audit: FULL 65% (125/192).

Evidence: verification/it-*.exit + summary-inference_trace.md (logs local,
*.log gitignored).
2026-10-14 20:58:18 +01:00

135 lines
5.2 KiB
Python

#!/usr/bin/env python3
"""check_inference_trace_parity — live-parity replay for the
inference_trace dichotomy gap-close (worktree rune-wave-dk).
Two passes over the gap truth (frozen_it_gap_truth.json, generated from
the pristine Python oracle under scripts/it_freeze_seams):
PASS 1 (seam, live delegation): replay every row through the module's
JSON runners with RUNE_IT_CORE unset — record_trace/read_traces
delegate their file IO to the freshly built Rust core (the
production strangler path: the facade resolves the path, the
kernel mkdirs/rotates/appends/reads).
PASS 2 (FFI composites): drive it_loader.record_trace /
it_loader.read_traces directly at the row-built paths, assembling
the record fruit (dir walk) on this side — proving the kernel's
own IO bytes match the oracle-frozen expectations. The record
payload carries the full dataclass shape (asdict(InferenceTrace)),
mirroring the production facade.
RUNE_HOME is pinned relative and the cwd is a fresh throwaway per pass
(rows speak cwd-relative paths). Exit 0 iff every compared row matches
the frozen expected byte-for-byte (semantic JSON compare, sorted keys).
"""
from __future__ import annotations
import json
import os
import sys
import tempfile
from dataclasses import asdict
from pathlib import Path
REPO = Path(__file__).resolve().parents[1]
os.environ.pop("RUNE_IT_CORE", None) # live: the facade must delegate
os.environ["RUNE_HOME"] = "it_rig_home"
sys.path.insert(0, str(REPO / "src"))
os.chdir(tempfile.mkdtemp(prefix="it-parity-"))
from rune import it_loader # noqa: E402
from rune import inference_trace as it # noqa: E402
TRUTH = REPO / "src" / "rust" / "inference_trace" / "src" / "frozen_it_gap_truth.json"
def same(a, b) -> bool:
return json.dumps(a, sort_keys=True) == json.dumps(b, sort_keys=True)
def row_dir(row) -> Path:
kw = row["kwargs"]
td = row["args"][1] if row["fn"] == "record_trace_json" else row["args"][0]
if td is not None:
return Path(td)
return Path(kw.get("rune_home", "")) / "state"
def fruit(base: Path) -> dict:
files = {}
if base.is_dir():
for p in sorted(base.rglob("*")):
if p.is_file():
files[str(p)] = p.read_text(encoding="utf-8")
return files
def main() -> int:
assert it_loader.available(), "Rust core .so not built (cargo build --release)"
it_loader._load()
rows = json.loads(TRUTH.read_text())
seam_failures: list[str] = []
ffi_failures: list[str] = []
ffi_skipped = 0
# ── PASS 1: the seam with live delegation ────────────────────────────
for i, row in enumerate(rows):
fn, args, kwargs = row["fn"], row["args"], row["kwargs"]
got = getattr(it, fn)(*args, **kwargs)
if not same(got, row["expected"]):
seam_failures.append(
f"row {i} {fn}: {json.dumps(got, sort_keys=True)[:200]} != "
f"{json.dumps(row['expected'], sort_keys=True)[:200]}")
# ── PASS 2: the FFI composites via it_loader ─────────────────────────
# fresh cwd: pass 1 realized every row's writes; the composites must
# see the same virgin state the oracle froze
os.chdir(tempfile.mkdtemp(prefix="it-parity-ffi-"))
for i, row in enumerate(rows):
fn, kwargs = row["fn"], row["kwargs"]
base = row_dir(row)
path = base / it.TRACE_FILENAME
try:
if fn == "record_trace_json":
it._py_seed(kwargs.get("prestate"))
got = {
"path": it_loader.record_trace(
asdict(it.InferenceTrace(**row["args"][0])), str(path),
kwargs.get("rotate_bytes", it.TRACE_ROTATE_BYTES),
kwargs.get("backups", it.TRACE_BACKUPS)),
"files": fruit(base),
}
elif fn == "read_traces_json":
it._py_seed(kwargs.get("prestate"))
try:
got = {"ok": True,
"records": it_loader.read_traces(str(path),
kwargs.get("limit"))}
except RuntimeError:
got = {"ok": False, "err_kind": "ValueError"}
else:
ffi_skipped += 1
continue
except RuntimeError as e:
got = {"error": str(e)}
if not same(got, row["expected"]):
ffi_failures.append(
f"row {i} {fn}: {json.dumps(got, sort_keys=True)[:200]} != "
f"{json.dumps(row['expected'], sort_keys=True)[:200]}")
total = len(rows)
print(f"pass1 seam-live: {total - len(seam_failures)}/{total} rows match")
print(f"pass2 ffi-composite: {total - ffi_skipped - len(ffi_failures)}"
f"/{total - ffi_skipped} rows match ({ffi_skipped} skipped by design)")
for f in seam_failures + ffi_failures:
print("FAIL", f)
ok = not seam_failures and not ffi_failures
print("PARITY OK" if ok else "PARITY FAILED")
return 0 if ok else 1
if __name__ == "__main__":
sys.exit(main())