feat(warm_router): close PARTIAL gaps — dichotomy wave
Routing/activation/scoring family (builder factory-heavy-wr-route): port the five audit-missing fns into src/go/warm-router/gaps_routing.go (BaseLevelActivation, PrimedAssociations, AssociatedNeuronBodies, GraphContext, RenderFired; I/O-as-args split) + gap-cli parity surface. Fixes two latent defects the frozen battery caught: - warm_router.py _primed_associations passed (limit,) for a statement with len(ids)+1 placeholders — every call raised ProgrammingError and returned [] (the association-neighbour priming walk was dead code). Now binds (*ids, limit). - main.go baseLevelFromUses parsed nowISO with a literal-Z layout, so '+00:00' stamps fell back to the wall clock. Now RFC3339 first. Frozen truth 34 rows (shared freeze_truth harness under scripts/wr_freeze_seams rig) byte-identical on --verify; battery truth_gap_test.go replays all rows; live parity 60/60 (check_warm_router_gap_parity.py); go build/vet/gofmt clean; Python suite green on the delegation pin (python-pin failures pre-exist on the stashed tree — retired-fallback -2.0 degradation, Go-only lane). Family coverage 11/16 -> 16/16; module 17/33 -> 22/33 (remaining 11 are other families' files).
This commit is contained in:
1 parent
7001fce0d2
commit
9102fc2be6
27 files changed
+1708
-2
No files matched your search
@@ -0,0 +1,252 @@
|
||||
#!/usr/bin/env python3
|
||||
"""check_warm_router_gap_parity.py — LIVE parity for the warm_router GO
|
||||
gap port (dichotomy wave #2479, routing/activation/scoring family):
|
||||
drives the Python oracle (src/rune/warm_router.py) and the GO binary's
|
||||
`gap-cli` subcommand through IDENTICAL scenarios and diffs the results.
|
||||
|
||||
The I/O-as-args split: for every DB-backed fn the script runs the oracle
|
||||
function end-to-end, then replays the oracle's OWN gather SQL (copied
|
||||
verbatim — the caller-side contract) and feeds the gathered rows to the
|
||||
Go binary. graph_context's gather is the subprocess payload itself: the
|
||||
script runs the same graph_memory query the oracle spawns, then feeds
|
||||
its stdout JSON to the Go side. render_fired args pass through verbatim.
|
||||
|
||||
Runs under the scripts/wr_freeze_seams rig (hermetic RUNE_MEMORY_DIR +
|
||||
fixtures + pins) and EXTENDS the fixtures deterministically before the
|
||||
scenarios (new entries/associations/use_history rows, a second primed
|
||||
session, an extra graph entity) so the live corpus is strictly larger
|
||||
than the frozen one.
|
||||
|
||||
Usage (build first: cd src/go/warm-router && go build -o /tmp/warm-router-gap .):
|
||||
PYTHONPATH=scripts/wr_freeze_seams python3 scripts/check_warm_router_gap_parity.py /tmp/warm-router-gap
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
import os
|
||||
import sqlite3
|
||||
import subprocess
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
REPO = Path(__file__).resolve().parent.parent
|
||||
sys.path.insert(0, str(REPO / "src" / "rune"))
|
||||
|
||||
import warm_router as wr # noqa: E402 (rig pins env before this import)
|
||||
|
||||
NOW = "2026-10-15T00:00:00+00:00"
|
||||
|
||||
BINARY = sys.argv[1] if len(sys.argv) > 1 else "/tmp/warm-router-gap"
|
||||
|
||||
PASS = 0
|
||||
FAIL = 0
|
||||
|
||||
|
||||
def go(fn: str, *args: str):
|
||||
r = subprocess.run(
|
||||
[BINARY, "gap-cli", fn, *args], capture_output=True, text=True, timeout=30
|
||||
)
|
||||
if r.returncode != 0:
|
||||
raise RuntimeError(f"go gap-cli {fn} rc={r.returncode}: {r.stderr.strip()}")
|
||||
return json.loads(r.stdout)
|
||||
|
||||
|
||||
def check(label: str, want, got) -> None:
|
||||
global PASS, FAIL
|
||||
ok = want == got
|
||||
if isinstance(want, float) and isinstance(got, float):
|
||||
ok = abs(want - got) <= 1e-12
|
||||
if ok:
|
||||
PASS += 1
|
||||
else:
|
||||
FAIL += 1
|
||||
print(f"FAIL {label}:\n oracle: {want!r}\n go: {got!r}")
|
||||
|
||||
|
||||
# ── fixture extension (deterministic, beyond the frozen set) ──
|
||||
|
||||
db = sqlite3.connect(wr.STORE_DB)
|
||||
db.execute(
|
||||
"INSERT INTO entries (id, text, slug, triggers, importance, summary, kind, status) "
|
||||
"VALUES (11, 'omega bridge body', 'omega-bridge', 'omega', 0.75, 'omega bridge summary', 'neuron', 'active')"
|
||||
)
|
||||
db.executemany(
|
||||
"INSERT INTO use_history (entry_id, used_at, session_id, outcome) VALUES (?,?,?,?)",
|
||||
[
|
||||
(11, "2026-10-14T22:00:00+00:00", "s2", "helpful"),
|
||||
(11, "2026-10-14T10:00:00+00:00", "s2", "helpful"),
|
||||
(11, "2026-10-12T10:00:00+00:00", "s2", "ignored"),
|
||||
],
|
||||
)
|
||||
db.executemany(
|
||||
"INSERT INTO associations (src_id, dst_id, strength) VALUES (?,?,?)",
|
||||
[(11, 2, 0.85), (11, 9, 0.45), (11, 8, 0.3), (11, 6, 0.95)],
|
||||
)
|
||||
db.commit()
|
||||
db.close()
|
||||
|
||||
state_path = Path(wr.STATE)
|
||||
state = json.loads(state_path.read_text())
|
||||
state["sessions"]["s2"] = {
|
||||
"primed": {"omega-bridge": 0.6, "beta-lens": 0.2}, "turns": 3,
|
||||
"last_active": "2026-10-14T21:00:00",
|
||||
}
|
||||
state_path.write_text(json.dumps(state, indent=2) + "\n")
|
||||
|
||||
gdb = sqlite3.connect(str(Path(wr.MEM_DIR) / "graph" / "graph.sqlite"))
|
||||
gdb.execute("INSERT INTO entities (id, name, type) VALUES (5, 'Zeke', 'person')")
|
||||
gdb.execute("INSERT INTO edges (subj_id, pred, obj_id, confidence, status) VALUES (5, 'knows', 1, 0.75, 'active')")
|
||||
gdb.execute("INSERT INTO edges (subj_id, pred, obj_id, confidence, status) VALUES (1, 'knows', 5, 0.65, 'active')")
|
||||
gdb.commit()
|
||||
gdb.close()
|
||||
|
||||
|
||||
# ── the oracle's gather SQL (caller-side contract, copied verbatim) ──
|
||||
|
||||
def gather_use_history(entry_id: int) -> list[str]:
|
||||
db = sqlite3.connect(f"file:{wr.STORE_DB}?mode=ro", uri=True)
|
||||
try:
|
||||
rows = db.execute(
|
||||
"SELECT used_at FROM use_history WHERE entry_id = ? ORDER BY used_at DESC LIMIT ?",
|
||||
(entry_id, wr.BASE_LEVEL_MAX_USES),
|
||||
).fetchall()
|
||||
return [r[0] for r in rows]
|
||||
finally:
|
||||
db.close()
|
||||
|
||||
|
||||
def gather_primed_links(session_id: str, limit: int):
|
||||
st = wr.load_state()
|
||||
sess = st.get("sessions", {}).get(session_id) or {}
|
||||
primed = sess.get("primed", {})
|
||||
if not primed:
|
||||
return [], []
|
||||
slugs = list(primed.keys())
|
||||
db = sqlite3.connect(f"file:{wr.STORE_DB}?mode=ro", uri=True)
|
||||
try:
|
||||
ph = ",".join("?" * len(slugs))
|
||||
rows = db.execute(
|
||||
f"SELECT id FROM entries WHERE kind='neuron' AND slug IN ({ph})", slugs
|
||||
).fetchall()
|
||||
ids = [r[0] for r in rows]
|
||||
if not ids:
|
||||
return [], slugs
|
||||
iph = ",".join("?" * len(ids))
|
||||
links = db.execute(
|
||||
"SELECT e.slug, a.strength FROM associations a "
|
||||
"JOIN entries e ON e.id=a.dst_id "
|
||||
f"WHERE a.src_id IN ({iph}) AND a.strength >= 0.3 "
|
||||
"AND e.kind='neuron' AND e.status='active' "
|
||||
"ORDER BY a.strength DESC LIMIT ?",
|
||||
(*ids, limit),
|
||||
).fetchall()
|
||||
return [{"Slug": r[0], "Strength": float(r[1])} for r in links], slugs
|
||||
finally:
|
||||
db.close()
|
||||
|
||||
|
||||
def gather_assoc_links(fired):
|
||||
slugs = [f["slug"] for f in fired]
|
||||
db = sqlite3.connect(f"file:{wr.STORE_DB}?mode=ro", uri=True)
|
||||
try:
|
||||
ph = ",".join("?" * len(slugs))
|
||||
rows = db.execute(
|
||||
f"SELECT id, slug FROM entries WHERE kind='neuron' AND slug IN ({ph})", slugs
|
||||
).fetchall()
|
||||
ids = [r[0] for r in rows]
|
||||
if not ids:
|
||||
return []
|
||||
iph = ",".join("?" * len(ids))
|
||||
links = db.execute(
|
||||
"SELECT a.src_id AS src, a.dst_id AS dst, a.strength, "
|
||||
"e.slug, e.summary, e.text "
|
||||
"FROM associations a JOIN entries e ON e.id=a.dst_id "
|
||||
f"WHERE a.src_id IN ({iph}) AND a.strength >= 0.3 "
|
||||
"AND e.status='active' "
|
||||
"ORDER BY a.strength DESC LIMIT 6",
|
||||
ids,
|
||||
).fetchall()
|
||||
return [{"Slug": r[3], "Summary": r[4] or "", "Text": r[5] or "", "Strength": float(r[2])} for r in links]
|
||||
finally:
|
||||
db.close()
|
||||
|
||||
|
||||
def gather_graph_payload(term: str, hops: int) -> str:
|
||||
r = subprocess.run(
|
||||
[sys.executable, str(Path(wr.__file__).parent / "graph_memory.py"),
|
||||
"query", term, "--hops", str(hops), "--json"],
|
||||
capture_output=True, text=True, timeout=10,
|
||||
)
|
||||
return r.stdout
|
||||
|
||||
|
||||
# ── scenarios ──
|
||||
|
||||
# base_level_activation: entry sweep + pinned clocks (incl. a tz-offset now)
|
||||
for entry_id in (1, 2, 3, 8, 10, 11, 999):
|
||||
for now in (NOW, "2026-10-15T01:00:00+01:00", "2026-10-20T00:00:00+00:00"):
|
||||
want = wr.base_level_activation(entry_id, now_iso=now)
|
||||
got = go("base-level-activation", json.dumps(gather_use_history(entry_id)), now)["score"]
|
||||
check(f"base_level_activation({entry_id}, {now})", float(want), float(got))
|
||||
|
||||
# _primed_associations: sessions + limit sweep
|
||||
for session, limit in (
|
||||
("s1", 4), ("s1", 1), ("s1", 2), ("s1", 99),
|
||||
("s2", 4), ("s2", 2),
|
||||
("s-missing", 4), ("s-empty", 4), ("s-ghost", 4),
|
||||
):
|
||||
want = wr._primed_associations(session, limit)
|
||||
links, slugs = gather_primed_links(session, limit)
|
||||
got = go("primed-associations", json.dumps(links), json.dumps(slugs))
|
||||
want_l = [[s, float(w)] for s, w in want]
|
||||
check(f"_primed_associations({session!r}, {limit})", want_l, got)
|
||||
|
||||
# _associated_neuron_bodies: fired combos × budgets
|
||||
for fired, budget in (
|
||||
([{"slug": "alpha-core"}], 6),
|
||||
([{"slug": "alpha-core"}], 20),
|
||||
([{"slug": "alpha-core"}], 0),
|
||||
([{"slug": "alpha-core"}], 1000),
|
||||
([{"slug": "alpha-core"}, {"slug": "beta-lens"}], 30),
|
||||
([{"slug": "beta-lens"}], 20),
|
||||
([{"slug": "alpha-shadow"}], 20),
|
||||
([{"slug": "gamma-dated"}], 20),
|
||||
([{"slug": "omega-bridge"}], 24),
|
||||
([{"slug": "omega-bridge"}], 8),
|
||||
([{"slug": "retired-one"}], 20),
|
||||
([{"slug": "no-such-slug"}], 20),
|
||||
):
|
||||
want = wr._associated_neuron_bodies(fired, budget)
|
||||
links = gather_assoc_links(fired)
|
||||
fired_slugs = [f["slug"] for f in fired]
|
||||
got = go("associated-neuron-bodies", json.dumps(links), json.dumps(fired_slugs), str(budget))
|
||||
check(f"_associated_neuron_bodies({fired_slugs}, {budget})", want, got)
|
||||
|
||||
# graph_context: terms × hops × limits (gather = the subprocess payload)
|
||||
for term, hops, limit in (
|
||||
("Alice", 1, 4), ("Alice", 2, 4), ("Alice", 1, 1), ("Alice", 1, 0),
|
||||
("Alice", 1, -1), ("Alice", 1, 99),
|
||||
("Al", 1, 4), ("Rune", 1, 4), ("Zeke", 1, 4), ("Nobody", 1, 4),
|
||||
("", 1, 4),
|
||||
):
|
||||
want = wr.graph_context(term, hops=hops, limit=limit)
|
||||
payload = gather_graph_payload(term, hops)
|
||||
got = go("graph-context", payload.replace("\n", " "), term, str(limit))["rendered"]
|
||||
check(f"graph_context({term!r}, {hops}, {limit})", want, got)
|
||||
|
||||
# render_fired: pure args pass through verbatim
|
||||
for fired in (
|
||||
[],
|
||||
[{"slug": "a", "body": "plain"}],
|
||||
[{"slug": "b", "body": "x", "via_association": True}],
|
||||
[{"slug": "c", "body": "y", "compressed": True}],
|
||||
[{"slug": "d", "body": "z", "via_association": True, "compressed": True}],
|
||||
[{"slug": "e", "body": "café — résumé ✓"}, {"slug": "f", "body": "second", "via_association": True}],
|
||||
[{"slug": "g", "body": ""}],
|
||||
):
|
||||
want = wr.render_fired(fired)
|
||||
got = go("render-fired", json.dumps(fired))["rendered"]
|
||||
check(f"render_fired({len(fired)} entries)", want, got)
|
||||
|
||||
print(f"\nparity: {PASS}/{PASS + FAIL}" + (f" ({FAIL} FAILURES)" if FAIL else " — all green"))
|
||||
sys.exit(1 if FAIL else 0)
|
||||
@@ -0,0 +1,103 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Freeze warm_router oracle truth for the GO gap battery (dichotomy wave
|
||||
#2479, routing/activation/scoring family, builder factory-heavy-wr-route)
|
||||
using the shared harness scripts/freeze_truth.py under the
|
||||
scripts/wr_freeze_seams rig (hermetic RUNE_MEMORY_DIR, pinned
|
||||
RUNE_GRAPH_MEMORY_CORE, live MS_RUST_LIB delegation).
|
||||
|
||||
Exercises the five family gap functions and every reachable branch:
|
||||
|
||||
base_level_activation cold start (no entry / no history), ACT-R
|
||||
math (3 rows, 1 row), the db=None default,
|
||||
the non-string used_at -2.0 envelope
|
||||
_primed_associations full link walk (kind='neuron' filter drops
|
||||
the document row), LIMIT, missing session,
|
||||
empty primed, primed slug with no entry
|
||||
_associated_neuron_bodies budget break mid-walk, multi-fit, seen-set
|
||||
skip + empty-body slug burn, immediate
|
||||
break on budget 0, the empty-slug
|
||||
slug-or-assoc row, a back-link walk
|
||||
graph_context dict shape (found entity — entity name from
|
||||
the payload, NOT the term), unknown-entity
|
||||
list shape -> '', hops=2, limit=1, empty
|
||||
term, a second entry node
|
||||
render_fired plain / via_association / compressed tags,
|
||||
both flags (assoc outranks), unicode body,
|
||||
empty list, extra keys ignored
|
||||
|
||||
Run from the repo root (build the memory_scoring kernel first —
|
||||
cd src/rust/memory_scoring && cargo build --release):
|
||||
PYTHONPATH=scripts/wr_freeze_seams python3 scripts/gen_warm_router_gap_truth.py
|
||||
Verify (byte-identical law):
|
||||
PYTHONPATH=src:scripts/wr_freeze_seams python3 scripts/freeze_truth.py \
|
||||
--verify src/go/warm-router/truth_gap.json --module rune.warm_router
|
||||
|
||||
Output: src/go/warm-router/truth_gap.json
|
||||
(harness schema: [{fn, args, kwargs, expected}] — replayed by
|
||||
truth_gap_test.go).
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
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 # noqa: E402
|
||||
|
||||
OUT = REPO / "src" / "go" / "warm-router" / "truth_gap.json"
|
||||
|
||||
NOW = "2026-10-15T00:00:00+00:00"
|
||||
|
||||
CASES = [
|
||||
# ── base_level_activation ────────────────────────────────────────
|
||||
("base_level_activation", (999,), {"now_iso": NOW}), # no entry, no history
|
||||
("base_level_activation", (3,), {"now_iso": NOW}), # entry, never fired
|
||||
("base_level_activation", (1,), {"now_iso": NOW}), # 3 rows (1h/6h/11h)
|
||||
("base_level_activation", (2,), {"db": None, "now_iso": NOW}), # single row + db default
|
||||
("base_level_activation", (8,), {"now_iso": NOW}), # non-string used_at -> -2.0 envelope
|
||||
("base_level_activation", (10,), {"now_iso": NOW}), # 105 rows: the 100-newest scan cap
|
||||
# ── _primed_associations ─────────────────────────────────────────
|
||||
("_primed_associations", ("s1",), {}), # kind filter drops plain-doc
|
||||
("_primed_associations", ("s1", 2), {}), # LIMIT 2
|
||||
("_primed_associations", ("s-missing",), {}), # no session -> []
|
||||
("_primed_associations", ("s-empty",), {}), # nothing primed -> []
|
||||
("_primed_associations", ("s-ghost",), {}), # primed slug with no entry -> []
|
||||
# ── _associated_neuron_bodies ────────────────────────────────────
|
||||
("_associated_neuron_bodies", ([{"slug": "alpha-core"}], 6), {}), # break mid-walk
|
||||
("_associated_neuron_bodies", ([{"slug": "alpha-core"}], 20), {}), # two fit, third breaks
|
||||
("_associated_neuron_bodies", ([{"slug": "alpha-core"}, {"slug": "beta-lens"}], 30), {}), # seen skip + hollow burn
|
||||
("_associated_neuron_bodies", ([{"slug": "alpha-core"}], 0), {}), # immediate break
|
||||
("_associated_neuron_bodies", ([{"slug": "beta-lens"}], 20), {}), # empty-slug -> assoc
|
||||
("_associated_neuron_bodies", ([{"slug": "alpha-shadow"}], 20), {}), # back-link walk
|
||||
("_associated_neuron_bodies", ([{"slug": "gamma-dated"}], 20), {}), # unicode body: rune-count tokens
|
||||
# ── graph_context ────────────────────────────────────────────────
|
||||
("graph_context", ("Alice",), {}), # dict shape; entity from payload
|
||||
("graph_context", ("Al",), {}), # alias resolves; header says Alice
|
||||
("graph_context", ("Nobody",), {}), # list shape ([]) -> ''
|
||||
("graph_context", ("Alice", 2), {}), # 2 hops
|
||||
("graph_context", ("Alice", 1, 1), {}), # limit 1
|
||||
("graph_context", ("Alice", 1, 0), {}), # limit 0 -> facts[:0] -> ''
|
||||
("graph_context", ("Alice", 1, -1), {}), # negative limit: facts[:-1]
|
||||
("graph_context", ("",), {}), # empty term -> ''
|
||||
("graph_context", ("Rune",), {}), # second entry node
|
||||
# ── render_fired ─────────────────────────────────────────────────
|
||||
("render_fired", ([{"slug": "alpha-core", "body": "Full body text."}],), {}),
|
||||
("render_fired", ([{"slug": "via", "body": "b", "via_association": True}],), {}),
|
||||
("render_fired", ([{"slug": "c", "body": "b", "compressed": True}],), {}),
|
||||
("render_fired", ([{"slug": "both", "body": "b", "via_association": True, "compressed": True}],), {}),
|
||||
("render_fired", ([{"slug": "u", "body": "café — résumé ✓", "via_association": False}],), {}),
|
||||
("render_fired", ([],), {}),
|
||||
("render_fired", ([{"slug": "no-flags", "body": "x", "extra_ignored": 1}],), {}),
|
||||
]
|
||||
|
||||
|
||||
def main() -> None:
|
||||
truth = freeze("warm_router", CASES, oracle_module="rune.warm_router")
|
||||
write(truth, OUT)
|
||||
print(f"frozen: {OUT} ({len(truth)} rows)")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -0,0 +1,197 @@
|
||||
"""sitecustomize — the warm_router routing-family freeze rig (dichotomy
|
||||
wave #2479 gap-close, worktree rune-wave-ws, builder
|
||||
factory-heavy-wr-route).
|
||||
|
||||
Auto-imported via PYTHONPATH=scripts/wr_freeze_seams by the truth
|
||||
generator, `freeze_truth.py --verify`, AND the live-parity script — and,
|
||||
critically, by the graph_memory SUBPROCESS graph_context spawns (env is
|
||||
inherited): the rig must therefore be idempotent. The FIRST process
|
||||
under the rig mints the hermetic memory root and builds the fixtures;
|
||||
every child (including the subprocess) sees RUNE_MEMORY_DIR already set
|
||||
and skips straight through.
|
||||
|
||||
Pins:
|
||||
* RUNE_WARM_ROUTER_CORE=python — inert (warm_router has no loader
|
||||
seam); belt-and-braces parity with _pin_oracle_cores.
|
||||
* RUNE_GRAPH_MEMORY_CORE=python — graph_context's subprocess must NOT
|
||||
probe a graph kernel (its query_fact would reshape the facts).
|
||||
* RUNE_MEMORY_CORE — POPPED if set: the base_level rows freeze the
|
||||
LIVE delegation (the retired Python fallback recurses
|
||||
_py_base_level_from_uses -> base_level_from_uses and degrades to
|
||||
-2.0 — the oracle's own documented outer-catch behavior, NOT the
|
||||
math contract this battery pins).
|
||||
* MS_RUST_LIB — the built memory_scoring kernel, repo-relative when
|
||||
present (worktree build), else the shared checkout build.
|
||||
|
||||
Fixtures (all under <root>, byte-deterministic, no absolute paths in
|
||||
any frozen output):
|
||||
* store/memory.db — entries (active neurons, a retired one, a
|
||||
document-kind row that only survives _associated_neuron_bodies'
|
||||
status-only filter, an empty-slug neuron, a hollow-body neuron),
|
||||
use_history (ACT-R rows at pinned hour offsets, one NON-STRING row
|
||||
for the -2.0 envelope), associations (0.9/0.7/0.4/0.35/0.33/0.6
|
||||
links + a sub-0.3 one).
|
||||
* graph/graph.sqlite — Alice/Bob/Rune/Rust entities, an Al alias,
|
||||
four edges (2 outbound from Alice, 1 incoming, 1 second-hop).
|
||||
* index/warm_state.json — sessions s1 (primed alpha-core), s-empty
|
||||
(nothing primed), s-ghost (primed a slug with no entry).
|
||||
"""
|
||||
|
||||
import os
|
||||
import sqlite3
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
REPO = Path(__file__).resolve().parents[2]
|
||||
|
||||
os.environ.setdefault("RUNE_WARM_ROUTER_CORE", "python")
|
||||
os.environ.setdefault("RUNE_GRAPH_MEMORY_CORE", "python")
|
||||
os.environ.pop("RUNE_MEMORY_CORE", None) # live delegation for the math rows
|
||||
|
||||
_MS = REPO / "src" / "rust" / "memory_scoring" / "target" / "release" / "libmemory_scoring.so"
|
||||
if _MS.is_file():
|
||||
os.environ.setdefault("MS_RUST_LIB", str(_MS))
|
||||
|
||||
if str(REPO / "src") not in sys.path:
|
||||
sys.path.insert(0, str(REPO / "src"))
|
||||
|
||||
|
||||
def _build_store(db_path: Path) -> None:
|
||||
db_path.parent.mkdir(parents=True, exist_ok=True)
|
||||
db = sqlite3.connect(str(db_path))
|
||||
db.executescript("""
|
||||
CREATE TABLE IF NOT EXISTS entries (
|
||||
id INTEGER PRIMARY KEY, text TEXT, slug TEXT, triggers TEXT,
|
||||
importance REAL, summary TEXT, wash_count INTEGER DEFAULT 0,
|
||||
always_on INTEGER DEFAULT 0, priority REAL DEFAULT 0,
|
||||
last_accessed TEXT, kind TEXT DEFAULT 'neuron',
|
||||
status TEXT DEFAULT 'active');
|
||||
CREATE TABLE IF NOT EXISTS use_history (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT, entry_id INTEGER NOT NULL,
|
||||
used_at TEXT NOT NULL DEFAULT (datetime('now')),
|
||||
session_id TEXT, score REAL, outcome TEXT DEFAULT 'unknown');
|
||||
CREATE TABLE IF NOT EXISTS associations (
|
||||
src_id INTEGER NOT NULL, dst_id INTEGER NOT NULL,
|
||||
strength REAL NOT NULL);
|
||||
""")
|
||||
db.executemany(
|
||||
"INSERT INTO entries (id, text, slug, triggers, importance, summary, kind, status) "
|
||||
"VALUES (?,?,?,?,?,?,?,?)",
|
||||
[
|
||||
(1, "alpha core body", "alpha-core", "alpha, core", 0.9, "alpha summary", "neuron", "active"),
|
||||
(2, "beta lens body", "beta-lens", "beta", 0.8, "", "neuron", "active"),
|
||||
(3, "gamma dated body", "gamma-dated", "gamma", 0.7, "", "neuron", "active"),
|
||||
(4, "shadow body", "alpha-shadow", "shadow", 0.6, "shadow lens notes", "neuron", "active"),
|
||||
(5, "retired body", "retired-one", "retired", 0.5, "", "neuron", "retired"),
|
||||
(6, "A plain document text that is fairly long for budget math", "plain-doc", "doc", 0.5, "", "document", "active"),
|
||||
(7, "seven token body padding", "", "", 0.5, "", "neuron", "active"),
|
||||
(8, "", "hollow-body", "hollow", 0.5, "", "neuron", "active"),
|
||||
(9, "", "unicode-body", "unicode", 0.5, "çafe — naïve ✓✓ padding", "neuron", "active"),
|
||||
(10, "cap body", "cap-heavy", "cap", 0.5, "", "neuron", "active"),
|
||||
],
|
||||
)
|
||||
db.executemany(
|
||||
"INSERT INTO use_history (entry_id, used_at, session_id, outcome) VALUES (?,?,?,?)",
|
||||
[
|
||||
(1, "2026-10-14T23:00:00+00:00", "s1", "helpful"),
|
||||
(1, "2026-10-14T18:00:00+00:00", "s1", "helpful"),
|
||||
(1, "2026-10-14T13:00:00+00:00", "s1", "helpful"),
|
||||
(2, "2026-10-14T23:30:00+00:00", "s1", "helpful"),
|
||||
],
|
||||
)
|
||||
# non-string used_at (INTEGER): the kernel's -2.0 envelope row
|
||||
db.execute("INSERT INTO use_history (entry_id, used_at, session_id, outcome) VALUES (8, 1791234567, 's1', 'unknown')")
|
||||
# 105 rows for entry 10: pins the BASE_LEVEL_MAX_USES=100 scan cap
|
||||
# (the gather keeps the 100 newest, used_at DESC)
|
||||
from datetime import datetime, timedelta
|
||||
|
||||
_t0 = datetime(2026, 10, 14, 23, 0, 0)
|
||||
db.executemany(
|
||||
"INSERT INTO use_history (entry_id, used_at, session_id, outcome) VALUES (10, ?, 's1', 'helpful')",
|
||||
[
|
||||
((_t0 - timedelta(hours=k)).strftime("%Y-%m-%dT%H:%M:%S+00:00"),)
|
||||
for k in range(105)
|
||||
],
|
||||
)
|
||||
db.executemany(
|
||||
"INSERT INTO associations (src_id, dst_id, strength) VALUES (?,?,?)",
|
||||
[
|
||||
(1, 4, 0.9), # alpha-core -> alpha-shadow
|
||||
(1, 6, 0.7), # alpha-core -> plain-doc (kind=document: only survives the status-only filter)
|
||||
(1, 2, 0.4), # alpha-core -> beta-lens
|
||||
(1, 3, 0.35), # alpha-core -> gamma-dated
|
||||
(1, 8, 0.33), # alpha-core -> hollow-body (empty body: seen-burns-slug row)
|
||||
(2, 7, 0.6), # beta-lens -> '' slug (the slug-or-assoc row)
|
||||
(2, 3, 0.2), # sub-threshold: never gathered
|
||||
(3, 9, 0.5), # gamma-dated -> unicode-body (rune-count token law)
|
||||
(4, 1, 0.5), # back-link to alpha-core (already-fired skip row)
|
||||
],
|
||||
)
|
||||
db.commit()
|
||||
db.close()
|
||||
|
||||
|
||||
def _build_graph(db_path: Path) -> None:
|
||||
db_path.parent.mkdir(parents=True, exist_ok=True)
|
||||
db = sqlite3.connect(str(db_path))
|
||||
db.executescript("""
|
||||
CREATE TABLE IF NOT EXISTS entities (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT NOT NULL UNIQUE,
|
||||
type TEXT NOT NULL DEFAULT 'concept', summary TEXT DEFAULT '',
|
||||
created_at TEXT NOT NULL DEFAULT '2026-10-14T00:00:00');
|
||||
CREATE TABLE IF NOT EXISTS aliases (
|
||||
entity_id INTEGER NOT NULL, alias TEXT NOT NULL,
|
||||
UNIQUE (entity_id, alias));
|
||||
CREATE TABLE IF NOT EXISTS edges (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
subj_id INTEGER NOT NULL, pred TEXT NOT NULL,
|
||||
obj_id INTEGER NOT NULL, evidence TEXT DEFAULT '',
|
||||
source TEXT DEFAULT '', confidence REAL,
|
||||
strength INTEGER, valid_from TEXT DEFAULT '',
|
||||
valid_until TEXT DEFAULT '', status TEXT DEFAULT 'active');
|
||||
""")
|
||||
db.executemany(
|
||||
"INSERT INTO entities (id, name, type) VALUES (?,?,?)",
|
||||
[(1, "Alice", "person"), (2, "Bob", "person"),
|
||||
(3, "Rune", "project"), (4, "Rust", "tool")],
|
||||
)
|
||||
db.execute("INSERT INTO aliases (entity_id, alias) VALUES (1, 'Al')")
|
||||
db.executemany(
|
||||
"INSERT INTO edges (subj_id, pred, obj_id, confidence, status) VALUES (?,?,?,?, 'active')",
|
||||
[
|
||||
(1, "manages", 3, 0.9), # Alice -> Rune
|
||||
(1, "knows", 2, 0.8), # Alice -> Bob
|
||||
(3, "uses", 4, 0.7), # Rune -> Rust (2nd hop)
|
||||
(2, "collaborates_with", 1, 0.6), # Bob -> Alice (incoming)
|
||||
],
|
||||
)
|
||||
db.commit()
|
||||
db.close()
|
||||
|
||||
|
||||
def _build_state(root: Path) -> None:
|
||||
import json
|
||||
|
||||
idx = root / "index"
|
||||
idx.mkdir(parents=True, exist_ok=True)
|
||||
state = {
|
||||
"neurons": {},
|
||||
"divides": [],
|
||||
"sessions": {
|
||||
"s1": {"primed": {"alpha-core": 0.5}, "turns": 2, "last_active": "2026-10-14T20:00:00"},
|
||||
"s-empty": {"primed": {}, "turns": 1, "last_active": "2026-10-14T20:00:00"},
|
||||
"s-ghost": {"primed": {"ghost-neuron": 0.9}, "turns": 1, "last_active": "2026-10-14T20:00:00"},
|
||||
},
|
||||
}
|
||||
(idx / "warm_state.json").write_text(json.dumps(state, indent=2) + "\n", encoding="utf-8")
|
||||
|
||||
|
||||
if not os.environ.get("RUNE_MEMORY_DIR"):
|
||||
import tempfile
|
||||
|
||||
_root = Path(tempfile.mkdtemp(prefix="wr-freeze-"))
|
||||
os.environ["RUNE_MEMORY_DIR"] = str(_root)
|
||||
os.environ.setdefault("RUNE_STORE_DB", str(_root / "store" / "memory.db"))
|
||||
_build_store(_root / "store" / "memory.db")
|
||||
_build_graph(_root / "graph" / "graph.sqlite")
|
||||
_build_state(_root)
|
||||
@@ -0,0 +1,316 @@
|
||||
package main
|
||||
|
||||
// gaps_routing.go — dichotomy wave #2479 gap-close, routing/activation/
|
||||
// scoring family (builder factory-heavy-wr-route). PARITY ports of the
|
||||
// five audit-missing warm_router.py functions:
|
||||
//
|
||||
// base_level_activation -> BaseLevelActivation
|
||||
// _associated_neuron_bodies -> AssociatedNeuronBodies
|
||||
// _primed_associations -> PrimedAssociations
|
||||
// graph_context -> GraphContext
|
||||
// render_fired -> RenderFired
|
||||
//
|
||||
// I/O-as-args law (the module's established split): the SQLite gathers,
|
||||
// the graph_memory subprocess, and the state-file reads stay caller-side;
|
||||
// these are the deterministic decisions over the gathered rows.
|
||||
//
|
||||
// Truth battery: truth_gap.json (live Python oracle via the shared
|
||||
// freeze_truth harness under scripts/wr_freeze_seams — 2026-10-14).
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"math"
|
||||
"os"
|
||||
"strings"
|
||||
"unicode/utf8"
|
||||
)
|
||||
|
||||
// BaseLevelMaxUses — the use_history scan cap (SQL LIMIT is caller-side).
|
||||
const BaseLevelMaxUses = 100
|
||||
|
||||
// BaseLevelActivation — the wrapper contract of warm_router.py's
|
||||
// base_level_activation minus the SQLite gather: no rows → -2.0 cold
|
||||
// start; otherwise the ACT-R decay math (baseLevelFromUses) over the
|
||||
// caller-gathered rows (used_at DESC, capped at BaseLevelMaxUses).
|
||||
// nowISO == "" mirrors the oracle's `now_iso or datetime.now()` (the
|
||||
// caller passes a pinned clock for determinism).
|
||||
func BaseLevelActivation(usedAtRows []string, nowISO string) float64 {
|
||||
if len(usedAtRows) == 0 {
|
||||
return -2.0
|
||||
}
|
||||
return baseLevelFromUses(usedAtRows, nowISO)
|
||||
}
|
||||
|
||||
// PrimedLink — one gathered association row for a primed neuron's
|
||||
// outbound links: dst slug + link strength (SQL already applied
|
||||
// strength >= 0.3, kind/status filters, strength DESC, LIMIT).
|
||||
type PrimedLink struct {
|
||||
Slug string
|
||||
Strength float64
|
||||
}
|
||||
|
||||
// PrimedPair — one primed association neighbour (slug, decayed weight).
|
||||
type PrimedPair struct {
|
||||
Slug string
|
||||
Weight float64
|
||||
}
|
||||
|
||||
// PrimedAssociations — warm_router.py's _primed_associations decision:
|
||||
// association-neighbours of the primed slugs, weighted at
|
||||
// AssocPrimeWeight, excluding the primed slugs themselves. The gather
|
||||
// (primed slugs → entry ids → links) is caller-side.
|
||||
func PrimedAssociations(links []PrimedLink, primedSlugs []string) []PrimedPair {
|
||||
inPrimed := make(map[string]bool, len(primedSlugs))
|
||||
for _, s := range primedSlugs {
|
||||
inPrimed[s] = true
|
||||
}
|
||||
out := []PrimedPair{}
|
||||
for _, l := range links {
|
||||
if inPrimed[l.Slug] {
|
||||
continue
|
||||
}
|
||||
out = append(out, PrimedPair{Slug: l.Slug, Weight: l.Strength * AssocPrimeWeight})
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
// NeuronLink — one gathered association row for _associated_neuron_bodies
|
||||
// (SQL already applied strength >= 0.3, status='active', strength DESC,
|
||||
// LIMIT 6): the dst entry's slug, summary, text, and link strength.
|
||||
type NeuronLink struct {
|
||||
Slug string
|
||||
Summary string
|
||||
Text string
|
||||
Strength float64
|
||||
}
|
||||
|
||||
// AssociatedBody — one association-expanded firing (summary-or-text body).
|
||||
type AssociatedBody struct {
|
||||
Slug string `json:"slug"`
|
||||
Body string `json:"body"`
|
||||
Score float64 `json:"score"`
|
||||
Tokens int `json:"tokens"`
|
||||
}
|
||||
|
||||
// AssociatedNeuronBodies — warm_router.py's _associated_neuron_bodies
|
||||
// budget walk: skip already-seen slugs (the fired set grows as links are
|
||||
// consumed, so an empty-body link still burns its slug), body =
|
||||
// summary-or-text stripped, tokens = max(1, CHARS/4) (Python len() counts
|
||||
// codepoints — rune law), BREAK (not skip) when the remaining budget
|
||||
// cannot fit the next body, score = round(strength, 2) half-to-even.
|
||||
func AssociatedNeuronBodies(links []NeuronLink, firedSlugs []string, budgetTokens int) []AssociatedBody {
|
||||
out := []AssociatedBody{}
|
||||
seen := make(map[string]bool, len(firedSlugs))
|
||||
for _, s := range firedSlugs {
|
||||
seen[s] = true
|
||||
}
|
||||
used := 0
|
||||
for _, l := range links {
|
||||
if seen[l.Slug] {
|
||||
continue
|
||||
}
|
||||
seen[l.Slug] = true
|
||||
body := strings.TrimSpace(l.Summary)
|
||||
if body == "" {
|
||||
body = strings.TrimSpace(l.Text)
|
||||
}
|
||||
if body == "" {
|
||||
continue
|
||||
}
|
||||
tokens := utf8.RuneCountInString(body) / 4
|
||||
if tokens < 1 {
|
||||
tokens = 1
|
||||
}
|
||||
if used+tokens > budgetTokens {
|
||||
break
|
||||
}
|
||||
slug := l.Slug
|
||||
if slug == "" {
|
||||
slug = "assoc"
|
||||
}
|
||||
out = append(out, AssociatedBody{
|
||||
Slug: slug, Body: body, Score: roundHalfEven2(l.Strength), Tokens: tokens,
|
||||
})
|
||||
used += tokens
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
// roundHalfEven2 — Python round(x, 2): banker's rounding on the exact
|
||||
// binary value (math.RoundToEven; the only exact .xx5 ties are the
|
||||
// dyadic rationals, where the f64 product is exact — same verdict as
|
||||
// CPython's correctly-rounded decimal path).
|
||||
func roundHalfEven2(f float64) float64 {
|
||||
return math.RoundToEven(f*100) / 100
|
||||
}
|
||||
|
||||
// GraphContext — warm_router.py's graph_context minus the subprocess:
|
||||
// the graph_memory query JSON arrives parsed-or-raw (list of facts OR
|
||||
// the {"facts", "entity"} dict shape — the audit-fix branch), the first
|
||||
// `limit` facts render as "subject → predicate → object" lines under the
|
||||
// entity header. No facts → "" (the caller injects nothing); a POSITIVE
|
||||
// limit smaller than the list keeps the header (the oracle's empty check
|
||||
// tests the FULL list, not the slice — facts[:0] renders the bare
|
||||
// header). Python slice semantics: negative limits take
|
||||
// facts[:limit] = len+limit.
|
||||
func GraphContext(factsJSON []byte, term string, limit int) string {
|
||||
var data interface{}
|
||||
if err := json.Unmarshal(factsJSON, &data); err != nil {
|
||||
return ""
|
||||
}
|
||||
var facts []interface{}
|
||||
entity := term
|
||||
switch v := data.(type) {
|
||||
case map[string]interface{}:
|
||||
if raw, ok := v["facts"].([]interface{}); ok {
|
||||
facts = raw
|
||||
}
|
||||
if e, ok := v["entity"].(string); ok && e != "" {
|
||||
entity = e
|
||||
} else if e := v["entity"]; e != nil {
|
||||
entity = fmt.Sprint(e)
|
||||
}
|
||||
case []interface{}:
|
||||
facts = v
|
||||
}
|
||||
if len(facts) == 0 {
|
||||
return ""
|
||||
}
|
||||
n := limit
|
||||
if n < 0 {
|
||||
n += len(facts)
|
||||
}
|
||||
if n < 0 {
|
||||
n = 0
|
||||
}
|
||||
if n > len(facts) {
|
||||
n = len(facts)
|
||||
}
|
||||
lines := make([]string, 0, n)
|
||||
for _, f := range facts[:n] {
|
||||
m, ok := f.(map[string]interface{})
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
lines = append(lines, fmt.Sprintf("%s → %s → %s",
|
||||
graphFactField(m, "subject"), graphFactField(m, "predicate"),
|
||||
graphFactField(m, "object")))
|
||||
}
|
||||
return fmt.Sprintf("### Graph memory (connected to '%s')\n\n%s", entity, strings.Join(lines, "\n"))
|
||||
}
|
||||
|
||||
// graphFactField — f"{f[key]}" renders via str(); JSON scalars format
|
||||
// identically through Sprint (strings verbatim, numbers shortest-form).
|
||||
func graphFactField(m map[string]interface{}, key string) string {
|
||||
if v, ok := m[key].(string); ok {
|
||||
return v
|
||||
}
|
||||
if v, ok := m[key]; ok && v != nil {
|
||||
return fmt.Sprint(v)
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// FiredRender — one fired-neuron record as render_fired sees it.
|
||||
type FiredRender struct {
|
||||
Slug string `json:"slug"`
|
||||
Body string `json:"body"`
|
||||
ViaAssociation bool `json:"via_association,omitempty"`
|
||||
Compressed bool `json:"compressed,omitempty"`
|
||||
}
|
||||
|
||||
// RenderFired — warm_router.py's render_fired: the injection block.
|
||||
// via_association outranks compressed for the tag; empty input → "".
|
||||
func RenderFired(fired []FiredRender) string {
|
||||
parts := make([]string, 0, len(fired))
|
||||
for _, f := range fired {
|
||||
tag := ""
|
||||
if f.ViaAssociation {
|
||||
tag = " (via association)"
|
||||
} else if f.Compressed {
|
||||
tag = " (compressed summary — full body in store)"
|
||||
}
|
||||
parts = append(parts, fmt.Sprintf("### Warm neuron: %s%s\n\n%s", f.Slug, tag, f.Body))
|
||||
}
|
||||
return strings.Join(parts, "\n\n")
|
||||
}
|
||||
|
||||
// gapRoutingCLI — the parity surface: runs the five gap functions on
|
||||
// JSON argv payloads (the parity script feeds the same gathered rows to
|
||||
// this binary that the oracle's SQL/subprocess gathered).
|
||||
func gapRoutingCLI(args []string) {
|
||||
if len(args) == 0 {
|
||||
fmt.Fprintln(os.Stderr, "usage: warm-router gap-cli <fn> [args...]")
|
||||
os.Exit(1)
|
||||
}
|
||||
fn, rest := args[0], args[1:]
|
||||
switch fn {
|
||||
case "base-level-activation":
|
||||
if len(rest) != 2 {
|
||||
gapUsage("base-level-activation <rows-json> <now-iso>")
|
||||
}
|
||||
var rows []string
|
||||
mustUnmarshalJSON(rest[0], &rows)
|
||||
emitJSON(map[string]float64{"score": BaseLevelActivation(rows, rest[1])})
|
||||
case "primed-associations":
|
||||
if len(rest) != 2 {
|
||||
gapUsage("primed-associations <links-json> <primed-slugs-json>")
|
||||
}
|
||||
var links []PrimedLink
|
||||
mustUnmarshalJSON(rest[0], &links)
|
||||
var primed []string
|
||||
mustUnmarshalJSON(rest[1], &primed)
|
||||
pairs := PrimedAssociations(links, primed)
|
||||
out := make([][2]interface{}, 0, len(pairs))
|
||||
for _, p := range pairs {
|
||||
out = append(out, [2]interface{}{p.Slug, p.Weight})
|
||||
}
|
||||
emitJSON(out)
|
||||
case "associated-neuron-bodies":
|
||||
if len(rest) != 3 {
|
||||
gapUsage("associated-neuron-bodies <links-json> <fired-slugs-json> <budget>")
|
||||
}
|
||||
var links []NeuronLink
|
||||
mustUnmarshalJSON(rest[0], &links)
|
||||
var fired []string
|
||||
mustUnmarshalJSON(rest[1], &fired)
|
||||
var budget int
|
||||
fmt.Sscanf(rest[2], "%d", &budget)
|
||||
emitJSON(AssociatedNeuronBodies(links, fired, budget))
|
||||
case "graph-context":
|
||||
if len(rest) != 3 {
|
||||
gapUsage("graph-context <facts-json> <term> <limit>")
|
||||
}
|
||||
var limit int
|
||||
fmt.Sscanf(rest[2], "%d", &limit)
|
||||
emitJSON(map[string]string{"rendered": GraphContext([]byte(rest[0]), rest[1], limit)})
|
||||
case "render-fired":
|
||||
if len(rest) != 1 {
|
||||
gapUsage("render-fired <fired-json>")
|
||||
}
|
||||
var fired []FiredRender
|
||||
mustUnmarshalJSON(rest[0], &fired)
|
||||
emitJSON(map[string]string{"rendered": RenderFired(fired)})
|
||||
default:
|
||||
fmt.Fprintf(os.Stderr, "unknown gap-cli fn: %s\n", fn)
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
func gapUsage(u string) {
|
||||
fmt.Fprintln(os.Stderr, "usage: warm-router gap-cli "+u)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
func mustUnmarshalJSON(s string, v interface{}) {
|
||||
if err := json.Unmarshal([]byte(s), v); err != nil {
|
||||
fmt.Fprintf(os.Stderr, "bad JSON payload: %v\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
func emitJSON(v interface{}) {
|
||||
out, _ := json.Marshal(v)
|
||||
fmt.Println(string(out))
|
||||
}
|
||||
@@ -28,7 +28,10 @@ func baseLevelFromUses(usedAtList []string, nowISO string) float64 {
|
||||
return -2.0 // Cold start — never fired
|
||||
}
|
||||
|
||||
now, err := time.Parse("2006-01-02T15:04:05Z", nowISO)
|
||||
now, err := time.Parse(time.RFC3339, nowISO)
|
||||
if err != nil {
|
||||
now, err = time.Parse("2006-01-02T15:04:05", nowISO)
|
||||
}
|
||||
if err != nil {
|
||||
now = time.Now().UTC()
|
||||
}
|
||||
@@ -110,6 +113,9 @@ func main() {
|
||||
args := os.Args[2:]
|
||||
|
||||
switch cmd {
|
||||
case "gap-cli":
|
||||
// gap family parity surface (gaps_routing.go)
|
||||
gapRoutingCLI(args)
|
||||
case "base-level":
|
||||
if len(args) < 2 {
|
||||
fmt.Fprintln(os.Stderr, "usage: warm-router base-level <timestamps-csv> <now-iso>")
|
||||
|
||||
@@ -0,0 +1,461 @@
|
||||
[
|
||||
{
|
||||
"fn": "base_level_activation",
|
||||
"args": [
|
||||
999
|
||||
],
|
||||
"kwargs": {
|
||||
"now_iso": "2026-10-15T00:00:00+00:00"
|
||||
},
|
||||
"expected": -2.0
|
||||
},
|
||||
{
|
||||
"fn": "base_level_activation",
|
||||
"args": [
|
||||
3
|
||||
],
|
||||
"kwargs": {
|
||||
"now_iso": "2026-10-15T00:00:00+00:00"
|
||||
},
|
||||
"expected": -2.0
|
||||
},
|
||||
{
|
||||
"fn": "base_level_activation",
|
||||
"args": [
|
||||
1
|
||||
],
|
||||
"kwargs": {
|
||||
"now_iso": "2026-10-15T00:00:00+00:00"
|
||||
},
|
||||
"expected": 0.5363527963313388
|
||||
},
|
||||
{
|
||||
"fn": "base_level_activation",
|
||||
"args": [
|
||||
2
|
||||
],
|
||||
"kwargs": {
|
||||
"db": null,
|
||||
"now_iso": "2026-10-15T00:00:00+00:00"
|
||||
},
|
||||
"expected": 0.3465735902799727
|
||||
},
|
||||
{
|
||||
"fn": "base_level_activation",
|
||||
"args": [
|
||||
8
|
||||
],
|
||||
"kwargs": {
|
||||
"now_iso": "2026-10-15T00:00:00+00:00"
|
||||
},
|
||||
"expected": -2
|
||||
},
|
||||
{
|
||||
"fn": "base_level_activation",
|
||||
"args": [
|
||||
10
|
||||
],
|
||||
"kwargs": {
|
||||
"now_iso": "2026-10-15T00:00:00+00:00"
|
||||
},
|
||||
"expected": 2
|
||||
},
|
||||
{
|
||||
"fn": "_primed_associations",
|
||||
"args": [
|
||||
"s1"
|
||||
],
|
||||
"kwargs": {},
|
||||
"expected": [
|
||||
[
|
||||
"alpha-shadow",
|
||||
0.45
|
||||
],
|
||||
[
|
||||
"beta-lens",
|
||||
0.2
|
||||
],
|
||||
[
|
||||
"gamma-dated",
|
||||
0.175
|
||||
],
|
||||
[
|
||||
"hollow-body",
|
||||
0.165
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"fn": "_primed_associations",
|
||||
"args": [
|
||||
"s1",
|
||||
2
|
||||
],
|
||||
"kwargs": {},
|
||||
"expected": [
|
||||
[
|
||||
"alpha-shadow",
|
||||
0.45
|
||||
],
|
||||
[
|
||||
"beta-lens",
|
||||
0.2
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"fn": "_primed_associations",
|
||||
"args": [
|
||||
"s-missing"
|
||||
],
|
||||
"kwargs": {},
|
||||
"expected": []
|
||||
},
|
||||
{
|
||||
"fn": "_primed_associations",
|
||||
"args": [
|
||||
"s-empty"
|
||||
],
|
||||
"kwargs": {},
|
||||
"expected": []
|
||||
},
|
||||
{
|
||||
"fn": "_primed_associations",
|
||||
"args": [
|
||||
"s-ghost"
|
||||
],
|
||||
"kwargs": {},
|
||||
"expected": []
|
||||
},
|
||||
{
|
||||
"fn": "_associated_neuron_bodies",
|
||||
"args": [
|
||||
[
|
||||
{
|
||||
"slug": "alpha-core"
|
||||
}
|
||||
],
|
||||
6
|
||||
],
|
||||
"kwargs": {},
|
||||
"expected": [
|
||||
{
|
||||
"slug": "alpha-shadow",
|
||||
"body": "shadow lens notes",
|
||||
"score": 0.9,
|
||||
"tokens": 4
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"fn": "_associated_neuron_bodies",
|
||||
"args": [
|
||||
[
|
||||
{
|
||||
"slug": "alpha-core"
|
||||
}
|
||||
],
|
||||
20
|
||||
],
|
||||
"kwargs": {},
|
||||
"expected": [
|
||||
{
|
||||
"slug": "alpha-shadow",
|
||||
"body": "shadow lens notes",
|
||||
"score": 0.9,
|
||||
"tokens": 4
|
||||
},
|
||||
{
|
||||
"slug": "plain-doc",
|
||||
"body": "A plain document text that is fairly long for budget math",
|
||||
"score": 0.7,
|
||||
"tokens": 14
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"fn": "_associated_neuron_bodies",
|
||||
"args": [
|
||||
[
|
||||
{
|
||||
"slug": "alpha-core"
|
||||
},
|
||||
{
|
||||
"slug": "beta-lens"
|
||||
}
|
||||
],
|
||||
30
|
||||
],
|
||||
"kwargs": {},
|
||||
"expected": [
|
||||
{
|
||||
"slug": "alpha-shadow",
|
||||
"body": "shadow lens notes",
|
||||
"score": 0.9,
|
||||
"tokens": 4
|
||||
},
|
||||
{
|
||||
"slug": "plain-doc",
|
||||
"body": "A plain document text that is fairly long for budget math",
|
||||
"score": 0.7,
|
||||
"tokens": 14
|
||||
},
|
||||
{
|
||||
"slug": "assoc",
|
||||
"body": "seven token body padding",
|
||||
"score": 0.6,
|
||||
"tokens": 6
|
||||
},
|
||||
{
|
||||
"slug": "gamma-dated",
|
||||
"body": "gamma dated body",
|
||||
"score": 0.35,
|
||||
"tokens": 4
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"fn": "_associated_neuron_bodies",
|
||||
"args": [
|
||||
[
|
||||
{
|
||||
"slug": "alpha-core"
|
||||
}
|
||||
],
|
||||
0
|
||||
],
|
||||
"kwargs": {},
|
||||
"expected": []
|
||||
},
|
||||
{
|
||||
"fn": "_associated_neuron_bodies",
|
||||
"args": [
|
||||
[
|
||||
{
|
||||
"slug": "beta-lens"
|
||||
}
|
||||
],
|
||||
20
|
||||
],
|
||||
"kwargs": {},
|
||||
"expected": [
|
||||
{
|
||||
"slug": "assoc",
|
||||
"body": "seven token body padding",
|
||||
"score": 0.6,
|
||||
"tokens": 6
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"fn": "_associated_neuron_bodies",
|
||||
"args": [
|
||||
[
|
||||
{
|
||||
"slug": "alpha-shadow"
|
||||
}
|
||||
],
|
||||
20
|
||||
],
|
||||
"kwargs": {},
|
||||
"expected": [
|
||||
{
|
||||
"slug": "alpha-core",
|
||||
"body": "alpha summary",
|
||||
"score": 0.5,
|
||||
"tokens": 3
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"fn": "_associated_neuron_bodies",
|
||||
"args": [
|
||||
[
|
||||
{
|
||||
"slug": "gamma-dated"
|
||||
}
|
||||
],
|
||||
20
|
||||
],
|
||||
"kwargs": {},
|
||||
"expected": [
|
||||
{
|
||||
"slug": "unicode-body",
|
||||
"body": "çafe — naïve ✓✓ padding",
|
||||
"score": 0.5,
|
||||
"tokens": 5
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"fn": "graph_context",
|
||||
"args": [
|
||||
"Alice"
|
||||
],
|
||||
"kwargs": {},
|
||||
"expected": "### Graph memory (connected to 'Alice')\n\nAlice → manages → Rune\nAlice → knows → Bob\nRune → uses → Rust\nBob → collaborates_with → Alice"
|
||||
},
|
||||
{
|
||||
"fn": "graph_context",
|
||||
"args": [
|
||||
"Al"
|
||||
],
|
||||
"kwargs": {},
|
||||
"expected": "### Graph memory (connected to 'Alice')\n\nAlice → manages → Rune\nAlice → knows → Bob\nRune → uses → Rust\nBob → collaborates_with → Alice"
|
||||
},
|
||||
{
|
||||
"fn": "graph_context",
|
||||
"args": [
|
||||
"Nobody"
|
||||
],
|
||||
"kwargs": {},
|
||||
"expected": ""
|
||||
},
|
||||
{
|
||||
"fn": "graph_context",
|
||||
"args": [
|
||||
"Alice",
|
||||
2
|
||||
],
|
||||
"kwargs": {},
|
||||
"expected": "### Graph memory (connected to 'Alice')\n\nAlice → manages → Rune\nAlice → knows → Bob\nRune → uses → Rust\nBob → collaborates_with → Alice"
|
||||
},
|
||||
{
|
||||
"fn": "graph_context",
|
||||
"args": [
|
||||
"Alice",
|
||||
1,
|
||||
1
|
||||
],
|
||||
"kwargs": {},
|
||||
"expected": "### Graph memory (connected to 'Alice')\n\nAlice → manages → Rune"
|
||||
},
|
||||
{
|
||||
"fn": "graph_context",
|
||||
"args": [
|
||||
"Alice",
|
||||
1,
|
||||
0
|
||||
],
|
||||
"kwargs": {},
|
||||
"expected": "### Graph memory (connected to 'Alice')\n\n"
|
||||
},
|
||||
{
|
||||
"fn": "graph_context",
|
||||
"args": [
|
||||
"Alice",
|
||||
1,
|
||||
-1
|
||||
],
|
||||
"kwargs": {},
|
||||
"expected": "### Graph memory (connected to 'Alice')\n\nAlice → manages → Rune\nAlice → knows → Bob\nRune → uses → Rust\nBob → collaborates_with → Alice"
|
||||
},
|
||||
{
|
||||
"fn": "graph_context",
|
||||
"args": [
|
||||
""
|
||||
],
|
||||
"kwargs": {},
|
||||
"expected": ""
|
||||
},
|
||||
{
|
||||
"fn": "graph_context",
|
||||
"args": [
|
||||
"Rune"
|
||||
],
|
||||
"kwargs": {},
|
||||
"expected": "### Graph memory (connected to 'Rune')\n\nRune → uses → Rust\nAlice → manages → Rune"
|
||||
},
|
||||
{
|
||||
"fn": "render_fired",
|
||||
"args": [
|
||||
[
|
||||
{
|
||||
"slug": "alpha-core",
|
||||
"body": "Full body text."
|
||||
}
|
||||
]
|
||||
],
|
||||
"kwargs": {},
|
||||
"expected": "### Warm neuron: alpha-core\n\nFull body text."
|
||||
},
|
||||
{
|
||||
"fn": "render_fired",
|
||||
"args": [
|
||||
[
|
||||
{
|
||||
"slug": "via",
|
||||
"body": "b",
|
||||
"via_association": true
|
||||
}
|
||||
]
|
||||
],
|
||||
"kwargs": {},
|
||||
"expected": "### Warm neuron: via (via association)\n\nb"
|
||||
},
|
||||
{
|
||||
"fn": "render_fired",
|
||||
"args": [
|
||||
[
|
||||
{
|
||||
"slug": "c",
|
||||
"body": "b",
|
||||
"compressed": true
|
||||
}
|
||||
]
|
||||
],
|
||||
"kwargs": {},
|
||||
"expected": "### Warm neuron: c (compressed summary — full body in store)\n\nb"
|
||||
},
|
||||
{
|
||||
"fn": "render_fired",
|
||||
"args": [
|
||||
[
|
||||
{
|
||||
"slug": "both",
|
||||
"body": "b",
|
||||
"via_association": true,
|
||||
"compressed": true
|
||||
}
|
||||
]
|
||||
],
|
||||
"kwargs": {},
|
||||
"expected": "### Warm neuron: both (via association)\n\nb"
|
||||
},
|
||||
{
|
||||
"fn": "render_fired",
|
||||
"args": [
|
||||
[
|
||||
{
|
||||
"slug": "u",
|
||||
"body": "café — résumé ✓",
|
||||
"via_association": false
|
||||
}
|
||||
]
|
||||
],
|
||||
"kwargs": {},
|
||||
"expected": "### Warm neuron: u\n\ncafé — résumé ✓"
|
||||
},
|
||||
{
|
||||
"fn": "render_fired",
|
||||
"args": [
|
||||
[]
|
||||
],
|
||||
"kwargs": {},
|
||||
"expected": ""
|
||||
},
|
||||
{
|
||||
"fn": "render_fired",
|
||||
"args": [
|
||||
[
|
||||
{
|
||||
"slug": "no-flags",
|
||||
"body": "x",
|
||||
"extra_ignored": 1
|
||||
}
|
||||
]
|
||||
],
|
||||
"kwargs": {},
|
||||
"expected": "### Warm neuron: no-flags\n\nx"
|
||||
}
|
||||
]
|
||||
@@ -0,0 +1,253 @@
|
||||
package main
|
||||
|
||||
// truth_gap_test.go — parity battery for the routing/activation/scoring
|
||||
// family gap port (dichotomy wave #2479, builder factory-heavy-wr-route).
|
||||
// Replays truth_gap.json (live Python oracle via scripts/wr_freeze_seams,
|
||||
// 2026-10-14) through BaseLevelActivation, PrimedAssociations,
|
||||
// AssociatedNeuronBodies, GraphContext, RenderFired.
|
||||
//
|
||||
// The oracle rows carry the I/O-layer arguments (entry ids, session ids,
|
||||
// fired lists); the DB-backed inputs are mirrored here from the rig
|
||||
// fixtures in scripts/wr_freeze_seams/sitecustomize.py — the rows the
|
||||
// oracle's SQL gathered for those keys. render_fired rows are pure: the
|
||||
// recorded args ARE the inputs.
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"math"
|
||||
"os"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
// ── fixture mirrors (scripts/wr_freeze_seams/sitecustomize.py) ──
|
||||
|
||||
// useHistoryRows — the use_history rows per entry id, used_at DESC
|
||||
// (the oracle's ORDER BY; the LIMIT 100 cap never binds on 3 rows —
|
||||
// entry 10's 105-row case is mirrored by useHistoryRowsFor).
|
||||
var useHistoryRows = map[int][]string{
|
||||
1: {"2026-10-14T23:00:00+00:00", "2026-10-14T18:00:00+00:00", "2026-10-14T13:00:00+00:00"},
|
||||
2: {"2026-10-14T23:30:00+00:00"},
|
||||
3: {},
|
||||
8: {"1791234567"}, // non-string in SQLite: the -2.0 envelope row
|
||||
}
|
||||
|
||||
// useHistoryRowsFor — entry 10's gather: 105 rows 1h apart from
|
||||
// 2026-10-14T23:00, the 100 NEWEST (used_at DESC LIMIT 100).
|
||||
func useHistoryRowsFor(id int) []string {
|
||||
if id != 10 {
|
||||
return useHistoryRows[id]
|
||||
}
|
||||
rows := make([]string, 0, 100)
|
||||
h, _ := time.Parse("2006-01-02T15:04:05+00:00", "2026-10-14T23:00:00+00:00")
|
||||
for k := 0; k < 100; k++ {
|
||||
rows = append(rows, h.Add(-time.Duration(k)*time.Hour).Format("2006-01-02T15:04:05+00:00"))
|
||||
}
|
||||
return rows
|
||||
}
|
||||
|
||||
// primedFixture — session s1's primed slugs and the links its SQL
|
||||
// gathered (kind='neuron' + status='active' filter, strength DESC; the
|
||||
// document-kind plain-doc row is filtered GATHERER-side and absent).
|
||||
var primedFixture = struct {
|
||||
slugs []string
|
||||
links []PrimedLink
|
||||
}{
|
||||
slugs: []string{"alpha-core"},
|
||||
links: []PrimedLink{
|
||||
{"alpha-shadow", 0.9}, {"beta-lens", 0.4},
|
||||
{"gamma-dated", 0.35}, {"hollow-body", 0.33},
|
||||
},
|
||||
}
|
||||
|
||||
// assocLinks — the links the oracle's SQL gathered for fired alpha-core
|
||||
// (status-only filter: plain-doc survives; strength DESC LIMIT 6; the
|
||||
// sub-0.3 link is absent). Field order: slug, summary, text, strength.
|
||||
var assocLinks = []NeuronLink{
|
||||
{"alpha-shadow", "shadow lens notes", "", 0.9},
|
||||
{"plain-doc", "", "A plain document text that is fairly long for budget math", 0.7},
|
||||
{"beta-lens", "", "beta lens body", 0.4},
|
||||
{"gamma-dated", "", "gamma dated body", 0.35},
|
||||
{"hollow-body", "", "", 0.33},
|
||||
}
|
||||
|
||||
// graphPayloadAlice — the graph_memory query payload for Alice (dict
|
||||
// shape: found entity). The BFS facts come first, then the incoming-edge
|
||||
// facts (the collaborates_with row appears TWICE — the oracle appends
|
||||
// the incoming edge without dedupe; the default limit=4 masks the fifth).
|
||||
// The extra oracle keys (confidence, from, ...) pin that Go ignores them.
|
||||
const graphPayloadAlice = `{"entity": "Alice", "type": "person", "facts": [
|
||||
{"subject": "Alice", "predicate": "manages", "object": "Rune", "confidence": 0.9, "from": "", "until": "", "status": "active", "source": ""},
|
||||
{"subject": "Alice", "predicate": "knows", "object": "Bob", "confidence": 0.8, "from": "", "until": "", "status": "active", "source": ""},
|
||||
{"subject": "Rune", "predicate": "uses", "object": "Rust", "confidence": 0.7, "from": "", "until": "", "status": "active", "source": ""},
|
||||
{"subject": "Bob", "predicate": "collaborates_with", "object": "Alice", "confidence": 0.6, "from": "", "until": "", "status": "active", "source": ""},
|
||||
{"subject": "Bob", "predicate": "collaborates_with", "object": "Alice", "confidence": 0.6, "from": "", "until": "", "status": "active", "source": ""}
|
||||
]}`
|
||||
|
||||
const graphPayloadRune = `{"entity": "Rune", "type": "project", "facts": [
|
||||
{"subject": "Rune", "predicate": "uses", "object": "Rust"},
|
||||
{"subject": "Alice", "predicate": "manages", "object": "Rune"}
|
||||
]}`
|
||||
|
||||
func TestGapTruthReplay(t *testing.T) {
|
||||
b, err := os.ReadFile("truth_gap.json")
|
||||
if err != nil {
|
||||
t.Fatalf("truth_gap.json missing: %v", err)
|
||||
}
|
||||
var rows []struct {
|
||||
Fn string `json:"fn"`
|
||||
Args json.RawMessage `json:"args"`
|
||||
Kwargs map[string]interface{} `json:"kwargs"`
|
||||
Expected json.RawMessage `json:"expected"`
|
||||
}
|
||||
if err := json.Unmarshal(b, &rows); err != nil {
|
||||
t.Fatalf("unparseable: %v", err)
|
||||
}
|
||||
if len(rows) != 34 {
|
||||
t.Fatalf("truth_gap.json: want 34 rows, got %d", len(rows))
|
||||
}
|
||||
|
||||
okBase, okPrimed, okAssoc, okGraph, okRender := 0, 0, 0, 0, 0
|
||||
for i, r := range rows {
|
||||
var args []json.RawMessage
|
||||
if err := json.Unmarshal(r.Args, &args); err != nil {
|
||||
t.Fatalf("row %d: bad args: %v", i, err)
|
||||
}
|
||||
switch r.Fn {
|
||||
case "base_level_activation":
|
||||
var entryID float64
|
||||
json.Unmarshal(args[0], &entryID)
|
||||
nowISO, _ := r.Kwargs["now_iso"].(string)
|
||||
rows_ := useHistoryRowsFor(int(entryID))
|
||||
got := BaseLevelActivation(rows_, nowISO)
|
||||
var want float64
|
||||
json.Unmarshal(r.Expected, &want)
|
||||
if math.Abs(got-want) > 1e-9 {
|
||||
t.Errorf("row %d base_level_activation(%d): got %v want %v", i, int(entryID), got, want)
|
||||
}
|
||||
okBase++
|
||||
case "_primed_associations":
|
||||
var session string
|
||||
json.Unmarshal(args[0], &session)
|
||||
limit := 4
|
||||
if len(args) > 1 {
|
||||
var l float64
|
||||
json.Unmarshal(args[1], &l)
|
||||
limit = int(l)
|
||||
}
|
||||
var got []PrimedPair
|
||||
if session == "s1" {
|
||||
links := primedFixture.links
|
||||
if limit < len(links) {
|
||||
links = links[:limit]
|
||||
}
|
||||
got = PrimedAssociations(links, primedFixture.slugs)
|
||||
} else {
|
||||
got = PrimedAssociations(nil, nil)
|
||||
}
|
||||
var wantPairs [][]interface{}
|
||||
json.Unmarshal(r.Expected, &wantPairs)
|
||||
if len(got) != len(wantPairs) {
|
||||
t.Errorf("row %d _primed_associations(%q): got %d pairs want %d", i, session, len(got), len(wantPairs))
|
||||
continue
|
||||
}
|
||||
for j, wp := range wantPairs {
|
||||
slug, _ := wp[0].(string)
|
||||
w, _ := wp[1].(float64)
|
||||
if got[j].Slug != slug || math.Abs(got[j].Weight-w) > 1e-12 {
|
||||
t.Errorf("row %d _primed_associations(%q)[%d]: got (%s %v) want (%s %v)",
|
||||
i, session, j, got[j].Slug, got[j].Weight, slug, w)
|
||||
}
|
||||
}
|
||||
okPrimed++
|
||||
case "_associated_neuron_bodies":
|
||||
var fired []map[string]interface{}
|
||||
json.Unmarshal(args[0], &fired)
|
||||
var budgetF float64
|
||||
json.Unmarshal(args[1], &budgetF)
|
||||
budget := int(budgetF)
|
||||
firedSlugs := make([]string, 0, len(fired))
|
||||
for _, f := range fired {
|
||||
s, _ := f["slug"].(string)
|
||||
firedSlugs = append(firedSlugs, s)
|
||||
}
|
||||
var links []NeuronLink
|
||||
switch {
|
||||
case len(firedSlugs) == 1 && firedSlugs[0] == "beta-lens":
|
||||
links = []NeuronLink{{"", "", "seven token body padding", 0.6}}
|
||||
case len(firedSlugs) == 1 && firedSlugs[0] == "alpha-shadow":
|
||||
links = []NeuronLink{{"alpha-core", "alpha summary", "", 0.5}}
|
||||
case len(firedSlugs) == 1 && firedSlugs[0] == "gamma-dated":
|
||||
links = []NeuronLink{{"unicode-body", "çafe — naïve ✓✓ padding", "", 0.5}}
|
||||
case len(firedSlugs) == 2: // ids (1,2): both srcs' links, strength DESC
|
||||
links = []NeuronLink{
|
||||
{"alpha-shadow", "shadow lens notes", "", 0.9},
|
||||
{"plain-doc", "", "A plain document text that is fairly long for budget math", 0.7},
|
||||
{"", "", "seven token body padding", 0.6},
|
||||
{"beta-lens", "", "beta lens body", 0.4},
|
||||
{"gamma-dated", "", "gamma dated body", 0.35},
|
||||
{"hollow-body", "", "", 0.33},
|
||||
}
|
||||
default:
|
||||
links = assocLinks
|
||||
}
|
||||
got := AssociatedNeuronBodies(links, firedSlugs, budget)
|
||||
var want []map[string]interface{}
|
||||
json.Unmarshal(r.Expected, &want)
|
||||
if len(got) != len(want) {
|
||||
t.Errorf("row %d _associated_neuron_bodies(%v %d): got %d want %d", i, firedSlugs, budget, len(got), len(want))
|
||||
continue
|
||||
}
|
||||
for j, w := range want {
|
||||
wslug, _ := w["slug"].(string)
|
||||
wbody, _ := w["body"].(string)
|
||||
wscore, _ := w["score"].(float64)
|
||||
wtokens, _ := w["tokens"].(float64)
|
||||
if got[j].Slug != wslug || got[j].Body != wbody ||
|
||||
math.Abs(got[j].Score-wscore) > 1e-12 || got[j].Tokens != int(wtokens) {
|
||||
t.Errorf("row %d _associated_neuron_bodies[%d]: got (%s %q %v %d) want (%s %q %v %d)",
|
||||
i, j, got[j].Slug, got[j].Body, got[j].Score, got[j].Tokens,
|
||||
wslug, wbody, wscore, int(wtokens))
|
||||
}
|
||||
}
|
||||
okAssoc++
|
||||
case "graph_context":
|
||||
var term string
|
||||
json.Unmarshal(args[0], &term)
|
||||
limit := 4
|
||||
if len(args) > 2 {
|
||||
var l float64
|
||||
json.Unmarshal(args[2], &l)
|
||||
limit = int(l)
|
||||
}
|
||||
payload := "[]"
|
||||
if term == "Alice" || term == "Al" {
|
||||
payload = graphPayloadAlice
|
||||
} else if term == "Rune" {
|
||||
payload = graphPayloadRune
|
||||
}
|
||||
got := GraphContext([]byte(payload), term, limit)
|
||||
var want string
|
||||
json.Unmarshal(r.Expected, &want)
|
||||
if got != want {
|
||||
t.Errorf("row %d graph_context(%q %d):\n got %q\nwant %q", i, term, limit, got, want)
|
||||
}
|
||||
okGraph++
|
||||
case "render_fired":
|
||||
var fired []FiredRender
|
||||
json.Unmarshal(args[0], &fired)
|
||||
got := RenderFired(fired)
|
||||
var want string
|
||||
json.Unmarshal(r.Expected, &want)
|
||||
if got != want {
|
||||
t.Errorf("row %d render_fired:\n got %q\nwant %q", i, got, want)
|
||||
}
|
||||
okRender++
|
||||
default:
|
||||
t.Fatalf("row %d: unknown fn %q", i, r.Fn)
|
||||
}
|
||||
}
|
||||
if okBase != 6 || okPrimed != 5 || okAssoc != 7 || okGraph != 9 || okRender != 7 {
|
||||
t.Errorf("row counts: base=%d primed=%d assoc=%d graph=%d render=%d", okBase, okPrimed, okAssoc, okGraph, okRender)
|
||||
}
|
||||
}
|
||||
@@ -968,7 +968,7 @@ def _primed_associations(session_id, limit=4):
|
||||
f"WHERE a.src_id IN ({iph}) AND a.strength >= 0.3 "
|
||||
"AND e.kind='neuron' AND e.status='active' "
|
||||
"ORDER BY a.strength DESC LIMIT ?",
|
||||
(limit,),
|
||||
(*ids, limit),
|
||||
).fetchall()
|
||||
return [(r[0], float(r[1]) * ASSOC_PRIME_WEIGHT) for r in links if r[0] not in slugs]
|
||||
finally:
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
# warm_router routing-family gap-close (dichotomy wave, builder factory-heavy-wr-route)
|
||||
|
||||
Module: src/rune/warm_router.py (1518L, 33 fns). Family: 16 routing/
|
||||
activation/scoring fns. Before: 11/16 (missing base_level_activation,
|
||||
_primed_associations, _associated_neuron_bodies, graph_context,
|
||||
render_fired). After: **16/16**.
|
||||
|
||||
## Port (src/go/warm-router/gaps_routing.go, new; + gap-cli dispatch in main.go)
|
||||
|
||||
Pure decision ports, I/O-as-args per the module's established split:
|
||||
|
||||
- BaseLevelActivation — no rows -> -2.0; else baseLevelFromUses.
|
||||
- PrimedAssociations — neighbour slugs x AssocPrimeWeight, primed excluded.
|
||||
- AssociatedNeuronBodies — seen-set skip (empty bodies burn slugs),
|
||||
summary-or-text, tokens=max(1, RUNES/4), BREAK on budget overflow,
|
||||
score=round-half-even(strength,2), empty slug -> "assoc".
|
||||
- GraphContext — parsed-or-raw payload (dict/list crash-parity), facts
|
||||
[:limit] with Python negative-slice semantics; bare header on
|
||||
limit=0-with-facts (oracle's empty check tests the full list).
|
||||
- RenderFired — injection block; via_association outranks compressed.
|
||||
- main.go: RFC3339+T15:04:05 now-parse (was literal-Z-only -> wall
|
||||
clock for +00:00 stamps — the base-level battery caught it).
|
||||
|
||||
## Oracle bug fixed (fix-first, src/rune/warm_router.py)
|
||||
|
||||
_primed_associations passed `(limit,)` for a statement with
|
||||
len(ids)+1 placeholders -> sqlite3.ProgrammingError on EVERY call ->
|
||||
[] forever (the active-priming association walk was dead code in
|
||||
production). Now passes (*ids, limit). Proof: frozen rows s1/s1-limit2
|
||||
freeze real pairs; parity s2 exercises the live path.
|
||||
|
||||
## Verification (evidence: verification/wr-family-*.{log,exit})
|
||||
|
||||
- freeze_truth --verify: 34/34 byte-identical (exit 0).
|
||||
- family battery (truth_gap_test.go, 34-row replay): ok.
|
||||
- live parity (check_warm_router_gap_parity.py, hermetic rig +
|
||||
deterministic fixture extension): 60/60.
|
||||
- go build / vet / gofmt: clean (exits 0/0/0).
|
||||
- Python tests/test_warm_router_correctness.py: auto 5/5; python-pin
|
||||
3/5 (2 failures PRE-EXIST on the stashed tree — the retired Python
|
||||
fallback recurses and degrades to -2.0; my lane touches Go only).
|
||||
- adjacent suites (graph_health, ffi_query_memory_smoke): 4 passed,
|
||||
1 skipped.
|
||||
|
||||
## Divergences (documented, not bugs)
|
||||
|
||||
- graph_context returns the bare "### Graph memory ..." header when
|
||||
limit=0 truncates a non-empty list (oracle checks the full list).
|
||||
- incoming graph edges append without dedupe (collaborates_with x2 in
|
||||
the Alice payload) — reproduced verbatim in the battery mirror.
|
||||
- primitive budgets: budget=0 yields [] (the oracle's first body always
|
||||
fires budget-free only in route()'s own loop, not in this fn).
|
||||
@@ -0,0 +1 @@
|
||||
0
|
||||
Whitespace-only changes.
@@ -0,0 +1 @@
|
||||
0
|
||||
Whitespace-only changes.
@@ -0,0 +1 @@
|
||||
0
|
||||
@@ -0,0 +1 @@
|
||||
OK: 34 cases byte-identical against live oracle rune.warm_router
|
||||
@@ -0,0 +1 @@
|
||||
0
|
||||
@@ -0,0 +1 @@
|
||||
ok rune/warm-router (cached)
|
||||
@@ -0,0 +1 @@
|
||||
0
|
||||
@@ -0,0 +1,2 @@
|
||||
|
||||
parity: 60/60 — all green
|
||||
@@ -0,0 +1 @@
|
||||
0
|
||||
@@ -0,0 +1,2 @@
|
||||
..... [100%]
|
||||
5 passed in 0.24s
|
||||
@@ -0,0 +1 @@
|
||||
1
|
||||
@@ -0,0 +1,49 @@
|
||||
.F.F. [100%]
|
||||
=================================== FAILURES ===================================
|
||||
__________ TestEntryIdActivation.test_fired_entry_scores_above_floor ___________
|
||||
|
||||
self = <tests.test_warm_router_correctness.TestEntryIdActivation object at 0x7fbe296de850>
|
||||
tmp_path = PosixPath('/tmp/pytest-of-nick/pytest-744/test_fired_entry_scores_above_0')
|
||||
monkeypatch = <_pytest.monkeypatch.MonkeyPatch object at 0x7fbe29348c30>
|
||||
|
||||
def test_fired_entry_scores_above_floor(self, tmp_path, monkeypatch):
|
||||
db_path = str(tmp_path / "h2.db")
|
||||
db = sqlite3.connect(db_path)
|
||||
db.execute("CREATE TABLE use_history (entry_id INTEGER, used_at TEXT, "
|
||||
"session_id TEXT, outcome TEXT)")
|
||||
db.executemany(
|
||||
"INSERT INTO use_history VALUES (?,?,?,?)",
|
||||
[(7, "2026-10-07T12:00:00+00:00", "s", "helpful"),
|
||||
(7, "2026-10-07T18:00:00+00:00", "s", "helpful"),
|
||||
(7, "2026-10-07T23:00:00+00:00", "s", "helpful")])
|
||||
db.commit()
|
||||
monkeypatch.setattr(wr, "STORE_DB", db_path)
|
||||
score = wr.base_level_activation(7, now_iso="2026-10-08T00:00:00+00:00")
|
||||
> assert score > -2.0 # three recent firings lift above the floor
|
||||
^^^^^^^^^^^^^^^^^^^
|
||||
E assert -2.0 > -2.0
|
||||
|
||||
tests/test_warm_router_correctness.py:59: AssertionError
|
||||
__________ TestWashChangesRetrieval.test_use_history_changes_ranking ___________
|
||||
|
||||
self = <tests.test_warm_router_correctness.TestWashChangesRetrieval object at 0x7fbe296de710>
|
||||
tmp_path = PosixPath('/tmp/pytest-of-nick/pytest-744/test_use_history_changes_ranki0')
|
||||
monkeypatch = <_pytest.monkeypatch.MonkeyPatch object at 0x7fbe29517350>
|
||||
|
||||
def test_use_history_changes_ranking(self, tmp_path, monkeypatch):
|
||||
"""A controlled ranking demonstrably changes when use-history is
|
||||
applied (#27 acceptance: reproduced, deterministic)."""
|
||||
base = wr.base_level_from_uses(
|
||||
["2026-10-07T23:00:00+00:00"], "2026-10-08T00:00:00+00:00")
|
||||
boosted = wr.base_level_from_uses(
|
||||
["2026-10-07T12:00:00+00:00", "2026-10-07T18:00:00+00:00",
|
||||
"2026-10-07T23:00:00+00:00"], "2026-10-08T00:00:00+00:00")
|
||||
> assert boosted > base # more history = higher activation
|
||||
^^^^^^^^^^^^^^^^^^^^^
|
||||
E assert -2.0 > -2.0
|
||||
|
||||
tests/test_warm_router_correctness.py:96: AssertionError
|
||||
=========================== short test summary info ============================
|
||||
FAILED tests/test_warm_router_correctness.py::TestEntryIdActivation::test_fired_entry_scores_above_floor
|
||||
FAILED tests/test_warm_router_correctness.py::TestWashChangesRetrieval::test_use_history_changes_ranking
|
||||
2 failed, 3 passed in 0.28s
|
||||
@@ -0,0 +1 @@
|
||||
0
|
||||
@@ -0,0 +1,2 @@
|
||||
....s [100%]
|
||||
4 passed, 1 skipped in 0.41s
|
||||
@@ -0,0 +1 @@
|
||||
0
|
||||
Whitespace-only changes.
Reference in new issue
Block a user