Oracle src/rune/event_envelope.py 303 lines / 8 fns: 5/8 -> 8/8
per scripts/dichotomy_audit.py (name-preserving match). The three
audit-named gaps land as Go surface in src/go/event-bus: ToDict
(to_dict), ToCanonicalDict (to_canonical_dict, incl. the loud
RuntimeError branch for un-bridged envelopes), TestEnvelope
(test_envelope), plus the canonical-bridge classmethod CreateEnvelope
(EventEnvelope.create) they depend on: event_type follows the CHANNELS
prior vocabulary (tool -> tool_result) with the prior-or-channel-or-
source-or-unknown fallback chain.
Parity repairs found on the way (all oracle-pinned):
- classifyAuthority/classifyUrgency were word-splitting: bare 'stop'
hit the amendment list (oracle: 'stop doing' is the multi-word
entry; 'Stop everything!' is emergency), 'stop,' and 'unstoppable'
misfired, and the low-urgency list matched 'when'/'you'/'can'/'no'/
'rush' as single words (oracle: 'when you can'/'no rush'; bare
'when' stays normal). Now \b<word>\b semantics with Unicode word
chars ('stopé' never matches).
- pyQuoteEvent had no ensure_ascii: unicode payloads hashed with raw
UTF-8 where the oracle hashes \uXXXX escapes — payload_hash
diverged on every unicode payload.
- createEnvelope now derives text from payload["text"] (oracle
signature; CLI folds --text in).
- minted ids/timestamps go through the no-clock/no-random seams
(EE_FROZEN_NOW + per-op uuid counter) — replayable under pins,
random uuid4-shaped ids in production.
Truth: scripts/gen_event_envelope_truth.py under the
scripts/ee_freeze_seams sitecustomize rig via the shared freeze_truth
harness (83-case envelope, frozen clock + deterministic uuid counter);
byte-identical across regens and freeze_truth --verify x2; embedded
VERBATIM in truth_envelope_test.go TestFrozenEnvelopeTruthReplay +
seam units (\b matcher, ensure_ascii escaping, event_type fallbacks,
loud bridge failure). Live parity 91/91 (scripts/
check_event_envelope_parity.py, PYTHON-json byte compare; negative
control detects divergence). gofmt/vet/go build clean; Python suite
green both pins (25 live + 25 RUNE_*_CORE=python). Dichotomy audit
5/8 PARTIAL -> 8/8 FULL.
266 lines
10 KiB
Python
266 lines
10 KiB
Python
#!/usr/bin/env python3
|
|
"""check_event_envelope_parity.py — live oracle-vs-Go parity sweep for
|
|
the event_envelope gap closure (#2479, contract factory-gap-ee).
|
|
|
|
The frozen envelope (truth_envelope.json, 83 cases) pins the surface
|
|
byte-identically. THIS script drives the LIVE Python oracle (under the
|
|
scripts/ee_freeze_seams rig: frozen clock + deterministic uuid counter)
|
|
and the Go binary (`op` mode, EE_FROZEN_NOW + per-op counter reset)
|
|
across the same branches, comparing the PYTHON-json byte form of every
|
|
result (separators ", "/": ", ensure_ascii, insertion order):
|
|
|
|
* classify_authority / classify_urgency — \b<word>\b regex semantics
|
|
(multi-word "stop doing" vs bare "stop", punctuation adjacency,
|
|
unicode word chars: "stopé" never matches, channel defaults).
|
|
* create_envelope — legacy path: auto authority/urgency, explicit
|
|
overrides, unicode + nested payloads.
|
|
* EventEnvelope.create — canonical bridge: CHANNELS prior vocabulary,
|
|
channel/source/unknown fallback chain, canonical asdict nesting.
|
|
* to_dict — 9-key legacy dict with insertion-ordered payloads.
|
|
* to_canonical_dict — schema_version-first key order,
|
|
content-addressed payload_hash (ensure_ascii hashing), and the loud
|
|
RuntimeError branch for un-bridged envelopes.
|
|
* test_envelope — the in-module self-test's captured stdout.
|
|
* CHANNELS / AUTHORITY_CLASSES — the constant tables.
|
|
|
|
Usage: PYTHONPATH=scripts/ee_freeze_seams:src python3 scripts/check_event_envelope_parity.py
|
|
[--bin src/go/event-bus/event-bus]
|
|
Exit 0 on 100% parity, 1 with the first divergences.
|
|
"""
|
|
|
|
import argparse
|
|
import json
|
|
import os
|
|
import subprocess
|
|
import sys
|
|
from pathlib import Path
|
|
|
|
REPO = Path(__file__).resolve().parent.parent
|
|
sys.path.insert(0, str(REPO / "src"))
|
|
|
|
FROZEN_NOW = "2026-10-14T11:22:33.123456+00:00"
|
|
|
|
import rune.event_envelope as ee # noqa: E402 (rig active via PYTHONPATH)
|
|
|
|
CLASSIFY_AUTHORITY = [
|
|
("hello there", "conversation"),
|
|
("Fix the failing test", "work"),
|
|
("run the suite", "work"),
|
|
("build it", "conversation"),
|
|
("test everything", "conversation"),
|
|
("create a file", "work"),
|
|
("add the guard", "work"),
|
|
("remove the shim", "work"),
|
|
("update the docs", "work"),
|
|
("change the port", "work"),
|
|
("Stop everything!", "work"),
|
|
("please cancel the order", "work"),
|
|
("abort the run", "work"),
|
|
("emergency shutdown", "work"),
|
|
("halt", "work"),
|
|
("Actually, don't modify the microkernel", "conversation"),
|
|
("dont do that", "conversation"),
|
|
("stop doing that", "work"),
|
|
("use rust instead", "work"),
|
|
("rather use go", "work"),
|
|
("pause for a bit", "work"),
|
|
("wait", "work"),
|
|
("hold", "work"),
|
|
("resume the work", "work"),
|
|
("continue the build", "work"),
|
|
("go", "work"),
|
|
("how is it going", "work"),
|
|
("what is the state", "work"),
|
|
("status?", "work"),
|
|
("progress report", "work"),
|
|
("check the log", "work"),
|
|
("hello", "work"),
|
|
("hello", "conversation"),
|
|
("hello", ""),
|
|
("stop,", "work"),
|
|
("unstoppable force", "work"),
|
|
("stopit now", "work"),
|
|
("", "work"),
|
|
("", "conversation"),
|
|
(" FIX it ", "work"),
|
|
("café stop", "work"),
|
|
("stopé now", "work"),
|
|
("Let's BUILD it, then run tests", "work"),
|
|
("what about the status, and check twice", "work"),
|
|
]
|
|
|
|
CLASSIFY_URGENCY = [
|
|
("anything", "emergency"),
|
|
("urgent please", "directive"),
|
|
("asap", "directive"),
|
|
("immediately", "conversation"),
|
|
("do it now", "directive"),
|
|
("critical issue", "conversation"),
|
|
("when you can", "directive"),
|
|
("no rush", "directive"),
|
|
("eventually", "conversation"),
|
|
("sometime later", "conversation"),
|
|
("when", "directive"),
|
|
("rush", "directive"),
|
|
("hello", "conversation"),
|
|
("", "directive"),
|
|
("NOW please", "directive"),
|
|
("no rushing", "directive"), # \b boundary: "rushing" ≠ "rush"
|
|
]
|
|
|
|
CREATE_ENVELOPE = [
|
|
("user", "conversation", {"text": "hello"}),
|
|
("user", "work", {"text": "Fix the failing test"}),
|
|
("user", "work", {"text": "Stop everything!"}),
|
|
("user", "conversation", {"text": "Actually, don't modify the microkernel"}),
|
|
("user", "work", {"text": "when you can"}),
|
|
("sensor", "sensor", {}),
|
|
("user", "work", {"text": "run it"}, "status_query", "t-42", "low"),
|
|
("user", "conversation", {"text": "hi", "extra": {"nested": [1, 2.5, None, True]}}),
|
|
("user", "work", {"text": "café résumé 🎯", "z": 1, "a": 2}),
|
|
("tool", "tool", {"result": "ok", "code": 0}),
|
|
]
|
|
|
|
CREATE = [
|
|
("user", "conversation", {"text": "hello"}),
|
|
("tool", "tool", {"x": 1}),
|
|
("user", "work", {"text": "Fix it"}),
|
|
("system", "system", {}),
|
|
("bg", "background", {}),
|
|
("sensor", "sensor", {}),
|
|
("user", "", {}),
|
|
("", "", {}),
|
|
("user", "unknown-channel", {"text": "hi"}),
|
|
]
|
|
|
|
TO_DICT_STATES = [
|
|
{"event_id": "evt_abc123def456", "timestamp": FROZEN_NOW,
|
|
"source": "user", "channel": "conversation", "authority_class": "conversation",
|
|
"task_id": None, "payload": {"text": "hi"}, "provenance": {}, "urgency": "normal"},
|
|
{"event_id": "id-2", "timestamp": "2026-10-14T00:00:00+00:00",
|
|
"source": "tool", "channel": "work", "authority_class": "directive",
|
|
"task_id": "t-9", "payload": {"n": 1.5, "b": False, "nil": None, "list": [1, "two"]},
|
|
"provenance": {"origin": "café", "chain": ["a", "b"]}, "urgency": "high"},
|
|
{"event_id": "id-3", "timestamp": FROZEN_NOW,
|
|
"source": "user", "channel": "", "authority_class": "",
|
|
"task_id": None, "payload": {}, "provenance": {"k": "v"}, "urgency": "low"},
|
|
]
|
|
|
|
TO_CANONICAL = [
|
|
("user", "conversation", {"text": "hello"}),
|
|
("tool", "tool", {"x": 1, "a": 2.0}),
|
|
("user", "work", {"text": "café résumé", "z": 1, "a": [True, None]}),
|
|
("system", "system", {}),
|
|
("bg", "background", {"nested": {"deep": [{"k": "v"}, 7]}}),
|
|
]
|
|
|
|
|
|
def run_go(binpath, env, req):
|
|
p = subprocess.run([str(binpath), "op"], input=json.dumps(req),
|
|
capture_output=True, text=True, env=env)
|
|
if p.returncode != 0:
|
|
raise RuntimeError(f"go op {req.get('op')} exited {p.returncode}: "
|
|
f"{p.stdout} {p.stderr}")
|
|
return json.loads(p.stdout)["json"]
|
|
|
|
|
|
def main():
|
|
ap = argparse.ArgumentParser()
|
|
ap.add_argument("--bin", default=str(REPO / "src/go/event-bus/event-bus"))
|
|
args = ap.parse_args()
|
|
binpath = Path(args.bin)
|
|
if not binpath.exists():
|
|
print(f"Go binary missing: {binpath} (go build -o event-bus . in src/go/event-bus)")
|
|
return 1
|
|
|
|
go_env = dict(os.environ)
|
|
go_env["EE_FROZEN_NOW"] = FROZEN_NOW
|
|
go_env.pop("EE_UUID_BASE", None)
|
|
|
|
fails = total = 0
|
|
|
|
def check(name, oracle_json, go_json):
|
|
nonlocal fails, total
|
|
total += 1
|
|
if oracle_json != go_json:
|
|
fails += 1
|
|
print(f"DIVERGE {name}:\n oracle: {oracle_json[:300]}\n"
|
|
f" go: {go_json[:300]}")
|
|
|
|
# classify — public fns (no mints; live semantics)
|
|
for text, channel in CLASSIFY_AUTHORITY:
|
|
check(f"classify_authority:{text[:30]!r}",
|
|
json.dumps(ee.classify_authority(text, channel)),
|
|
run_go(binpath, go_env, {"op": "classify_authority",
|
|
"text": text, "channel": channel}))
|
|
for text, authority in CLASSIFY_URGENCY:
|
|
check(f"classify_urgency:{text[:30]!r}",
|
|
json.dumps(ee.classify_urgency(text, authority)),
|
|
run_go(binpath, go_env, {"op": "classify_urgency",
|
|
"text": text, "authority_class": authority}))
|
|
|
|
# create_envelope — rig seam (per-call mint reset) vs op (per-op reset)
|
|
for row in CREATE_ENVELOPE:
|
|
source, channel, payload = row[0], row[1], row[2]
|
|
req = {"op": "create_envelope", "source": source, "channel": channel,
|
|
"payload": payload}
|
|
if len(row) > 3:
|
|
req["authority_class"] = row[3]
|
|
if len(row) > 4:
|
|
req["task_id"] = row[4]
|
|
if len(row) > 5:
|
|
req["urgency"] = row[5]
|
|
check(f"create_envelope:{source}/{channel}/{str(payload)[:30]}",
|
|
json.dumps(ee.ee_create_envelope(*row)),
|
|
run_go(binpath, go_env, req))
|
|
|
|
# EventEnvelope.create — canonical bridge
|
|
for source, channel, payload in CREATE:
|
|
check(f"create:{source}/{channel}",
|
|
json.dumps(ee.ee_create(source, channel, payload)),
|
|
run_go(binpath, go_env, {"op": "create", "source": source,
|
|
"channel": channel, "payload": payload}))
|
|
|
|
# to_dict — explicit states (insertion-ordered payloads byte-compared)
|
|
for state in TO_DICT_STATES:
|
|
full = dict(state)
|
|
full["_canonical"] = None
|
|
check(f"to_dict:{state['event_id']}",
|
|
json.dumps(ee.ee_to_dict(full)),
|
|
run_go(binpath, go_env, {"op": "to_dict", "state": full}))
|
|
|
|
# to_canonical_dict — bridged
|
|
for source, channel, payload in TO_CANONICAL:
|
|
check(f"to_canonical_dict:{source}/{channel}/{str(payload)[:30]}",
|
|
json.dumps(ee.ee_to_canonical_dict(source, channel, payload)),
|
|
run_go(binpath, go_env, {"op": "to_canonical_dict", "source": source,
|
|
"channel": channel, "payload": payload}))
|
|
|
|
# to_canonical_dict — unbridged loud failure
|
|
state = dict(TO_DICT_STATES[0])
|
|
state["_canonical"] = None
|
|
check("to_canonical_dict:unbridged",
|
|
json.dumps(ee.ee_to_canonical_dict_unbridged(state)),
|
|
run_go(binpath, go_env, {"op": "to_canonical_dict_unbridged",
|
|
"state": state}))
|
|
|
|
# test_envelope — captured stdout
|
|
check("test_envelope",
|
|
json.dumps(ee.ee_test_envelope()),
|
|
run_go(binpath, go_env, {"op": "test_envelope"}))
|
|
|
|
# constant tables
|
|
check("channels",
|
|
json.dumps(ee.ee_channels()),
|
|
run_go(binpath, go_env, {"op": "channels"}))
|
|
check("authority_classes",
|
|
json.dumps(ee.ee_authority_classes()),
|
|
run_go(binpath, go_env, {"op": "authority_classes"}))
|
|
|
|
print(f"parity: {total - fails}/{total} match")
|
|
return 1 if fails else 0
|
|
|
|
|
|
if __name__ == "__main__":
|
|
sys.exit(main())
|