Files
rune/scripts/gen_task_gate_truth.py
T

590 lines
21 KiB
Python

#!/usr/bin/env python3
"""gen_task_gate_truth.py — freeze/replay parity truth for task_gate
(dichotomy wave, #2479 tranche).
Freeze mode (default): exercises EVERY public function of the LIVE Python
oracle (src/rune/task_gate.py) across every branch and records
(kernel_input, expected_kernel_output, oracle_return) triples into
src/rust/task_gate/src/frozen_tg_truth.json.
Replay mode (--replay): re-runs the SAME scenarios with the Rust core
delegation active and asserts both kernel-level (loader direct) and
facade-level (oracle functions delegate) parity against the frozen file.
Poisoned-truth law: freeze pins RUNE_TG_CORE=python BEFORE any import.
No-clock law: the wall clock is frozen by patching the datetime symbol in
task_gate, so every kernel payload carries its own `now` and replay is
deterministic regardless of run date.
Boundary: the sqlite IO (connect, the row reads, UPDATE/INSERT) and the
CLI main() stay in the Python facade — the kernel owns the verdict logic
(pattern extraction, regex gate matching, count/threshold/status
transitions, promotion decision, listing projection, hook echo).
list_gates' ORDER BY is decided by sqlite in the facade; the kernel
receives already-ordered rows.
"""
import json
import os
import sqlite3
import sys
import tempfile
from datetime import datetime, timezone
REPO = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
TRUTH_PATH = os.path.join(
REPO, "src", "rust", "task_gate", "src", "frozen_tg_truth.json"
)
REPLAY = "--replay" in sys.argv
if not REPLAY:
os.environ["RUNE_TG_CORE"] = "python" # poisoned-truth law
sys.path.insert(0, os.path.join(REPO, "src"))
sys.path.insert(0, os.path.join(REPO, "src", "rune"))
import task_gate as oracle_mod # noqa: E402
if REPLAY:
import tg_loader # noqa: E402 (kernel-level replay side)
FROZEN_NOW = "2026-10-11T23:00:00.123456+00:00"
class FrozenDatetime(datetime):
@classmethod
def now(cls, tz=None):
assert tz is timezone.utc or tz is None
return datetime(2026, 10, 11, 23, 0, 0, 123456, tzinfo=timezone.utc)
oracle_mod.datetime = FrozenDatetime
_COLS = ("id", "instruction", "pattern", "count", "threshold", "status",
"promoted_at", "created_at", "last_seen")
def fresh_db():
tmp = tempfile.mkdtemp(prefix="tg_truth_")
oracle_mod.DB_PATH = os.path.join(tmp, "task_gate.db")
return oracle_mod.connect()
def seed_rows(pre_rows):
"""Seed explicit rows (dicts with any subset of the columns; count/
threshold/status/pattern/created_at/last_seen default like the oracle
would for a fresh row). Returns rows as full dicts in id order."""
db = fresh_db()
for i, r in enumerate(pre_rows, start=1):
db.execute(
"INSERT INTO instructions (id, instruction, pattern, count,"
" threshold, status, promoted_at, created_at, last_seen)"
" VALUES (?,?,?,?,?,?,?,?,?)",
(
r.get("id", i),
r.get("instruction", "seed instruction %d" % i),
r.get("pattern", r"\bseed\b"),
r.get("count", 1),
r.get("threshold", 3),
r.get("status", "observing"),
r.get("promoted_at"),
r.get("created_at", FROZEN_NOW),
r.get("last_seen", FROZEN_NOW),
),
)
db.commit()
rows = [dict(r) for r in db.execute(
"SELECT * FROM instructions ORDER BY id").fetchall()]
db.close()
return rows
def read_rows():
db = sqlite3.connect(oracle_mod.DB_PATH)
db.row_factory = sqlite3.Row
rows = [dict(r) for r in db.execute(
"SELECT * FROM instructions ORDER BY id").fetchall()]
db.close()
return rows
def kernel_input(rows, text):
return {"instructions": rows, "text": text, "now": FROZEN_NOW}
def expected_record(rows_after, result):
"""Derive the kernel's expected doc purely from oracle behavior."""
if result["matched"]:
row = next(r for r in rows_after if r["id"] == result["id"])
return {"matched": True, "id": row["id"], "count": row["count"],
"status": row["status"], "promoted": result["promoted"],
"last_seen": row["last_seen"]}
row = next(r for r in rows_after if r["id"] == result["id"])
return {"matched": False,
"new_row": {k: row[k] for k in
("instruction", "pattern", "count", "threshold",
"status", "created_at", "last_seen")}}
# ── record_instruction ───────────────────────────────────────────────────────
def r_new_keywords(rec):
rows = seed_rows([])
text = "Always CHECK the benchmark before building"
result = oracle_mod.record_instruction(text)
after = read_rows()
rec("new-keywords-pattern",
kernel_input(rows, text), result, after,
expected_record(after, result))
def r_new_no_keywords(rec):
rows = seed_rows([])
text = "do it"
result = oracle_mod.record_instruction(text)
after = read_rows()
rec("new-no-keywords-fallback-escape",
kernel_input(rows, text), result, after,
expected_record(after, result))
def r_new_fallback_truncate50(rec):
rows = seed_rows([])
text = " AB CD EF GH IJ KL MN OP QR ST UV WX YZ 12 34 56 "
result = oracle_mod.record_instruction(text)
after = read_rows()
rec("new-fallback-truncated-50-stripped",
kernel_input(rows, text), result, after,
expected_record(after, result))
def r_new_regex_special(rec):
rows = seed_rows([])
text = "fix the bug (now)!"
result = oracle_mod.record_instruction(text)
after = read_rows()
rec("new-regex-special-chars",
kernel_input(rows, text), result, after,
expected_record(after, result))
def r_new_unicode(rec):
rows = seed_rows([])
text = "café über always"
result = oracle_mod.record_instruction(text)
after = read_rows()
rec("new-unicode-keywords",
kernel_input(rows, text), result, after,
expected_record(after, result))
def r_new_underscore_digit(rec):
rows = seed_rows([])
text = "v1_2 test_it now"
result = oracle_mod.record_instruction(text)
after = read_rows()
rec("new-underscore-digit-keywords",
kernel_input(rows, text), result, after,
expected_record(after, result))
def r_new_instruction_verbatim(rec):
# the INSERT stores the ORIGINAL text, not the lowered/stripped form
rows = seed_rows([])
text = " ALWAYS check "
result = oracle_mod.record_instruction(text)
after = read_rows()
rec("new-instruction-verbatim-not-stripped",
kernel_input(rows, text), result, after,
expected_record(after, result))
def r_match_observing(rec):
rows = seed_rows([
{"pattern": r"\bcheck\b", "count": 1, "threshold": 3,
"status": "observing"},
])
text = "please CHECK everything"
result = oracle_mod.record_instruction(text)
after = read_rows()
rec("match-observing-increment",
kernel_input(rows, text), result, after,
expected_record(after, result))
def r_match_promote(rec):
rows = seed_rows([
{"pattern": r"\bcheck\b", "count": 2, "threshold": 3,
"status": "observing"},
])
text = "check again"
result = oracle_mod.record_instruction(text)
after = read_rows()
rec("match-promotes-at-threshold",
kernel_input(rows, text), result, after,
expected_record(after, result))
def r_match_already_active(rec):
rows = seed_rows([
{"pattern": r"\bcheck\b", "count": 5, "threshold": 3,
"status": "active", "promoted_at": FROZEN_NOW},
])
text = "check once more"
result = oracle_mod.record_instruction(text)
after = read_rows()
rec("match-already-active-no-promote",
kernel_input(rows, text), result, after,
expected_record(after, result))
def r_match_first_wins(rec):
rows = seed_rows([
{"pattern": r"\bcheck\b", "count": 1, "threshold": 3},
{"pattern": r"\bcheck|everything\b", "count": 1, "threshold": 3},
])
text = "check everything"
result = oracle_mod.record_instruction(text)
after = read_rows()
rec("match-first-row-wins",
kernel_input(rows, text), result, after,
expected_record(after, result))
def r_match_skips_retired(rec):
rows = seed_rows([
{"pattern": r"\bcheck\b", "count": 1, "threshold": 3,
"status": "retired"},
{"pattern": r"\bbenchmark\b", "count": 1, "threshold": 3},
])
text = "check the benchmark"
result = oracle_mod.record_instruction(text)
after = read_rows()
rec("match-skips-retired-row",
kernel_input(rows, text), result, after,
expected_record(after, result))
def r_match_word_boundary(rec):
rows = seed_rows([
{"pattern": r"\bcheck\b", "count": 1, "threshold": 3},
])
text = "the checks all pass"
result = oracle_mod.record_instruction(text)
after = read_rows()
rec("no-match-word-boundary-plural",
kernel_input(rows, text), result, after,
expected_record(after, result))
def r_match_fallback_pattern(rec):
rows = seed_rows([
{"pattern": r"do\ it", "count": 1, "threshold": 3},
])
text = "Do IT now"
result = oracle_mod.record_instruction(text)
after = read_rows()
rec("match-fallback-escaped-space-pattern",
kernel_input(rows, text), result, after,
expected_record(after, result))
def r_match_digit_threshold(rec):
rows = seed_rows([
{"pattern": r"\bship\b", "count": 3, "threshold": 4},
])
text = "ship it"
result = oracle_mod.record_instruction(text)
after = read_rows()
rec("match-count-below-higher-threshold",
kernel_input(rows, text), result, after,
expected_record(after, result))
def r_new_after_nonmatch(rec):
rows = seed_rows([
{"pattern": r"\bdeploy\b", "count": 1, "threshold": 3},
])
text = "release the kraken"
result = oracle_mod.record_instruction(text)
after = read_rows()
rec("new-row-after-existing-nonmatch",
kernel_input(rows, text), result, after,
expected_record(after, result))
# ── check_context ────────────────────────────────────────────────────────────
def c_no_active(rec):
rows = seed_rows([
{"pattern": r"\bcheck\b", "count": 1, "threshold": 3},
{"pattern": r"\bship\b", "count": 3, "threshold": 3,
"status": "retired"},
])
context = "check the ship"
matches = oracle_mod.check_context(context)
rec("ctx-no-active-gates",
{"instructions": rows, "context": context},
matches, None, {"matches": matches})
def c_one_match(rec):
rows = seed_rows([
{"pattern": r"\bcheck\b", "count": 3, "threshold": 3,
"status": "active", "promoted_at": FROZEN_NOW,
"instruction": "always check"},
])
context = "about to check the benchmark"
matches = oracle_mod.check_context(context)
rec("ctx-one-match",
{"instructions": rows, "context": context},
matches, None, {"matches": matches})
def c_multi_match_order(rec):
rows = seed_rows([
{"pattern": r"\bcheck\b", "count": 3, "threshold": 3,
"status": "active", "instruction": "always check"},
{"pattern": r"\bship\b", "count": 7, "threshold": 3,
"status": "active", "instruction": "ship weekly"},
{"pattern": r"\bbenchmark\b", "count": 4, "threshold": 3,
"status": "active", "instruction": "run the benchmark"},
])
context = "check, ship, benchmark"
matches = oracle_mod.check_context(context)
rec("ctx-multi-match-rowid-order",
{"instructions": rows, "context": context},
matches, None, {"matches": matches})
def c_case_insensitive(rec):
rows = seed_rows([
{"pattern": r"\bcheck\b", "count": 3, "threshold": 3,
"status": "active", "instruction": "always check"},
])
context = "CHECK EVERYTHING NOW"
matches = oracle_mod.check_context(context)
rec("ctx-case-insensitive-context",
{"instructions": rows, "context": context},
matches, None, {"matches": matches})
def c_no_match(rec):
rows = seed_rows([
{"pattern": r"\bcheck\b", "count": 3, "threshold": 3,
"status": "active", "instruction": "always check"},
])
context = "deploy to production"
matches = oracle_mod.check_context(context)
rec("ctx-no-match",
{"instructions": rows, "context": context},
matches, None, {"matches": matches})
def c_word_boundary(rec):
rows = seed_rows([
{"pattern": r"\bcheck\b", "count": 3, "threshold": 3,
"status": "active", "instruction": "always check"},
])
context = "the checks pass"
matches = oracle_mod.check_context(context)
rec("ctx-word-boundary-plural-no-match",
{"instructions": rows, "context": context},
matches, None, {"matches": matches})
# ── list_gates ───────────────────────────────────────────────────────────────
def l_empty(rec):
seed_rows([])
gates = oracle_mod.list_gates()
rec("list-empty", {}, gates, read_rows(), None)
def l_order_desc(rec):
seed_rows([
{"pattern": r"\ba\b", "count": 5, "instruction": "five"},
{"pattern": r"\bb\b", "count": 1, "instruction": "one"},
{"pattern": r"\bc\b", "count": 3, "instruction": "three"},
])
gates = oracle_mod.list_gates()
rec("list-ordered-count-desc", {}, gates, read_rows(), None)
def l_ties(rec):
seed_rows([
{"pattern": r"\ba\b", "count": 2, "instruction": "first"},
{"pattern": r"\bb\b", "count": 4, "instruction": "second"},
{"pattern": r"\bc\b", "count": 2, "instruction": "third"},
])
gates = oracle_mod.list_gates()
rec("list-tie-order", {}, gates, read_rows(), None)
def l_null_promoted_at(rec):
seed_rows([
{"pattern": r"\ba\b", "count": 2, "status": "active",
"promoted_at": FROZEN_NOW, "instruction": "active one"},
{"pattern": r"\bb\b", "count": 1, "instruction": "observing one"},
])
gates = oracle_mod.list_gates()
rec("list-null-and-set-promoted-at", {}, gates, read_rows(), None)
# ── promote_gate ─────────────────────────────────────────────────────────────
def p_first(rec):
seed_rows([
{"pattern": r"\ba\b", "count": 1, "instruction": "observing"},
])
ret = oracle_mod.promote_gate(1)
rec("promote-existing-id",
{"id": 1, "now": FROZEN_NOW}, ret, read_rows(),
{"status": "active", "promoted_at": FROZEN_NOW})
def p_unknown_id(rec):
seed_rows([])
ret = oracle_mod.promote_gate(42)
rec("promote-unknown-id",
{"id": 42, "now": FROZEN_NOW}, ret, read_rows(),
{"status": "active", "promoted_at": FROZEN_NOW})
def p_overrides_retired(rec):
seed_rows([
{"pattern": r"\ba\b", "count": 1, "status": "retired",
"instruction": "retired one"},
])
ret = oracle_mod.promote_gate(1)
rec("promote-retired-row-becomes-active",
{"id": 1, "now": FROZEN_NOW}, ret, read_rows(),
{"status": "active", "promoted_at": FROZEN_NOW})
# ── handle_hook ──────────────────────────────────────────────────────────────
def h_default(rec):
ret = oracle_mod.handle_hook("post-build")
rec("hook-plain-event", {"event": "post-build"}, ret, None,
{"status": "ok", "event": "post-build", "handler": "task_gate"})
def h_with_data(rec):
ret = oracle_mod.handle_hook("pre-commit", {"sha": "abc"})
rec("hook-with-data", {"event": "pre-commit"}, ret, None,
{"status": "ok", "event": "pre-commit", "handler": "task_gate"})
def h_empty(rec):
ret = oracle_mod.handle_hook("")
rec("hook-empty-event", {"event": ""}, ret, None,
{"status": "ok", "event": "", "handler": "task_gate"})
GROUPS = [
("record_instruction", [r_new_keywords, r_new_no_keywords,
r_new_fallback_truncate50, r_new_regex_special,
r_new_unicode, r_new_underscore_digit,
r_new_instruction_verbatim, r_match_observing,
r_match_promote, r_match_already_active,
r_match_first_wins, r_match_skips_retired,
r_match_word_boundary, r_match_fallback_pattern,
r_match_digit_threshold, r_new_after_nonmatch]),
("check_context", [c_no_active, c_one_match, c_multi_match_order,
c_case_insensitive, c_no_match, c_word_boundary]),
("list_gates", [l_empty, l_order_desc, l_ties, l_null_promoted_at]),
("promote_gate", [p_first, p_unknown_id, p_overrides_retired]),
("handle_hook", [h_default, h_with_data, h_empty]),
]
# groups where the kernel is involved (list_gates' ordering is sqlite's)
KERNEL_GROUPS = {"record_instruction", "check_context", "promote_gate",
"handle_hook"}
def main():
frozen = None
if REPLAY:
with open(TRUTH_PATH) as f:
frozen = json.load(f)["cases"]
groups = {}
for group, cases in GROUPS:
recs = []
def rec(name, kinput, oracle_ret, rows_after, kexpected, _r=recs):
entry = {"name": name, "input": kinput, "return": oracle_ret,
"expected": kexpected}
if rows_after is not None:
entry["rows_after"] = rows_after
if REPLAY:
old = next(c for c in frozen[group] if c["name"] == name)
for key in ("input", "return", "expected", "rows_after"):
if key not in entry and key not in old:
continue
got, want = entry.get(key), old.get(key)
if json.dumps(got, sort_keys=True) != json.dumps(
want, sort_keys=True):
print(f"FACADE DIVERGE [{group}] {name} {key}")
print(" got: ", json.dumps(got, sort_keys=True)[:600])
print(" want:", json.dumps(want, sort_keys=True)[:600])
recs.append({"name": name, "diverged": key})
return
_r.append(entry)
for c in cases:
c(rec)
groups[group] = recs
total = sum(len(v) for v in groups.values())
if REPLAY:
facade_failures = sum(
1 for v in groups.values() for c in v if "diverged" in c)
failures = 0
for group, cases in frozen.items():
if group not in KERNEL_GROUPS:
continue
for case in cases:
inp = case["input"]
if group == "record_instruction":
got = tg_loader.record_instruction(
inp["instructions"], inp["text"], inp["now"])
elif group == "check_context":
got = tg_loader.check_context(
inp["instructions"], inp["context"])
elif group == "promote_gate":
got = tg_loader.promote_gate(inp["id"], inp["now"])
else:
got = tg_loader.handle_hook(inp["event"])
if json.dumps(got, sort_keys=True) != json.dumps(
case["expected"], sort_keys=True):
failures += 1
print(f"KERNEL DIVERGE [{group}] {case['name']}")
print(" got: ", json.dumps(got, sort_keys=True)[:600])
print(" want:", json.dumps(
case["expected"], sort_keys=True)[:600])
print(f"replay: facade {total - facade_failures}/{total}, "
f"kernel {total - failures}/{total}")
return 1 if (failures or facade_failures) else 0
doc = {
"frozen": datetime.now(timezone.utc).isoformat(),
"oracle": "src/rune/task_gate.py",
"pin": "RUNE_TG_CORE=python",
"note": "Frozen via scripts/gen_task_gate_truth.py against the live "
"Python oracle; wall clock frozen at " + FROZEN_NOW + ". "
"Battery embeds this VERBATIM.",
"cases": groups,
}
os.makedirs(os.path.dirname(TRUTH_PATH), exist_ok=True)
with open(TRUTH_PATH, "w") as f:
json.dump(doc, f, indent=1, sort_keys=True)
f.write("\n")
print(f"frozen {total} cases → {os.path.relpath(TRUTH_PATH, REPO)}")
return 0
if __name__ == "__main__":
sys.exit(main())