Files
rune/scripts/gen_behavior_truth.py
T
Nick d23000f3f1 feat(behavior): close PARTIAL gaps — dichotomy wave
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).
2026-10-14 04:08:47 +01:00

311 lines
15 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/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'}")