Files
rune/scripts/qm_shadow.py
T
Nick 33ff9ec4e0
local-review.yml (push) Invalid workflow file
Auto-version and Release / release (push) Successful in 9s
CI Pipeline / lint (push) Failing after 28s
CI Pipeline / go-surface (push) Failing after 18s
CI Pipeline / rust-surface (push) Successful in 4m8s
CI Pipeline / canary (push) Failing after 1m4s
CI Pipeline / best-practices (push) Successful in 6s
CI Pipeline / documentation (push) Successful in 7s
CI Pipeline / type-check (push) Failing after 35s
CI Pipeline / gitea-offline (push) Successful in 18s
CI Pipeline / unit-tests (push) Failing after 8m14s
deploy / deploy (push) Failing after 15m11s
CI Pipeline / required-checks (push) Failing after 1s
CI Pipeline / CI Pipeline / notify-event-bridge (push) Failing after 9s
feat(phase-g): #2447 remaining — CI qualification + fresh shadow evidence for the query_memory authority switch (contract BUILDER-2026-10-08T13:52:55Z-b0fc70)
- ci.yml: query_memory in ALL THREE rust build lists + a shadow step.
- scripts/qm_shadow.py: the honest shadow — the TRUE pre-shim Python oracle
  (recovered from git history 6f44a87~1 — the parity harness pointed at the
  superseded src/rune/query_memory.py, comparing Rust against Rust) vs the
  Rust CLI on the frozen 24-command sequence in isolated HOMEs.
- Fresh evidence: 24/24 commands exact-equal, history.jsonl + topic_stats.json
  byte-parity. The authority switch itself was already landed
  (shared/query_memory.py = AUTHORITY-SWITCHED shim, verification wall green).
2026-10-08 14:59:52 +01:00

159 lines
6.4 KiB
Python

