Files
rune/tests/test_cache.py
T
Nick f944d7df38 feat(cache): close PARTIAL gaps — dichotomy wave
Port the eleven audit-named missing fns name-preserving 1:1 from
src/rune/cache.py (recordHit/_record_hit, recordMiss, flushStats,
getCache, putCache, invalidateScope, invalidateAll, nowTs, parseTs,
cacheStats, handleHook) with the in-memory hit/miss accumulation
(threshold 50 / interval 30s), INVALIDATION_MAP, full schema (both
indexes) and an oracle-byte-parity CLI (usage gates, --json indent=2,
rune-aware :20 padding and [:200] truncation, compact hook line,
PLUGIN manifest). Clock/monotonic/DB behind Env seams.

Frozen truth: 78 cases via the shared freeze_truth.py harness
(envelope, pinned clock, sandboxed RUNE_MEMORY_DIR), byte-identical
regen + --verify green. Go battery replays verbatim + flush-branch
seam pins + 16-case CLI live parity (100%). Python oracle battery 12
passed BOTH pins. Audit: cache 6/17 -> 17/17 FULL (GO).
2026-10-14 02:59:43 +01:00

164 lines
5.8 KiB
Python

"""Cache oracle battery — dichotomy wave gap closure (#2479).
The Go core (src/go/cache) ports the eleven audit-named missing fns
1:1; this battery pins the PYTHON ORACLE itself (sandboxed memory dir,
frozen clock, monkeypatched monotonic — no real filesystem writes
outside the sandbox) and cross-checks the committed frozen truth
byte-identically against the live oracle (delegation-live law). Both
pins run green: RUNE_CACHE_CORE=python and unset (cache has no core
seam — the pin documents the freeze convention either way).
"""
import importlib
import json
import os
import sqlite3
import subprocess
import sys
import tempfile
from pathlib import Path
import pytest
ROOT = Path(__file__).resolve().parent.parent
sys.path.insert(0, str(ROOT / "src"))
FROZEN = ROOT / "src/go/cache/frozen_truth.json"
FROZEN_NOW = "2026-10-13T12:00:00+00:00"
@pytest.fixture()
def oracle(monkeypatch, tmp_path):
"""A freshly-imported rune.cache against a throwaway DB with a
frozen clock (module globals reset — import-time DB_PATH derived
from the sandbox)."""
monkeypatch.setenv("RUNE_MEMORY_DIR", str(tmp_path))
monkeypatch.setenv("RUNE_FROZEN_NOW", FROZEN_NOW)
import rune.cache as cache_mod
mod = importlib.reload(cache_mod)
return mod
def db_hit_miss(mod, key):
db = sqlite3.connect(mod.DB_PATH)
try:
row = db.execute("SELECT hit_count, miss_count FROM cache WHERE key=?", (key,)).fetchone()
return row
finally:
db.close()
def test_frozen_truth_replay(oracle):
"""The committed truth replays against the live oracle: same case
sequence, same sandbox conditions, identical expected values."""
doc = json.loads(FROZEN.read_text())
assert doc["frozen_now"] == FROZEN_NOW
cases = []
for c in doc["cases"]:
cases.append({"fn": c["fn"], "args": c["args"], "kwargs": c.get("kwargs", {})})
sys.path.insert(0, str(ROOT / "scripts"))
from freeze_truth import freeze as _freeze
fresh = _freeze("rune.cache", cases, oracle_module="rune.cache")
assert len(fresh) == len(doc["cases"])
for frozen, live in zip(doc["cases"], fresh):
assert frozen["expected"] == live["expected"], f"divergence at {frozen['fn']}"
assert json.loads(json.dumps(fresh)) == json.loads(json.dumps(doc["cases"]))
def test_pending_hit_visibility(oracle):
"""The double-get audit fix: the pending in-memory count is visible
to the NEXT get before any flush (row + pending invariant)."""
oracle.put_cache("k", "value")
first = oracle.get_cache("k")
second = oracle.get_cache("k")
assert first["hit_count"] == 0
assert second["hit_count"] == 1
def test_true_miss_writes_nothing(oracle):
"""A key never seen records no miss (no write-on-read for ghosts)."""
result = oracle.get_cache("ghost")
assert result == {"hit": False, "key": "ghost"}
assert oracle._miss_counts == {}
def test_invalidated_miss_records(oracle):
oracle.put_cache("k", "v")
oracle.invalidate("k")
assert oracle.get_cache("k") == {"hit": False, "key": "k"}
assert oracle._miss_counts.get("k") == 1
def test_flush_threshold(oracle):
"""_FLUSH_THRESHOLD=50: no DB write before the 50th event, all
pending counts land on it."""
oracle.put_cache("k", "v")
for _ in range(oracle._FLUSH_THRESHOLD - 1):
oracle.get_cache("k")
assert db_hit_miss(oracle, "k")[0] == 0
oracle.get_cache("k") # the 50th event
assert db_hit_miss(oracle, "k")[0] == oracle._FLUSH_THRESHOLD
def test_flush_interval(oracle, monkeypatch):
"""_FLUSH_INTERVAL=30s: a monotonic jump past the interval flushes
on the next record (the branch the frozen truth cannot idle for)."""
real_monotonic = oracle.time.monotonic
t = {"now": real_monotonic()}
monkeypatch.setattr(oracle.time, "monotonic", lambda: t["now"])
oracle.put_cache("k", "v")
oracle.get_cache("k")
assert db_hit_miss(oracle, "k")[0] == 0
t["now"] += oracle._FLUSH_INTERVAL + 0.5
oracle.get_cache("k")
assert db_hit_miss(oracle, "k")[0] == 2
def test_upsert_preserves_counts(oracle):
oracle.put_cache("k", "v1")
oracle.get_cache("k")
oracle.get_cache("k")
oracle.cache_stats() # flush -> DB hit_count 2
oracle.put_cache("k", "v2") # upsert must NOT reset stats
assert db_hit_miss(oracle, "k")[0] == 2
assert oracle.get_cache("k")["hit_count"] == 2
def test_hit_rate_half_even():
"""f'{x:.0f}%' ties round half-to-even (quirk #3 family); the Go
port's %.0f must agree (pinned in cache_test.go)."""
assert f"{12.5:.0f}" == "12"
assert f"{13.5:.0f}" == "14"
def test_invalidation_map_scopes(oracle):
result = oracle.handle_hook("memory.created", {})
assert result["scopes"] == ["retrieval", "warm_digest"]
assert oracle.handle_hook("nothing.here", None) == {
"status": "ok", "event": "nothing.here", "handler": "cache"}
def test_plugin_manifest(oracle):
assert oracle.PLUGIN["name"] == "cache"
assert oracle.PLUGIN["hooks"] == {
"on_session_end": "handle_hook", "on_memory_add": "handle_hook"}
assert oracle.PLUGIN["auto_activate"] is True
def test_cli_usage_bytes(tmp_path):
"""The oracle CLI usage gates print exactly these bytes."""
env = dict(os.environ, RUNE_MEMORY_DIR=str(tmp_path),
PYTHONPATH=str(ROOT / "src"))
r = subprocess.run([sys.executable, "-m", "rune.cache", "get"],
capture_output=True, text=True, cwd=ROOT, env=env)
assert r.returncode == 0
assert r.stdout == "usage: cache.py get <key>\n"
def test_compress_and_hash(oracle):
text = "# comment\n====\nkeep this substantive line\n(_source_: cite)\nab\n"
compressed = oracle._compress(text)
assert compressed == "keep this substantive line"
assert oracle._hash("hello") == __import__("hashlib").sha256(b"hello").hexdigest()[:16]