Files
rune/scripts/check_growth_delta_parity.py
T
Nick c8b003e8fe
CI Pipeline / best-practices (push) Successful in 7s
CI Pipeline / documentation (push) Successful in 8s
CI Pipeline / rust-surface (push) Failing after 13s
CI Pipeline / go-surface (push) Failing after 18s
CI Pipeline / gitea-offline (push) Successful in 17s
CI Pipeline / type-check (push) Failing after 43s
CI Pipeline / required-checks (push) Canceled after 0s
CI Pipeline / CI Pipeline / notify-event-bridge (push) Canceled after 0s
Auto-version and Release / release (push) Canceled after 56s
CI Pipeline / lint (push) Canceled after 56s
CI Pipeline / unit-tests (push) Canceled after 56s
CI Pipeline / canary (push) Canceled after 55s
deploy / deploy (push) Canceled after 46s
feat(growth_delta): close PARTIAL gaps — dichotomy wave
parity: every growth_delta kernel ported name-preserving into the
cognition_core broker — _parse_json (fence strip, brace extraction, the
_parse_error degrade), _load_deltas/_save_deltas (parse-or-default, the
exact json.dump indent=2 bytes), _apply_profile (first-near-dup replace,
distinct append), _apply_one (200-char evidence, now-as-argument),
reflect's gate pipeline ([:3] slice, 12-char floor, behavioural-only,
0.6 gate), apply's validation (invalid-json/short/wrong-target/low-conf
branches), handle_hook passthrough, _llm's exact Ollama payload,
_write_store's memory_store argv, _ctx_budget's #28 arithmetic, and the
dict-aware py_near_dup.

fix-first: the facade's _near_dup fed DICTS into the string-only
growth_near_dup kernel, which answered False for every dict pair — live
core and pinned fallback DISAGREED (test_growth_delta_error_paths only
ran pinned, masking it). The new cc_py_near_dup kernel takes dicts-or-
strings; both pins now agree and the previously-masked assertion holds
live.

doc-envelope FFI via cc_free_string (never re-exported); cc_loader pins
argtypes+restype for all 12 new symbols; facade delegation with the
RUNE_COGNITION_CORE=python pin. Battery: 9 tests replay 24 pure +
22 state frozen-oracle cases VERBATIM (include_str!). Live parity 86/86
facade checks both pins; freeze_truth --verify byte-identical both pins.
clippy --all-targets -D warnings 0 (incl. two pre-existing lints the new
toolchain gates: branch_battery module inception, parse_probe format!).
Audit: growth_delta 5/20 → 17/20; the 3 remaining (_store_db env-path,
_cc_core loader probe, _py_growth_profile fallback oracle) stay Python
by law, same calibration as drift_cache.
2026-10-13 10:50:57 +01:00

235 lines
8.8 KiB
Python