#!/usr/bin/env python3
"""qm_shadow.py — #2447 remaining: the shadow comparison, honestly.
The original parity harness (src/rust/query_memory/parity_test.py) compares
the WRONG Python side now: it points at src/rune/query_memory.py — a file
that no longer exists (the oracle moved to shared/ and was superseded by the
AUTHORITY-SWITCHED shim). A shadow against the shim compares Rust vs Rust.
This harness extracts the TRUE pre-shim Python oracle from git history
(6f44a87~1:shared/query_memory.py, the commit that superseded it) and runs
an identical frozen command sequence through:
- the pre-shim Python oracle (its own CLI, HOME-pinned store)
- the Rust CLI binary (target/release/query_memory, HOME-pinned store)
Comparison (byte-parity laws from the frozen contract):
1. stdout per command
2. history.jsonl — byte parity with ISO timestamps masked
3. topic_stats.json — byte parity (catches float-repr divergence)
Divergence = defect (exit 1). Equal = the shadow evidence for the authority
switch (exit 0).
python3 scripts/qm_shadow.py # fresh shadow run
python3 scripts/qm_shadow.py --print # also dump per-command outputs
"""
from __future__ import annotations
import argparse
import os
import re
import shutil
import subprocess
import sys
import tempfile
from pathlib import Path
REPO = Path("/mnt/workdrive/rune")
PY = sys.executable
PRE_SHIM_REF = "6f44a87~1"
PRE_SHIM_PATH = "shared/query_memory.py"
RS_BIN = REPO / "src/rust/query_memory/target/release/query_memory"
TS_RE = re.compile(r"\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d+)?\+00:00")
SEQUENCE = [
("record", ["memory consolidation test", "--strategy", "consolidated"]),
("record", ["memory retrieval failed", "--strategy", "direct"]),
("record", ["web search results ranking", "--strategy", "direct"]),
("record", ["python file parsing", "--strategy", "ast"]),
("record", ["unknown gibberish xyzzy", "--strategy", "consolidated"]),
("record", ["memory web python", "--strategy", "consolidated"]), # tie-break probe
("record", ["mémoire 取得框架 🧠 test", "--strategy", "consolidated"]), # unicode
("record", ['quotes "back\\slash" and ,commas;', "--strategy", "direct"]),
("record", ["memory recall", "--strategy", "consolidated"]),
("record", ["memory store", "--strategy", "hybrid"]),
("record", ["memory index", "--strategy", "consolidated"]),
("record", ["memory lookup", "--strategy", "direct"]),
("record", ["memory cache", "--strategy", "hybrid"]),
("record", ["memory grep", "--strategy", "consolidated"]),
("record", ["memory embedding", "--strategy", "direct"]),
("record", ["memory vector", "--strategy", "hybrid"]),
("record", ["memory search", "--strategy", "consolidated"]),
("record", ["memory query", "--strategy", "direct"]), # crosses >=10
("rate", ["memory consolidation"]),
("rate", ["web crawling"]),
("rate", ["python unittest"]),
("rate", ["nothing matches here"]),
("health", []),
("stats", []),
]
def _oracle_script(cache: Path) -> Path:
"""Extract the pre-shim oracle from git history (cached per run)."""
if cache.exists():
return cache
r = subprocess.run(
["git", "-C", str(REPO), "show", f"{PRE_SHIM_REF}:{PRE_SHIM_PATH}"],
capture_output=True,
text=True,
timeout=30,
)
if r.returncode != 0 or "QueryMemory" not in r.stdout:
raise RuntimeError(
f"cannot recover the pre-shim oracle from {PRE_SHIM_REF}:{PRE_SHIM_PATH} — "
f"the shadow needs the true Python implementation"
)
cache.parent.mkdir(parents=True, exist_ok=True)
cache.write_text(r.stdout)
return cache
def run(cmd_list: list, home: str) -> tuple[int, str]:
env = dict(os.environ, HOME=home)
p = subprocess.run(cmd_list, env=env, capture_output=True, text=True, timeout=30)
return p.returncode, p.stdout + (f"[stderr: {p.stderr}]" if p.stderr else "")
def main() -> int:
ap = argparse.ArgumentParser()
ap.add_argument("--print", action="store_true", dest="verbose")
args = ap.parse_args()
if not RS_BIN.exists():
raise RuntimeError(f"Rust CLI not built: {RS_BIN}")
with tempfile.TemporaryDirectory(prefix="qm_shadow_") as td:
work = Path(td)
py_home = work / "home_py"
rs_home = work / "home_rs"
py_home.mkdir()
rs_home.mkdir()
oracle = _oracle_script(work / "qm_py_oracle.py")
for label, argv in SEQUENCE:
rc_py, out_py = run([PY, str(oracle), label] + argv, str(py_home))
rc_rs, out_rs = run([str(RS_BIN), label] + argv, str(rs_home))
if rc_py != rc_rs or out_py != out_rs:
print(f"✗ DIVERGENCE at {label} {argv[:1]} (rc {rc_py} vs {rc_rs})")
if args.verbose:
print(f" py: {out_py!r}\n rs: {out_rs!r}")
return 1
# history.jsonl byte parity (timestamps masked)
hist_py = py_home / ".config/opencode/memory/query_memory/history.jsonl"
hist_rs = rs_home / ".config/opencode/memory/query_memory/history.jsonl"
if not hist_py.exists() and not hist_rs.exists():
print("✗ history.jsonl missing in BOTH (sequence never wrote history)")
return 1
h_py = TS_RE.sub("<TS>", hist_py.read_text()) if hist_py.exists() else "<MISSING>"
h_rs = TS_RE.sub("<TS>", hist_rs.read_text()) if hist_rs.exists() else "<MISSING>"
if h_py != h_rs:
print("✗ history.jsonl DIVERGENCE (masked)")
return 1
# topic_stats.json byte parity
st_py = py_home / ".config/opencode/memory/query_memory/topic_stats.json"
st_rs = rs_home / ".config/opencode/memory/query_memory/topic_stats.json"
b_py = st_py.read_bytes() if st_py.exists() else b"<MISSING>"
b_rs = st_rs.read_bytes() if st_rs.exists() else b"<MISSING>"
if b_py != b_rs:
print("✗ topic_stats.json DIVERGENCE (byte)")
return 1
print(
f"SHADOW OK: {len(SEQUENCE)}/{len(SEQUENCE)} commands exact-equal, "
f"history + topic_stats byte-parity (pre-shim oracle vs Rust)"
)
return 0
if __name__ == "__main__":
try:
raise SystemExit(main())
except Exception as e: # noqa: BLE001 — terminal reporter: prints and exits 1
print(f"qm_shadow: {e}", file=sys.stderr)
raise SystemExit(1)