Audit 6/14 → 14/14 FULL (missing fns _bh_core, connect,
_correction_matches_python, _habit_matches_python, _reinforce_rust,
_reinforce_python, list_items, behavior_stats). All ported
name-preserving into src/rust/behavior as REAL public fns, rows-in/
decisions-out — SQLite open/exec IO stays Python (no crate in this
repo links a sqlite driver; the memory_storage precedent):
* _bh_core() -> Option<BhCore> — the core probe, RUNE_BEHAVIOR_CORE=
python pin honored (the in-process core has no load-failure branch).
* connect() -> ConnectSpec — path + WAL pragma + the 7 schema stmts
VERBATIM as sqlite stores them on a fresh oracle connect.
* _correction_matches_python/_habit_matches_python — the inline
Python-pin predicates over row structs.
* _reinforce_rust/_reinforce_python — both oracle halves as one
fetch-row→math→write-back ReinforcePlan (result dict + UPDATE
payload + activation-log row; ts an argument, no-clock law). The
ep-shim's habitmath IS this crate's reinforce math — the battery
replays both names and pins their coincidence.
* list_items — filters, ORDER BY confidence DESC (stable sort = the
sqlite rowid-order tie law, pinned by a frozen tie case), LIMIT,
item_type key law.
* behavior_stats — the five counters over row collections.
Row structs gain the stored columns (created_at/last_reinforced/
supersedes_id, decay_rate/last_activated) for verbatim row replay.
New FFI: bh_connect, bh_core_probe, bh_python_predicates,
bh_reinforce_plan, bh_list_items, bh_behavior_stats (doc-envelope
law, no free symbol).
Truth: gen_behavior_truth.py now pins the clock (RUNE_FROZEN_NOW →
freeze_truth._pin_clock over behavior.datetime) — every timestamp in
the corpus frozen, regeneration byte-identical x2; new sections:
pre-rows for all reinforce cases, 42+36-row predicate matrix, 5 full
list outputs, stats_full row dumps, connect schema (sqlite_master,
sqlite_% filtered), core_probe, tie pin. bh_pure_truth.json: 81-case
freeze_truth envelope corpus — freeze_truth --verify byte-identical.
Divergence documented (oracle behavior, not a bug): the ep kernel's
Num wire law renders integral confidences as JSON integers in RESULT
dicts ("confidence": 1) while sqlite REAL read-back renders 1.0 —
the plan applies the wire law to results, REAL floats to write-backs.
Battery: 17 tests — full pre→final row replay (timestamps verbatim),
schema verbatim, predicate matrix, list/stats verbatim, pure corpus.
clippy --all-targets -D warnings 0. Parity
scripts/check_behavior_parity.py: FROZEN 137/137 pure-fn replay
through the cdylib FFI + LIVE 14/14 facade-vs-pin. Python 7/7 both
pins (delegation live + RUNE_BEHAVIOR_CORE=python).
311 lines
15 KiB
Python
311 lines
15 KiB
Python
#!/usr/bin/env python3
|
||
"""Freeze behavior oracle truth for the Rust port battery
|
||
(dichotomy wave #2479 tranche, batch: behavior; gap-close pass).
|
||
|
||
behavior.py's decision surface (14 fns):
|
||
connect, add_correction, add_habit, match_context, reinforce,
|
||
_reinforce_rust, _reinforce_python, _correction_matches_python,
|
||
_habit_matches_python, _bh_core, list_items, behavior_stats,
|
||
main (CLI — not frozen; argparse/IO), PLUGIN (data — embedded
|
||
verbatim in the crate).
|
||
|
||
The decision math (reinforce counting/confidence/promotion/state) is
|
||
served IN-PROCESS by the Rust evidence_provenance cdylib through
|
||
ep_loader — the oracle IS the strangler shim. The frozen truth pins
|
||
RUNE_BEHAVIOR_CORE=python (the POISONED-TRUTH LAW: a future delegating
|
||
facade must never silently record kernel output as oracle truth).
|
||
|
||
Frozen: add_correction/add_habit return shapes, match_context branch
|
||
matrix (pattern/domain/confidence/match_type/invalid-regex), the
|
||
python-pin predicate matrix (every row × context through
|
||
_correction_matches_python/_habit_matches_python), reinforce branch
|
||
matrix (habit/correction x success/failure/neutral x
|
||
promotion/archival/not-found, WITH pre-rows), list_items filters+
|
||
limits+FULL row outputs, stats counts + the row collections they count,
|
||
connect's schema (sqlite_master DDL, creation order), the _bh_core pin
|
||
probe. SQLite rows replayed as dicts (row_factory=Row -> dict(c)).
|
||
|
||
Clock law: RUNE_FROZEN_NOW pins behavior.datetime (the freeze_truth
|
||
harness clock) — every created_at/last_reinforced/last_activated in the
|
||
corpus is frozen, so regeneration is byte-identical and the battery
|
||
replays timestamps VERBATIM.
|
||
|
||
Outputs:
|
||
/tmp/behavior_truth.json — replayed VERBATIM by
|
||
src/rust/behavior/src/branch_battery.rs
|
||
src/rust/behavior/bh_pure_truth.json — freeze_truth-envelope corpus
|
||
(pure-fn cases; byte-verified via freeze_truth.py --verify)
|
||
"""
|
||
from __future__ import annotations
|
||
|
||
import json
|
||
import os
|
||
import sys
|
||
import tempfile
|
||
from pathlib import Path
|
||
|
||
os.environ["RUNE_BEHAVIOR_CORE"] = "python" # freeze the ORACLE, never the kernel
|
||
|
||
FROZEN_NOW = "2026-10-13T00:00:00"
|
||
os.environ["RUNE_FROZEN_NOW"] = FROZEN_NOW
|
||
|
||
_tmp = tempfile.mkdtemp(prefix="bh-truth-")
|
||
os.environ["RUNE_HOME"] = _tmp
|
||
os.environ["RUNE_MEMORY_DIR"] = os.path.join(_tmp, "memory")
|
||
|
||
sys.path.insert(0, str(Path(__file__).resolve().parents[1] / "src"))
|
||
sys.path.insert(0, str(Path(__file__).resolve().parent))
|
||
|
||
import freeze_truth # noqa: E402 (shared harness: clock pin + envelope)
|
||
|
||
from rune import behavior as bh # noqa: E402
|
||
|
||
freeze_truth._pin_clock(bh) # behavior.datetime -> frozen clock
|
||
|
||
CRATE = Path(__file__).resolve().parents[1] / "src" / "rust" / "behavior"
|
||
|
||
|
||
def row(table, rid):
|
||
db = bh.connect()
|
||
try:
|
||
r = db.execute(f"SELECT * FROM {table} WHERE id=?", (rid,)).fetchone()
|
||
return dict(r) if r else None
|
||
finally:
|
||
db.close()
|
||
|
||
|
||
cases = {"add_correction": [], "add_habit": [], "match": [],
|
||
"reinforce_habit": [], "reinforce_correction": [],
|
||
"list": [], "stats": []}
|
||
|
||
# ── add_correction shapes ─────────────────────────────────────────────
|
||
r = bh.add_correction("say X", "say Y")
|
||
cases["add_correction"].append({"name": "defaults", "args": ["say X", "say Y"],
|
||
"expected": r, "row": row("corrections", r["added"])})
|
||
r = bh.add_correction("orig", "corr", scope_tags={"k": "v"}, domain="shell",
|
||
pattern="shell")
|
||
cases["add_correction"].append({"name": "scoped", "args": ["orig", "corr"],
|
||
"expected": r, "row": row("corrections", r["added"])})
|
||
|
||
# ── add_habit shapes ──────────────────────────────────────────────────
|
||
r = bh.add_habit("trig", "act")
|
||
cases["add_habit"].append({"name": "defaults", "expected": r,
|
||
"row": row("habits", r["added"])})
|
||
r = bh.add_habit("trig2", "act2", name="n", context_tags=["a"],
|
||
min_activations=5)
|
||
cases["add_habit"].append({"name": "full", "expected": r,
|
||
"row": row("habits", r["added"])})
|
||
|
||
# ── match_context branch matrix ───────────────────────────────────────
|
||
# seed: pattern+domain correction, domain-only correction, low-conf
|
||
# correction, pattern-only correction, bad-regex correction, habits
|
||
bh.add_correction("o1", "scoped corr", scope_tags={}, domain="shell",
|
||
pattern="deploy")
|
||
bh.add_correction("o2", "domain corr", scope_tags={}, domain="editor")
|
||
bh.add_correction("o3", "plain corr")
|
||
bh.add_correction("o4", "bad regex corr", pattern="([unclosed")
|
||
low = bh.add_correction("o5", "low conf corr")["added"]
|
||
db = bh.connect()
|
||
db.execute("UPDATE corrections SET confidence=0.2 WHERE id=?", (low,))
|
||
db.commit()
|
||
db.close()
|
||
bh.add_habit("deploy", "run deploy script")
|
||
bh.add_habit("test (unit|e2e)", "run tests")
|
||
bh.add_habit("([broken", "bad regex habit")
|
||
hslow = bh.add_habit("zzz-no-match-ever", "quiet")["added"]
|
||
db = bh.connect()
|
||
db.execute("UPDATE habits SET confidence=0.2 WHERE id=?", (hslow,))
|
||
db.commit()
|
||
db.close()
|
||
|
||
|
||
def match_case(name, context, match_type=None):
|
||
got = bh.match_context(context, match_type=match_type)
|
||
return {"name": name, "context": context, "match_type": match_type,
|
||
"corrections": sorted(c["corrected_behavior"] for c in got["corrections"]),
|
||
"habits": sorted(h["action_template"] for h in got["habits"]),
|
||
"n_corr_fields": sorted(got["corrections"][0].keys()) if got["corrections"] else [],
|
||
"scope_tags_type": type(got["corrections"][0]["scope_tags"]).__name__ if got["corrections"] else None}
|
||
|
||
|
||
cases["match"].append(match_case("pattern-domain-hit", "deploy to shell now"))
|
||
cases["match"].append(match_case("domain-only-miss", "deploy the editor"))
|
||
cases["match"].append(match_case("plain-always", "unrelated chatter here"))
|
||
cases["match"].append(match_case("type-habit-only", "deploy to shell now", "habit"))
|
||
cases["match"].append(match_case("type-correction-only", "deploy to shell now", "correction"))
|
||
cases["match"].append(match_case("habit-regex-hit", "run the unit tests"))
|
||
cases["match"].append(match_case("low-conf-filtered", "zzz-no-match-ever quiet"))
|
||
cases["match"].append(match_case("bad-regex-skipped", "([unclosed anything"))
|
||
|
||
# ── python-pin predicate matrix (gap-close surface) ───────────────────
|
||
# Every correction/habit row present at match time × every match
|
||
# context, through the INLINE oracle predicates — the verbatim replay
|
||
# corpus for _correction_matches_python / _habit_matches_python.
|
||
MATCH_CONTEXTS = [
|
||
"deploy to shell now", "deploy the editor", "unrelated chatter here",
|
||
"run the unit tests", "zzz-no-match-ever quiet", "([unclosed anything",
|
||
]
|
||
_db = bh.connect()
|
||
_corr_rows = [dict(r) for r in _db.execute("SELECT * FROM corrections").fetchall()]
|
||
_habit_rows = [dict(r) for r in _db.execute("SELECT * FROM habits").fetchall()]
|
||
_db.close()
|
||
cases["predicates"] = {
|
||
"corrections": [
|
||
{"context": ctx, "row": dict(c), "context_low": ctx.lower(),
|
||
"matched": bh._correction_matches_python(dict(c), ctx, ctx.lower())}
|
||
for ctx in MATCH_CONTEXTS for c in _corr_rows
|
||
],
|
||
"habits": [
|
||
{"context": ctx, "row": dict(h),
|
||
"matched": bh._habit_matches_python(dict(h), ctx)}
|
||
for ctx in MATCH_CONTEXTS for h in _habit_rows
|
||
],
|
||
}
|
||
|
||
# ── reinforce matrix ──────────────────────────────────────────────────
|
||
def reinf_case(name, item_type, outcome, seed_fn, pre=None, n=1):
|
||
rid = seed_fn()["added"]
|
||
table = "habits" if item_type == "habit" else "corrections"
|
||
if pre:
|
||
db = bh.connect()
|
||
for k, v in pre.items():
|
||
db.execute(f"UPDATE {table} SET {k}=? WHERE id=?", (v, rid))
|
||
db.commit()
|
||
db.close()
|
||
pre_row = row(table, rid)
|
||
outs = [bh.reinforce(rid, outcome, item_type=item_type) for _ in range(n)]
|
||
return {"name": name, "item_type": item_type, "outcome": outcome,
|
||
"pre": pre or {}, "n": n, "pre_row": pre_row,
|
||
"results": outs,
|
||
"final_row": row(table, rid)}
|
||
|
||
|
||
cases["reinforce_habit"].append(reinf_case(
|
||
"success-promotes-at-3", "habit", "success", lambda: bh.add_habit("t1", "a1"), n=3))
|
||
cases["reinforce_habit"].append(reinf_case(
|
||
"failure-counts", "habit", "failure", lambda: bh.add_habit("t2", "a2"), n=2))
|
||
cases["reinforce_habit"].append(reinf_case(
|
||
"neutral-bumps-activation-only", "habit", "neutral",
|
||
lambda: bh.add_habit("t3", "a3"), n=1))
|
||
cases["reinforce_habit"].append(reinf_case(
|
||
"already-active-stays", "habit", "success",
|
||
lambda: bh.add_habit("t4", "a4", min_activations=1), n=2))
|
||
cases["reinforce_habit"].append(reinf_case(
|
||
"min5-gate", "habit", "success",
|
||
lambda: bh.add_habit("t5", "a5", min_activations=5), n=4))
|
||
cases["reinforce_correction"].append(reinf_case(
|
||
"success-plus-point-one", "correction", "success",
|
||
lambda: bh.add_correction("x1", "y1"), n=1))
|
||
cases["reinforce_correction"].append(reinf_case(
|
||
"failure-archives", "correction", "failure",
|
||
lambda: bh.add_correction("x2", "y2"), n=1))
|
||
cases["reinforce_correction"].append(reinf_case(
|
||
"double-failure-floor", "correction", "failure",
|
||
lambda: bh.add_correction("x3", "y3"), n=3))
|
||
cases["reinforce_correction"].append(reinf_case(
|
||
"ceiling-at-one", "correction", "success",
|
||
lambda: bh.add_correction("x4", "y4"), pre={"confidence": 0.95}, n=1))
|
||
cases["reinforce_correction"].append(reinf_case(
|
||
"neutral-noop", "correction", "neutral",
|
||
lambda: bh.add_correction("x5", "y5"), n=1))
|
||
cases["reinforce_habit"].append(
|
||
{"name": "habit-not-found", "item_type": "habit", "outcome": "success",
|
||
"pre": {}, "n": 1, "pre_row": None,
|
||
"results": [bh.reinforce(99991, "success", item_type="habit")],
|
||
"final_row": None})
|
||
cases["reinforce_correction"].append(
|
||
{"name": "correction-not-found", "item_type": "correction",
|
||
"outcome": "success", "pre": {}, "n": 1, "pre_row": None,
|
||
"results": [bh.reinforce(99992, "success", item_type="correction")],
|
||
"final_row": None})
|
||
|
||
# ── list_items filters ────────────────────────────────────────────────
|
||
cases["list"].append({"name": "all-keys",
|
||
"result_keys": sorted(bh.list_items().keys())})
|
||
for t in ("all", "correction", "habit"):
|
||
got = bh.list_items(item_type=t)
|
||
cases["list"].append({"name": f"type-{t}", "keys": sorted(got.keys()),
|
||
"n_corr": len(got.get("corrections", [])),
|
||
"n_hab": len(got.get("habits", []))})
|
||
got = bh.list_items(limit=1)
|
||
cases["list"].append({"name": "limit-1", "n_corr": len(got.get("corrections", [])),
|
||
"n_hab": len(got.get("habits", []))})
|
||
|
||
# ── stats ─────────────────────────────────────────────────────────────
|
||
cases["stats"].append({"name": "counts", "expected": bh.behavior_stats()})
|
||
|
||
# ── gap-close surfaces: tie pin, full rows, list/stats replay ────────
|
||
# Tie law: two lowest-id corrections share the top confidence — SQLite
|
||
# returns rowid order for equal ORDER BY keys; the port's stable sort
|
||
# must reproduce it (pinned here, not assumed).
|
||
db = bh.connect()
|
||
db.execute("UPDATE corrections SET confidence=0.85 WHERE id=(SELECT MIN(id) FROM corrections)")
|
||
db.execute("UPDATE corrections SET confidence=0.85 WHERE id=(SELECT MIN(id) FROM corrections WHERE id > (SELECT MIN(id) FROM corrections))")
|
||
db.commit()
|
||
db.close()
|
||
|
||
_dump_db = bh.connect()
|
||
_all_corrections = [dict(r) for r in _dump_db.execute("SELECT * FROM corrections ORDER BY id").fetchall()]
|
||
_all_habits = [dict(r) for r in _dump_db.execute("SELECT * FROM habits ORDER BY id").fetchall()]
|
||
_n_activations = _dump_db.execute("SELECT COUNT(*) FROM habit_activations").fetchone()[0]
|
||
_dump_db.close()
|
||
|
||
cases["list_full"] = []
|
||
for t, lim in [("all", 20), ("correction", 20), ("habit", 20), ("all", 1), ("all", 3)]:
|
||
got = bh.list_items(item_type=t, limit=lim)
|
||
cases["list_full"].append({
|
||
"name": f"{t}-limit{lim}", "item_type": t, "limit": lim,
|
||
"result": json.loads(json.dumps(got))})
|
||
cases["stats_full"] = {
|
||
"corrections": json.loads(json.dumps(_all_corrections)),
|
||
"habits": json.loads(json.dumps(_all_habits)),
|
||
"activations": _n_activations,
|
||
"stats": bh.behavior_stats(),
|
||
}
|
||
|
||
# ── connect (schema as sqlite stores it) + the _bh_core pin probe ────
|
||
db = bh.connect()
|
||
cases["connect"] = {
|
||
"journal_mode": db.execute("PRAGMA journal_mode").fetchone()[0],
|
||
"schema": [
|
||
{"kind": r["type"], "name": r["name"], "sql": r["sql"]}
|
||
for r in db.execute(
|
||
"SELECT type, name, sql FROM sqlite_master "
|
||
"WHERE sql IS NOT NULL AND name NOT LIKE 'sqlite_%'").fetchall()],
|
||
}
|
||
db.close()
|
||
cases["core_probe"] = {"runes_behavior_core_env": os.environ["RUNE_BEHAVIOR_CORE"],
|
||
"core": bh._bh_core()}
|
||
|
||
truth = {"frozen": "behavior decision surface (reinforce math via ep strangler shim)",
|
||
"frozen_now": FROZEN_NOW,
|
||
"oracle": "src/rune/behavior.py",
|
||
"cases": cases,
|
||
"plugin": bh.PLUGIN}
|
||
|
||
out = Path("/tmp/behavior_truth.json")
|
||
out.write_text(json.dumps(truth, indent=1, default=str) + "\n")
|
||
|
||
# ── freeze_truth-envelope corpus: the PURE fn surface ────────────────
|
||
# (predicates over row dicts + reinforce not-found envelopes + the
|
||
# _bh_core pin probe — byte-verified via freeze_truth.py --verify)
|
||
pure_cases = []
|
||
for ctx in MATCH_CONTEXTS:
|
||
for c in _corr_rows:
|
||
pure_cases.append(("_correction_matches_python", (dict(c), ctx, ctx.lower()), {}))
|
||
for h in _habit_rows:
|
||
pure_cases.append(("_habit_matches_python", (dict(h), ctx), {}))
|
||
pure_cases.append(("reinforce", (99991, "success"), {"item_type": "habit"}))
|
||
pure_cases.append(("reinforce", (99992, "success"), {"item_type": "correction"}))
|
||
pure_cases.append(("_bh_core", (), {}))
|
||
pure_truth = freeze_truth.freeze("rune.behavior", pure_cases, oracle_module="rune.behavior")
|
||
freeze_truth.write_envelope(FROZEN_NOW, pure_truth, CRATE / "bh_pure_truth.json")
|
||
|
||
n = (len(cases["add_correction"]) + len(cases["add_habit"]) + len(cases["match"])
|
||
+ len(cases["reinforce_habit"]) + len(cases["reinforce_correction"])
|
||
+ len(cases["list"]) + len(cases["stats"]))
|
||
print(f"froze {n} cases + {len(cases['predicates']['corrections'])}+"
|
||
f"{len(cases['predicates']['habits'])} predicate rows + "
|
||
f"{len(cases['list_full'])} full lists -> {out}")
|
||
print(f"froze {len(pure_truth)} pure cases -> {CRATE / 'bh_pure_truth.json'}")
|