#!/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())