#!/usr/bin/env python3
"""check_growth_delta_parity.py — live parity: growth_delta facade under
BOTH core pins vs the frozen oracle truth (dichotomy wave).
Per pin (RUNE_COGNITION_CORE=python and unset → Rust via cc_loader) it
replays every frozen case through the LIVE facade. File seams are tmp
DELTAS_FILE dirs; subprocess/urlopen are stubbed at parity time (nothing
touches the machine store); the clock is frozen.
Usage: python3 scripts/check_growth_delta_parity.py
Exit 0 iff every case matches its frozen expected in BOTH pins.
"""
from __future__ import annotations
import json
import os
import subprocess
import sys
import tempfile
import urllib.request
from datetime import datetime
from pathlib import Path
from types import SimpleNamespace
sys.path.insert(0, str(Path(__file__).resolve().parents[1] / "src"))
sys.path.insert(0, str(Path(__file__).resolve().parents[1] / "scripts"))
import rune.growth_delta as gd # noqa: E402
CRATE = Path(__file__).resolve().parents[1] / "src" / "rust" / "cognition_core" / "src"
EMPTY = {"applied": [], "pending": [], "last_read_back": None}
# NOTE (no-clock law): the facade's wall-clock `applied_at` is NOT logic —
# the apply_one case is normalized to the frozen `now` before comparing;
# apply_ok compares only clock-free fields. The kernel takes `now` as an
# argument, so the Rust battery is exact with zero masking.
FAILS = []
CHECKS = [0]
def call_core(core, fn, *args, **kwargs):
old = os.environ.get("RUNE_COGNITION_CORE")
os.environ["RUNE_COGNITION_CORE"] = core
try:
return getattr(gd, fn)(*args, **kwargs)
finally:
if old is None:
os.environ.pop("RUNE_COGNITION_CORE", None)
else:
os.environ["RUNE_COGNITION_CORE"] = old
def with_file(state, core, fn, *args):
with tempfile.TemporaryDirectory() as td:
path = os.path.join(td, "deltas.json")
if state is not None:
with open(path, "w") as f:
if isinstance(state, dict) and "__raw__" in state:
f.write(state["__raw__"])
else:
json.dump(state, f)
orig = gd.DELTAS_FILE
gd.DELTAS_FILE = path
try:
result = call_core(core, fn, *args)
try:
with open(path) as f:
after = f.read()
except OSError:
after = None
finally:
gd.DELTAS_FILE = orig
return result, after
def check(name, got, want):
CHECKS[0] += 1
g, w = json.dumps(got, sort_keys=True), json.dumps(want, sort_keys=True)
if g == w:
return
FAILS.append(name)
print(f"MISMATCH [{name}]\n got: {g[:240]}\n want: {w[:240]}")
def main() -> int:
for core in ("python", "auto"):
live = call_core(core, "_cc_core") is not None
tag = f"{core}:{'rust' if live else 'py'}"
print(f"== {tag} ==")
truth = json.loads((CRATE / "frozen_growth_delta_truth.json").read_text())
for c in truth:
got = call_core(core, c["fn"], *c["args"], **c["kwargs"])
check(f"{tag}:{c['fn']}", got, c["expected"])
state = json.loads((CRATE / "frozen_growth_delta_state.json").read_text())["cases"]
for c in state["load_deltas"]:
raw = c["input"]["raw"]
seed = None if raw is None else {"__raw__": raw}
got, _ = with_file(seed, core, "_load_deltas")
check(f"{tag}:load:{c['name']}", got, c["expected"])
for c in state["save_deltas"]:
st = json.loads(json.dumps(c["input"]["state"]))
_, after = with_file(None, core, "_save_deltas", st)
check(f"{tag}:save:{c['name']}", after, c["expected"])
for c in state["apply_profile"]:
prof = json.loads(json.dumps(c["input"]["profile"]))
delta = json.loads(json.dumps(c["input"]["delta"]))
action, after = with_file(
{**EMPTY, "profile": prof}, core, "_apply_profile", delta)
check(f"{tag}:profile:{c['name']}",
{"profile": json.loads(after)["profile"], "action": action},
c["expected"])
for c in state["apply_one"]:
i = c["input"]
got, _ = with_file(dict(EMPTY), core, "_apply_one",
i["change"], i["evidence"], i["conf"],
i["target"])
got = {**got, "applied_at": i["now"]} # no-clock law: the
# facade's wall-clock stamp is not logic — normalize to the
# frozen `now` before comparing
check(f"{tag}:apply_one", got, c["expected"])
for c in state["reflect"]:
orig_llm = gd._llm
gd._llm = lambda m: json.dumps({"deltas": c["input"]["deltas"]})
try:
res, _ = with_file(dict(EMPTY), core, "reflect", "material", True)
finally:
gd._llm = orig_llm
check(f"{tag}:reflect:{c['name']}", res["would_apply"],
c["expected"])
c = state["llm"][0]
captured = {}
class Resp:
def read(self):
return b"{}"
def __enter__(self):
return self
def __exit__(self, *exc):
return False
orig_open = urllib.request.urlopen
orig_ctx = gd._ctx_budget
gd._ctx_budget = lambda mid: c["input"]["num_ctx"]
urllib.request.urlopen = lambda req, timeout=0: (
captured.update(data=req.data.decode()), Resp())[1]
try:
call_core(core, "_llm", c["input"]["prompt"])
finally:
urllib.request.urlopen = orig_open
gd._ctx_budget = orig_ctx
check(f"{tag}:llm", captured.get("data"), c["expected"])
c = state["write_store"][0]
argv_cap = {}
orig_run = subprocess.run
subprocess.run = lambda argv, **kw: (
argv_cap.update(argv=list(argv)),
SimpleNamespace(returncode=0))[1]
try:
call_core(core, "_write_store", c["input"]["text"],
c["input"]["topic"])
finally:
subprocess.run = orig_run
check(f"{tag}:store", argv_cap.get("argv", [])[2:], c["expected"][2:])
# ctx_budget through the LIVE facade: the oracle signature only
# exposes model_id (task_kind always "default" there — the
# task-kind branches are kernel-covered by the Rust battery).
# Rows: unknown model (default), cloud, local, small, zero-window.
rows = [("unknown-model", 8192, True),
("cloud-model", 32768, False),
("local-model", 32768, True),
("small-local", 2048, True),
("zero-window", 8192, True)]
for name, window, local in rows:
want = next(c_["expected"] for c_ in state["ctx_budget"]
if c_["input"]["window"] == window
and c_["input"]["local"] == local
and c_["input"]["task_kind"] == "default")
reg = SimpleNamespace()
if window == 8192 and local:
reg.profiles = {}
else:
reg.profiles = {"t": SimpleNamespace(
id=name, context_window=window, local=local)}
import rune
from rune import model_registry as mr
import types as _t
stub = _t.ModuleType("rune.model_registry")
stub.ModelRegistry = lambda: reg
# the real resolve defaults registry=None → its OWN module's
# ModelRegistry; force the stub row explicitly
stub.resolve_context_budget = (
lambda mid, tk="default", registry=None, _r=reg:
mr.resolve_context_budget(mid, tk, registry=_r))
saved = sys.modules.get("rune.model_registry")
rune.model_registry = stub
sys.modules["rune.model_registry"] = stub
try:
got = call_core(core, "_ctx_budget", name)
finally:
if saved is not None:
rune.model_registry = saved
sys.modules["rune.model_registry"] = saved
check(f"{tag}:ctx:{name}", got, want)
res, _ = with_file(dict(EMPTY), core, "apply", json.dumps({
"change": "a valid longer change here", "confidence": 0.9,
"target": "delivery", "evidence": "ev"}))
check(f"{tag}:apply_ok",
[{"change": r["change"], "target": r["target"],
"confidence": r["confidence"]} for r in res.get("applied", [])],
[{"change": "a valid longer change here", "target": "delivery",
"confidence": 0.9}])
bad = len(FAILS)
print(f"{'PASS' if bad == 0 else 'FAIL'}: {CHECKS[0] - bad}/{CHECKS[0]}")
return 1 if bad else 0
if __name__ == "__main__":
sys.exit(main())