Kernel port of the 6 audit-gap fns (now_iso, connect, resolve_entity,
add_edge, query, stats) + handle_hook into src/rust/graph_memory (was a
W6 stub): the write-time gating (gm_strength_to_conf — exact float
semantics incl. the 3.5->0.8200000000000001 artifact, unlike the Go
twin's 2-decimal rounding), pred vocabulary gate (gm_normalize_pred),
node-type fallback (gm_node_type), duplicate-vs-supersede decision
(gm_supersede), 400-char evidence cap (gm_trim_evidence), query-fact
projection (gm_query_fact), stats top-8 projection (gm_stats), hook
contract (gm_handle_hook). SQLite IO stays Python (every oracle fn
takes a live db handle); the facade (graph_memory.py) delegates the
decisions through gm_loader with RUNE_GRAPH_MEMORY_CORE=python pin
honor; the probe is _core (machinery-excluded).
Truth: frozen_truth.json 38 cases (scripts/gen_graph_memory_truth.py
under scripts/gm_freeze_seams — wiped-per-process hermetic store,
RUNE_MEMORY_DIR pin, envelope clock) — byte-identical across
generation and two --verify runs. Rust battery 2/2 with the truth
embedded via include_str! (scripted store mirrors the SQL semantics
row for row: OR-IGNORE aliases, sqlite_sequence in the connect shape).
Live parity 1330/1330 (15 frozen FFI rows + 1310 fuzz checks over 60
seeded op-sequences dual-mode python-pin vs live core + 5 live
supersession-chain checks). clippy --all-targets -D warnings 0.
Python suite both pins: test_graph_health+test_graph_projection
7 passed + 1 pre-existing worktree-only failure (store cache
current.json missing — verified identical on stashed base);
test_p1_03 baseline 23 pre-existing failures identical on stashed
base (zero regressions). ruff clean.
Audit: graph_memory 2/9 PARTIAL -> 9/9 FULL (RUST); headline
FULL 43% (83/192), fn 64% (1447/2278).
Evidence: verification/gm_*.{log,exit} (all exit 0 except the two
pre-existing pytest baselines).
122 lines
5.5 KiB
Python
122 lines
5.5 KiB
Python
#!/usr/bin/env python3
|
|
"""gen_graph_memory_truth.py — factory wave GAP truth for graph_memory.
|
|
|
|
Freezes the oracle behavior of the 6 audit-gap functions (dichotomy wave
|
|
#2479: now_iso, connect, resolve_entity, add_edge, query, stats) through
|
|
the SHARED harness (scripts/freeze_truth.py — one law).
|
|
|
|
Runs under the freeze rig (scripts/gm_freeze_seams/sitecustomize.py —
|
|
PYTHONPATH-imported by BOTH this generator and --verify): RUNE_MEMORY_DIR
|
|
pinned to a wiped-per-process hermetic scratch, the clock pinned via
|
|
RUNE_FROZEN_NOW (the harness patches the oracle's module-global datetime),
|
|
and the gm_* seams that drive the REAL db-carrying fns on the hermetic
|
|
connection with JSON-safe shapes.
|
|
|
|
Run (from the repo root):
|
|
PYTHONHASHSEED=0 RUNE_FROZEN_NOW=2026-10-13T12:00:00 \
|
|
PYTHONPATH=scripts/gm_freeze_seams:src \
|
|
python3 scripts/gen_graph_memory_truth.py
|
|
|
|
Verify (byte-identical, same rig — the envelope carries frozen_now):
|
|
PYTHONHASHSEED=0 PYTHONPATH=scripts/gm_freeze_seams:src \
|
|
python3 scripts/freeze_truth.py --verify \
|
|
src/rust/graph_memory/frozen_truth.json \
|
|
--module rune.graph_memory
|
|
|
|
Case map (every gap branch):
|
|
* now_iso — seconds-precision shape (frozen clock; fractional dropped).
|
|
* gm_connect — DDL shape (entities/aliases/edges tables exist).
|
|
* strength_to_conf — direct kernel: below-floor (2, 2.9, 0, -1), floor
|
|
(3->0.76), mid (4->0.88, 3.5 float artifact), ceiling (5->0.99,
|
|
6/100 capped), unparseable (None, "x", "", object) -> None.
|
|
* gm_resolve — create (person type kept), alias-hit (case-insensitive),
|
|
unknown-type fallback (concept), empty/blank -> None.
|
|
* gm_add_edge — unknown pred refused (False), gated strength (False),
|
|
None-confidence+None-strength refused (False), happy path (True),
|
|
duplicate re-add (True, no new row), stronger re-add (True,
|
|
supersedes), self-loop refused (False), empty-subj refused (False),
|
|
pred normalization ("Works On" -> works_on), evidence cap (400).
|
|
* gm_query — exact hit (facts projected, timestamps "TS"), alias hit,
|
|
substring fallback, miss -> [], empty -> [].
|
|
* gm_stats — counts + top-8 predicates after the seeded writes.
|
|
"""
|
|
|
|
import sys
|
|
from pathlib import Path
|
|
|
|
REPO = Path(__file__).resolve().parents[1]
|
|
sys.path.insert(0, str(REPO / "scripts"))
|
|
|
|
from freeze_truth import freeze, write_envelope # noqa: E402
|
|
|
|
import rune.graph_memory as oracle # noqa: E402
|
|
|
|
FROZEN_NOW = "2026-10-13T12:00:00"
|
|
|
|
cases = [
|
|
# now_iso: seconds-precision shape under the frozen clock.
|
|
("now_iso", (), {}),
|
|
# gm_connect: the DDL shape on the pinned dir.
|
|
("gm_connect", (), {}),
|
|
# strength_to_conf: the gating kernel, every branch.
|
|
("strength_to_conf", (2,), {}),
|
|
("strength_to_conf", (2.9,), {}),
|
|
("strength_to_conf", (0,), {}),
|
|
("strength_to_conf", (-1,), {}),
|
|
("strength_to_conf", (3,), {}),
|
|
("strength_to_conf", (4,), {}),
|
|
("strength_to_conf", (5,), {}),
|
|
("strength_to_conf", (3.5,), {}),
|
|
("strength_to_conf", (6,), {}),
|
|
("strength_to_conf", (100,), {}),
|
|
("strength_to_conf", (None,), {}),
|
|
("strength_to_conf", ("x",), {}),
|
|
("strength_to_conf", ("",), {}),
|
|
("strength_to_conf", ("4",), {}),
|
|
# gm_resolve: create / alias-hit / fallback / empty.
|
|
("gm_resolve", ("Ada Lovelace", "person"), {}),
|
|
("gm_resolve", ("ada lovelace",), {}),
|
|
("gm_resolve", ("Analytical Engine", "machine"), {}),
|
|
("gm_resolve", ("",), {}),
|
|
("gm_resolve", (" ",), {}),
|
|
("gm_resolve", (None,), {}),
|
|
# gm_add_edge: every branch of the gating + supersession machine.
|
|
("gm_add_edge", ("Ada Lovelace", "frobnicate", "Analytical Engine",
|
|
{"confidence": 0.9}), {}),
|
|
("gm_add_edge", ("Ada Lovelace", "builds", "Analytical Engine",
|
|
{"strength": 2}), {}),
|
|
("gm_add_edge", ("Ada Lovelace", "builds", "Analytical Engine", {}), {}),
|
|
("gm_add_edge", ("Ada Lovelace", "builds", "Analytical Engine",
|
|
{"confidence": 0.9, "evidence": "first notes",
|
|
"source": "truth"}), {}),
|
|
("gm_add_edge", ("Ada Lovelace", "builds", "Analytical Engine",
|
|
{"confidence": 0.9, "evidence": "first notes",
|
|
"source": "truth"}), {}),
|
|
("gm_add_edge", ("Ada Lovelace", "builds", "Analytical Engine",
|
|
{"confidence": 0.95, "evidence": "revised notes",
|
|
"source": "truth"}), {}),
|
|
("gm_add_edge", ("Ada Lovelace", "likes", "Ada Lovelace",
|
|
{"confidence": 0.9}), {}),
|
|
("gm_add_edge", ("", "likes", "Analytical Engine",
|
|
{"confidence": 0.9}), {}),
|
|
("gm_add_edge", ("Ada Lovelace", "Works On", "Difference Engine",
|
|
{"confidence": 0.8, "evidence": "e",
|
|
"source": "truth"}), {}),
|
|
("gm_add_edge", ("Ada Lovelace", "knows", "Charles Babbage",
|
|
{"confidence": 0.8, "evidence": "y" * 500,
|
|
"source": "truth"}), {}),
|
|
# gm_query: exact / alias / substring / miss / empty.
|
|
("gm_query", ("Ada Lovelace", 1), {}),
|
|
("gm_query", ("ada lovelace", 1), {}),
|
|
("gm_query", ("Babbage", 1), {}),
|
|
("gm_query", ("Nobody Here", 1), {}),
|
|
("gm_query", ("", 1), {}),
|
|
# gm_stats: counts after the seeded writes.
|
|
("gm_stats", (), {}),
|
|
]
|
|
|
|
truth = freeze("rune.graph_memory", cases, oracle_module="rune.graph_memory")
|
|
write_envelope(FROZEN_NOW, truth,
|
|
REPO / "src" / "rust" / "graph_memory" / "frozen_truth.json")
|
|
print(f"froze {len(truth)} rows -> src/rust/graph_memory/frozen_truth.json")
|