Files
rune/tests/test_p1_03_memory_selection.py
T
Nick f5dfd4e6b9
CI Pipeline / best-practices (push) Successful in 9s
CI Pipeline / documentation (push) Successful in 10s
CI Pipeline / required-checks (push) Canceled after 0s
CI Pipeline / CI Pipeline / notify-event-bridge (push) Canceled after 0s
CI Pipeline / rust-surface (push) Canceled after 13s
deploy / deploy (push) Canceled after 2s
Auto-version and Release / release (push) Canceled after 15s
CI Pipeline / go-surface (push) Canceled after 15s
CI Pipeline / canary (push) Canceled after 16s
CI Pipeline / type-check (push) Canceled after 11s
CI Pipeline / unit-tests (push) Canceled after 20s
CI Pipeline / lint (push) Canceled after 20s
CI Pipeline / gitea-offline (push) Canceled after 10s
feat(memory_selector): port to FULL Rust — dichotomy wave
RUST verdict (dichotomy law, #2479 tranche): the module's pure decision
math is ported to src/rust/memory_selector — select_core (ONE floor with
store_scored exemption, stable raw-score ranking, budget cap, block
building, abstention, irrelevant_rate) + per-source post-IO kernels
(neurons trigger-scan, graphs entity-reach fallback, abstraction LIKE
floor, consolidated floor, persona wanted-gate, store dedup+projection).
IO stays Python: source gathering (store recall, list_neurons, graph
query, LIKE scan, consolidation read).

Wiring: mse_loader.py ctypes (doc-envelope, cs_free_string — no free
symbol re-export), facade delegation in memory_selector.py with
RUNE_MSE_CORE=python fallback pin, 7-case battery embedded verbatim from
the frozen oracle truth (16 select + 4 neurons + 2 graphs + abstraction +
consolidated + 4 wanted + 3 store cases).

Parity: 41/41 live (Rust core vs frozen oracle on the whole truth
surface, through the delegating facade); battery 7/7 in-crate; clippy 0
warnings; polyglot lint clean for the crate.

Tests: p1_03 memory_selection 68/68 in both pin states (2 new fallback-
pin discipline tests); full suite 2622 passed — 3 pre-existing failures
confirmed identical on the clean tree (ci_lint_baseline, t214 spine
seeds, umbrella manifest) + one env-only fix applied to
test_ffi_query_memory_smoke (PYTHONPATH for the subprocess).

Audit: memory_selector 11/14 (79%, PARTIAL — gaps are Python-only glue:
_mse_core probe, add_source registry, _source_store one-line delegate).
2026-10-11 10:38:12 +01:00

1542 lines
62 KiB
Python

"""P1-03 (#26) frozen tests — unified memory selection + true abstention.
Frozen tests are the spec. Each task's tests land red first, then the
implementation makes them green. Covers:
- Task 1: ``memory_type`` column + backfill migration + typed recall filter;
- Task 2: ``MemorySelector`` skeleton, store-recall source, true abstention,
ContextBroker composition;
- Task 3: remaining selector sources (neurons WITHOUT the importance
fallback, graphs, abstraction, de-bypassed consolidated, typed persona);
- Task 4: operator single-contributor collapse + TaskState supremacy;
- Task 5: memory sub-budget, trace fields, canary, docs.
Acceptance criteria from #26: a trivial task can legitimately receive ZERO
recalled memories; the irrelevant-memory rate is measured; old-task retrieval
can never override the active TaskState.
"""
from __future__ import annotations
import json
import math
import sqlite3
import sys
import tempfile
from pathlib import Path
import pytest
ROOT = Path(__file__).resolve().parents[1]
sys.path.insert(0, str(ROOT / "src"))
from rune import memory_store as ms # noqa: E402
# ---------------------------------------------------------------------------
# Isolation helpers — every test gets its own store DB and Rune home so the
# suite never touches a real memory store (preserve-stores constraint).
# ---------------------------------------------------------------------------
@pytest.fixture(autouse=True)
def _isolated_memory_env(tmp_path, monkeypatch):
"""Point RUNE_HOME / RUNE_MEMORY_DIR / the store DB at tmp_path and force
lexical-only recall (no Ollama, no embeddings) — deterministic. The
consolidation dir is isolated too: memory_consolidation hardcodes
~/.rune/consolidation and must never read real user data here."""
home = tmp_path / "home"
mem = tmp_path / "memory"
monkeypatch.setenv("RUNE_HOME", str(home))
monkeypatch.setenv("RUNE_MEMORY_DIR", str(mem))
monkeypatch.setattr(ms, "DB_PATH", str(mem / "store" / "memory.db"))
monkeypatch.setattr(ms, "STORE_DIR", str(mem / "store"))
from rune import memory_consolidation as _mc
consolidation_dir = tmp_path / "consolidation"
monkeypatch.setattr(_mc, "CONSOLIDATION_DIR", str(consolidation_dir))
monkeypatch.setattr(_mc, "KNOWLEDGE_FILE", str(consolidation_dir / "knowledge.json"))
monkeypatch.setattr(_mc, "LESSONS_FILE", str(consolidation_dir / "lessons.json"))
monkeypatch.setattr(_mc, "CONNECTIONS_FILE", str(consolidation_dir / "connections.json"))
_no_embed(monkeypatch)
yield
def _no_embed(monkeypatch):
"""Force lexical-only recall: no Ollama, no embeddings, deterministic."""
monkeypatch.setattr(ms, "_embed", lambda texts: {})
def _add(db, text, kind="fact", memory_type=None, importance=0.5):
"""Insert an entry the way the store's own writer would (no embedding in
tests — FTS is what recall matches on)."""
from rune.memory_store import now_iso
cur = db.execute(
"INSERT INTO entries (text, importance, created_at, last_accessed, "
"topic, entities, source, method, status, kind, memory_type) "
"VALUES (?,?,?,?,?,?,?,?,?,?,?)",
(
text,
importance,
now_iso(),
now_iso(),
"",
"[]",
"test",
"curator",
"active",
kind,
memory_type,
),
)
db.execute("INSERT INTO entries_fts (rowid, text) VALUES (?,?)", (cur.lastrowid, text))
db.commit()
return cur.lastrowid
# ---------------------------------------------------------------------------
# Task 1 — memory_type column + backfill migration + typed recall filter
# ---------------------------------------------------------------------------
def test_memory_type_column_exists_after_migration():
db = ms.connect()
try:
cols = {row[1] for row in db.execute("PRAGMA table_info(entries)")}
finally:
db.close()
assert "memory_type" in cols, "migration must add the memory_type column"
def test_ensure_memory_type_column_is_idempotent():
db = ms.connect()
try:
ms.ensure_memory_type_column(db)
ms.ensure_memory_type_column(db) # must not raise
cols = {row[1] for row in db.execute("PRAGMA table_info(entries)")}
assert "memory_type" in cols
finally:
db.close()
def test_backfill_classifies_only_neuron_rows():
"""kind='neuron' -> 'associative'; every other row stays NULL."""
db = ms.connect()
try:
_add(db, "Kubernetes pods restart automatically on failure", kind="neuron")
_add(db, "Kubernetes pods restart policy for the cluster", kind="fact")
_add(db, "Kubernetes pods restart behavior in the runbook", kind="consolidated")
ms.ensure_memory_type_column(db)
rows = db.execute("SELECT kind, memory_type FROM entries ORDER BY kind").fetchall()
by_kind = {row["kind"]: row["memory_type"] for row in rows}
assert by_kind["neuron"] == "associative", "neurons must backfill to associative"
assert by_kind["fact"] is None, "non-neuron rows must stay NULL (unclassified)"
assert by_kind["consolidated"] is None, "non-neuron rows must stay NULL"
finally:
db.close()
def test_backfill_runs_on_legacy_db_without_the_column(tmp_path):
"""A pre-existing DB lacking memory_type migrates in place: column added,
neurons backfilled, other rows untouched."""
legacy = sqlite3.connect(tmp_path / "legacy.db")
legacy.row_factory = sqlite3.Row
legacy.execute(
"CREATE TABLE entries (id INTEGER PRIMARY KEY AUTOINCREMENT, text TEXT, "
"kind TEXT DEFAULT 'fact', status TEXT DEFAULT 'active')"
)
legacy.execute("INSERT INTO entries (text, kind) VALUES ('legacy neuron body here', 'neuron')")
legacy.execute("INSERT INTO entries (text, kind) VALUES ('legacy fact body here', 'fact')")
legacy.commit()
ms.ensure_memory_type_column(legacy)
cols = {row[1] for row in legacy.execute("PRAGMA table_info(entries)")}
assert "memory_type" in cols
rows = legacy.execute("SELECT kind, memory_type FROM entries ORDER BY kind").fetchall()
by_kind = {row["kind"]: row["memory_type"] for row in rows}
assert by_kind["neuron"] == "associative"
assert by_kind["fact"] is None
legacy.close()
def test_typed_recall_returns_typed_and_null_excludes_other_types(monkeypatch):
"""memory_types filter keeps matching + NULL rows, drops other types."""
_no_embed(monkeypatch)
db = ms.connect()
try:
_add(db, "Kubernetes pods restart automatically on failure", memory_type="associative")
_add(db, "Kubernetes pods restart policy for the cluster", memory_type="episodic")
_add(db, "Kubernetes pods restart behavior in the runbook", memory_type=None)
results = ms.recall(db, "kubernetes pods restart", memory_types=["associative"])
texts = [r["text"] for r in results]
assert any("automatically" in t for t in texts), "typed row must be returned"
assert any("runbook" in t for t in texts), "NULL (unclassified) row must be returned"
assert not any("policy" in t for t in texts), "other-type row must be excluded"
finally:
db.close()
def test_typed_recall_accepts_multiple_types(monkeypatch):
_no_embed(monkeypatch)
db = ms.connect()
try:
_add(db, "Kubernetes pods restart automatically on failure", memory_type="self")
_add(db, "Kubernetes pods restart policy for the cluster", memory_type="personality")
_add(db, "Kubernetes pods restart behavior in the runbook", memory_type="associative")
results = ms.recall(db, "kubernetes pods restart", memory_types=["self", "personality"])
texts = [r["text"] for r in results]
assert any("automatically" in t for t in texts)
assert any("policy" in t for t in texts)
assert not any("runbook" in t for t in texts)
finally:
db.close()
def test_untyped_recall_unchanged_by_typed_rows(monkeypatch):
"""memory_types=None behaves exactly as before: type never excludes."""
_no_embed(monkeypatch)
db = ms.connect()
try:
_add(db, "Kubernetes pods restart automatically on failure", memory_type="associative")
_add(db, "Kubernetes pods restart policy for the cluster", memory_type="episodic")
_add(db, "Kubernetes pods restart behavior in the runbook", memory_type=None)
results = ms.recall(db, "kubernetes pods restart")
texts = [r["text"] for r in results]
assert len(texts) == 3, "untyped recall must see every matching row"
finally:
db.close()
def test_recall_abstains_when_nothing_matches(monkeypatch):
"""True abstention survives the migration: no match -> []."""
_no_embed(monkeypatch)
db = ms.connect()
try:
_add(db, "Quarterly fiscal audit committee schedule for review")
assert ms.recall(db, "kubernetes pods restart") == []
finally:
db.close()
# ---------------------------------------------------------------------------
# Task 2 — MemorySelector skeleton + store-recall source + true abstention
# ---------------------------------------------------------------------------
def test_selector_default_floor_is_the_store_floor():
from rune.memory_selector import MemorySelector
sel = MemorySelector(db_path=":memory:")
assert sel.min_score == ms.RECALL_MIN_SCORE
def test_select_for_task_result_fields():
from rune.memory_selector import MemorySelector, SelectionResult
sel = MemorySelector(db_path=":memory:")
result = sel.select_for_task("what time is it")
assert isinstance(result, SelectionResult)
assert result.blocks == []
assert isinstance(result.candidates_evaluated, int)
assert isinstance(result.selected_count, int)
assert isinstance(result.abstained, bool)
assert isinstance(result.types_queried, list)
def test_trivial_task_receives_zero_blocks():
"""THE acceptance criterion: a trivial task abstains — ZERO memory."""
db = ms.connect()
try:
_add(db, "Kubernetes pods restart automatically on failure")
finally:
db.close()
from rune.memory_selector import MemorySelector
sel = MemorySelector(db_path=ms.DB_PATH)
result = sel.select_for_task("what time is it")
assert result.blocks == [], "trivial task must receive ZERO memory blocks"
assert result.abstained is True
assert result.selected_count == 0
def test_relevant_task_returns_memory_block():
db = ms.connect()
try:
_add(db, "Kubernetes pods restart automatically on failure")
_add(db, "Kubernetes pods restart policy for the cluster")
_add(db, "Kubernetes pods restart behavior in the runbook")
finally:
db.close()
from rune.memory_selector import MemorySelector
sel = MemorySelector(db_path=ms.DB_PATH)
result = sel.select_for_task("kubernetes pods restart automatically")
assert result.blocks, "relevant task must surface memory"
assert result.abstained is False
assert result.selected_count == len(result.blocks)
block = result.blocks[0]
assert block.name == "memory"
assert "Kubernetes" in block.content
assert block.source == "memory_selector.select_for_task"
assert block.evictable is True
def test_below_floor_candidates_counted_but_not_selected():
"""Uniform floor: a source candidate scoring below min_score is counted
(candidates_evaluated) but never selected — the irrelevant-memory rate
(candidates - selected) / candidates is computable."""
from rune.memory_selector import MemorySelector
sel = MemorySelector(db_path=ms.DB_PATH)
def weak_source(query, types, budget, min_score):
return [{"text": "weakly related fragment", "score": 0.2, "kind": "probe"}]
sel.add_source("probe", weak_source)
result = sel.select_for_task("kubernetes pods restart")
assert result.blocks == [], "below-floor candidates must not become blocks"
assert result.candidates_evaluated == 1, "candidates still counted"
assert result.selected_count == 0
assert result.abstained is True
def test_above_floor_source_candidate_selected():
"""The floor is the ONLY gate at the selector: a high-scoring candidate
is selected regardless of any importance-style side channel."""
from rune.memory_selector import MemorySelector
sel = MemorySelector(db_path=ms.DB_PATH)
def strong_source(query, types, budget, min_score):
return [{"text": "strongly related memory fragment", "score": 0.9, "kind": "probe"}]
sel.add_source("probe", strong_source)
result = sel.select_for_task("kubernetes pods restart")
assert result.abstained is False
assert result.selected_count == 1
assert "strongly related memory fragment" in result.blocks[0].content
def test_selector_respects_budget_cap():
db = ms.connect()
try:
for i in range(6):
_add(db, f"Kubernetes pods restart automatically in cluster {i}")
finally:
db.close()
from rune.memory_selector import MemorySelector
sel = MemorySelector(db_path=ms.DB_PATH)
result = sel.select_for_task("kubernetes pods restart automatically", budget=2)
assert result.selected_count <= 2
assert result.candidates_evaluated >= result.selected_count
def test_selector_types_queried_recorded():
from rune.memory_selector import MemorySelector
sel = MemorySelector(db_path=ms.DB_PATH)
result = sel.select_for_task("what time is it", types=["associative", "episodic"])
assert result.types_queried == ["associative", "episodic"]
assert sel.select_for_task("what time is it").types_queried == []
def test_selector_empty_description_abstains():
from rune.memory_selector import MemorySelector
sel = MemorySelector(db_path=ms.DB_PATH)
result = sel.select_for_task("")
assert result.blocks == []
assert result.abstained is True
def test_selector_source_failure_abstains_not_raises():
"""Degrade-not-crash: a failing source is skipped, never fail-open."""
from rune.memory_selector import MemorySelector
sel = MemorySelector(db_path=ms.DB_PATH)
def boom(query, types, budget, min_score):
raise RuntimeError("source exploded")
sel.add_source("boom", boom)
result = sel.select_for_task("kubernetes pods restart")
assert result.blocks == []
assert result.abstained is True
def test_selector_store_failure_abstains_and_logs(caplog):
"""The store source failing is an abstention + observable log."""
import logging
from rune.memory_selector import MemorySelector
sel = MemorySelector(db_path=ms.DB_PATH)
def boom(query, types, budget, min_score):
raise RuntimeError("store exploded")
with caplog.at_level(logging.WARNING, logger="rune.memory_selector"):
sel.add_source("store", boom) # replace the store source
result = sel.select_for_task("kubernetes pods restart")
assert result.blocks == []
assert result.abstained is True
assert any("store" in record.message.lower() for record in caplog.records)
def test_selector_passes_floor_to_store_recall():
"""One floor constant: the store source receives the selector's min_score
(the store's calibrated gate applies it — no second, divergent floor)."""
from rune import memory_store as store
from rune.memory_selector import MemorySelector
captured: dict = {}
original = store.recall
def spy(db, query, **kwargs):
captured.update(kwargs)
return original(db, query, **kwargs)
ms.recall = spy # noqa: N806 - module attr swap, restored below
try:
sel = MemorySelector(db_path=ms.DB_PATH, min_score=0.63)
sel.select_for_task("kubernetes pods restart")
finally:
ms.recall = original # noqa: N806
assert captured.get("min_score") == 0.63
# ---------------------------------------------------------------------------
# Task 2 — ContextBroker composition (authority map v1_owner)
# ---------------------------------------------------------------------------
def test_broker_composes_memory_selector():
from rune.context_broker import ContextBroker
broker = ContextBroker()
assert getattr(broker, "memory_selector", None) is not None, (
"ContextBroker must own the memory selector (authority map v1_owner)"
)
def test_broker_memory_selector_selects_for_task():
from rune.context_broker import ContextBroker
from rune.memory_selector import SelectionResult
broker = ContextBroker()
result = broker.memory_selector.select_for_task("kubernetes pods restart")
assert isinstance(result, SelectionResult)
def test_authority_map_memory_selection_v1_owner():
import json
manifest = json.loads((ROOT / "config" / "v1_authority_map.json").read_text())
responsibility = next(r for r in manifest["responsibilities"] if r["id"] == "memory_selection")
assert responsibility["v1_owner"] == "ContextBroker.memory_selector"
# ---------------------------------------------------------------------------
# Task 4 — operator single-contributor collapse + TaskState supremacy
# (red until Task 4: these assert on the operator source itself)
# ---------------------------------------------------------------------------
def test_operator_hardcoded_persona_query_gone():
"""The operator no longer carries the hardcoded persona query string."""
import inspect
from rune import rune_operator
source = inspect.getsource(rune_operator)
assert '"Rune personality voice identity how to speak"' not in source
def test_operator_importance_fallback_gone():
"""The forbidden top-5-importance fallback is deleted from the operator —
ALL of its patterns are grepped (discharge finding 6: one literal is not
enough), and a behavioral twin proves an off-trigger high-importance
neuron is not injected through the operator's contributor."""
import inspect
from rune import rune_operator
source = inspect.getsource(rune_operator)
for pattern in (
"reverse=True)[:5]", # the original fallback slice
"reverse=True)[: 5]",
"reverse=True) [:5]",
"top_5",
"top-5",
):
assert pattern not in source, f"the importance-fallback pattern {pattern!r} must stay removed"
# Behavioral twin at operator level: importance alone never injects.
_seed_neuron(
"Quarterly fiscal audit committee schedule for review",
triggers="audit",
importance=0.99,
)
op = ro.RuneOperator(str(Path(tempfile.mkdtemp()) / "operator.json"))
task = mock.Mock(description="kubernetes pods restart")
task.task_id = "t-fallback"
block = op._contributor_memory(task, {})
assert block is None or "fiscal audit" not in block.content, (
"an off-trigger high-importance neuron must not inject through the operator"
)
# ---------------------------------------------------------------------------
# Task 3 — remaining selector sources; the bypasses die here
# ---------------------------------------------------------------------------
def _seed_neuron(text, triggers="", importance=0.5):
db = ms.connect()
try:
return _add(db, text, kind="neuron", memory_type="associative", importance=importance)
finally:
db.close()
def test_high_importance_irrelevant_neuron_not_injected():
"""THE fallback kill: a high-importance neuron that does not match the
task is NOT injected merely because it is important."""
from rune.memory_selector import MemorySelector
_seed_neuron(
"Quarterly fiscal audit committee schedule for review",
triggers="audit",
importance=0.99,
)
sel = MemorySelector(db_path=ms.DB_PATH)
result = sel.select_for_task("kubernetes pods restart automatically")
texts = [b.content for b in result.blocks]
assert not any("fiscal audit" in t for t in texts), "importance alone must never inject an irrelevant neuron"
assert result.abstained is True
def test_relevant_neuron_still_surfaces_via_selector():
"""Trigger-matched neurons flow through the selector, above the floor."""
from rune.memory_selector import MemorySelector
_seed_neuron("Kubernetes pods restart automatically on failure", triggers="kubernetes", importance=0.9)
sel = MemorySelector(db_path=ms.DB_PATH)
result = sel.select_for_task("kubernetes pods restart")
assert result.abstained is False
assert any("Kubernetes" in b.content for b in result.blocks)
def test_consolidated_item_below_floor_abstains():
"""THE flat-0.8 kill: a consolidated item is a candidate under the ONE
floor — below it, the selector abstains."""
from rune import memory_selector as selmod
from rune.memory_selector import MemorySelector
sel = MemorySelector(db_path=ms.DB_PATH)
def consolidated_source(query, types, budget, min_score):
return [{"text": "consolidated trivia", "score": 0.3, "kind": "consolidated"}]
sel.add_source("consolidated", consolidated_source)
result = sel.select_for_task("kubernetes pods restart")
assert result.blocks == [], "consolidated knowledge must compete under the same floor"
assert result.abstained is True
assert result.candidates_evaluated >= 1
def test_gate_consolidated_bypass_removed_from_cached_recall():
"""cached_recall routes EVERY query through the thresholded recall — the
flat-0.8 consolidated shortcut is gone from the code path."""
import inspect
source = inspect.getsource(ms.cached_recall)
assert "gate_consolidated" not in source, "cached_recall must no longer consult gate_consolidated's flat-0.8 bypass"
assert "0.8" not in source, "the flat relevance=0.8 shortcut must be gone"
def _no_shards(monkeypatch):
"""Disable shard routing (cached_recall would silently reroute to an
empty out-of-repo shard, vacating assertions)."""
monkeypatch.setitem(sys.modules, "shard_manager", None)
def test_cached_recall_never_returns_flat_eight_tenths(monkeypatch):
"""Behavioral (discharge finding 6): whatever cached_recall returns, every
row is a thresholded recall row — it either carries the store's calibrated
scoring fields, or it abstains. No flat-0.8 injection rows exist.
(Shard routing is disabled: it can silently reroute to an empty shard,
which would make this assertion vacuously pass.)"""
_no_embed(monkeypatch)
_no_shards(monkeypatch)
db = ms.connect()
try:
_add(db, "Kubernetes pods restart automatically on failure shapecheck")
results = ms.cached_recall(db, "kubernetes pods restart shapecheck", budget=3)
for row in results:
assert isinstance(row, dict)
# A thresholded recall row carries the calibrated fields the
# store's gate produces (rrf/confidence/id). An injected
# flat-relevance row would not.
assert "rrf" in row and "confidence" in row and "id" in row, (
f"row lacks the calibrated recall fields (flat-injection shape?): {sorted(row)}"
)
# relevance is the store's blended score (metadata-scaled), never
# the old hardcoded flat 0.8.
assert float(row.get("relevance", -1)) != 0.8, "flat 0.8 relevance row detected"
assert all(isinstance(r, dict) for r in results)
finally:
db.close()
def test_cached_recall_abstains_without_matches(monkeypatch):
"""Behavioral twin (discharge finding 6): with a seeded DISTRACTOR that
cannot match, cached_recall returns NOTHING — scored-or-abstained, never
a fallback injection."""
_no_embed(monkeypatch)
_no_shards(monkeypatch)
db = ms.connect()
try:
_add(db, "Quarterly fiscal audit committee schedule for review", importance=0.99)
results = ms.cached_recall(db, "kubernetes pods restart absentprobe", budget=3)
assert results == [], "no matching rows must mean zero output (abstention)"
finally:
db.close()
def test_cached_recall_returns_calibrated_rows_on_match(monkeypatch):
"""Behavioral twin (discharge finding 6): a real match returns real
thresholded rows with the calibrated fields — the positive branch of the
scored-or-abstained contract."""
_no_embed(monkeypatch)
_no_shards(monkeypatch)
db = ms.connect()
try:
_add(db, "Kubernetes pods restart automatically on failure positivecheck")
_add(db, "Kubernetes pods restart policy for the cluster positivecheck")
results = ms.cached_recall(db, "kubernetes pods restart positivecheck", budget=3)
assert results, "a genuine conjunctive match must surface rows"
for row in results:
assert "rrf" in row and "relevance" in row and float(row["relevance"]) > 0
finally:
db.close()
def test_persona_typed_query_replaces_hardcoded_query():
"""The persona source queries self/personality types derived from the
ACTIVE task — the hardcoded 'Rune personality voice identity how to
speak' query is gone."""
from rune.memory_selector import MemorySelector
sel = MemorySelector(db_path=ms.DB_PATH)
captured: dict = {}
def spy(query, types, budget, min_score):
captured["query"] = query
captured["types"] = types
return []
sel.add_source("persona", spy)
sel.select_for_task("fix the login timeout bug", types=["self", "personality"])
assert "how to speak" not in captured["query"], (
"the hardcoded persona query must be replaced by the active-task query"
)
assert captured["types"] == ["self", "personality"]
def test_persona_typed_query_thresholded_and_abstains_on_trivial():
"""Persona memory is thresholded like every source: a trivial task gets
zero persona lines."""
db = ms.connect()
try:
_add(db, "I speak in one clean sentence, evidence first", memory_type="personality", importance=0.95)
finally:
db.close()
from rune.memory_selector import MemorySelector
sel = MemorySelector(db_path=ms.DB_PATH)
result = sel.select_for_task("what time is it", types=["self", "personality"])
texts = [b.content for b in result.blocks]
assert not any("one clean sentence" in t for t in texts), "persona memory must abstain on an unrelated trivial task"
assert result.abstained is True
def test_persona_relevant_task_surfaces_persona_memory():
db = ms.connect()
try:
_add(db, "I speak in one clean sentence, evidence first", memory_type="personality", importance=0.95)
finally:
db.close()
from rune.memory_selector import MemorySelector
sel = MemorySelector(db_path=ms.DB_PATH)
result = sel.select_for_task("how do I speak in one clean sentence", types=["self", "personality"])
assert any("one clean sentence" in b.content for b in result.blocks)
def test_selector_registers_all_sources():
"""One selector, every source: store, neurons, graphs, abstraction,
consolidated, persona — the pre-P1-03 parallel paths' knowledge."""
from rune.memory_selector import MemorySelector
sel = MemorySelector(db_path=ms.DB_PATH)
for name in ("store", "neurons", "graphs", "abstraction", "consolidated", "persona"):
assert name in sel.source_names(), f"source {name!r} must be registered"
def test_neuron_source_failure_abstains():
"""warm_neuron_store failure -> source skipped, selector still works."""
from rune import memory_selector as selmod
from rune.memory_selector import MemorySelector
sel = MemorySelector(db_path=ms.DB_PATH)
def boom(query, types, budget, min_score):
raise RuntimeError("neuron store gone")
sel.add_source("neurons", boom)
db = ms.connect()
try:
_add(db, "Kubernetes pods restart automatically on failure")
finally:
db.close()
result = sel.select_for_task("kubernetes pods restart automatically")
assert result.abstained is False, "other sources still function"
assert result.selected_count >= 1
# ---------------------------------------------------------------------------
# Task 4 — operator single-contributor collapse + TaskState supremacy
# ---------------------------------------------------------------------------
import unittest.mock as mock # noqa: E402
from rune import rune_operator as ro # noqa: E402
def _mutating_response(**kw):
"""Mutation tasks need mutating tool evidence to complete (2026-09-10)."""
from rune.tool_protocol import ToolEvent, ToolRequest
base = dict(success=True, user_text="done", model="m")
base.update(kw)
base.setdefault(
"tool_events",
[
ToolEvent(
kind="completed",
request=ToolRequest(
call_id="w1", name="write", arguments={"path": "/tmp/x", "content": "x"}, source="model"
),
result={"success": True, "result": "wrote /tmp/x"},
)
],
)
return ro.OperatorResponse(**base)
def _operator(tmp_path):
return ro.RuneOperator(str(tmp_path / "operator.json"))
def test_exactly_one_memory_contributor_registered(tmp_path):
op = _operator(tmp_path)
broker = op._context_broker()
with broker._lock:
names = [name for name, _cb, _b in broker._contributors]
memory_names = [
n for n in names if n in {"memory", "persona_memories", "consolidated", "neurons", "graphs", "abstraction"}
]
assert memory_names == ["memory"], f"exactly ONE memory contributor must remain, got {memory_names}"
def test_memory_contributor_delegates_to_broker_selector(tmp_path):
"""Discharge (finding 5): the store is SEEDED so the positive branch is
exercised — the contributor must return a real selector-sourced block."""
db = ms.connect()
try:
_add(db, "Kubernetes pods restart automatically on failure")
_add(db, "Kubernetes pods restart policy for the cluster")
finally:
db.close()
op = _operator(tmp_path)
broker = op._context_broker()
assert getattr(broker, "memory_selector", None) is not None
task = mock.Mock(description="kubernetes pods restart automatically")
task.task_id = "t1"
block = op._contributor_memory(task, {})
assert block is not None, "seeded relevant memory must surface through the contributor"
assert block.source == "memory_selector.select_for_task"
assert "Kubernetes" in block.content
def test_trivial_task_prompt_contains_no_memory_blocks(tmp_path):
"""Acceptance: a trivial task's assembled prompt carries no memory block.
Discharge (finding 5): a high-importance DISTRACTOR is seeded first, so
the zero-memory proof is not vacuous — and a relevant-task positive
control proves the memory contributor actually fires when it should."""
db = ms.connect()
try:
_add(db, "Quarterly fiscal audit committee schedule for review", importance=0.99)
finally:
db.close()
op = _operator(tmp_path)
# Positive control: the contributor produces a selector-sourced block
# when the task IS relevant (the machinery works).
relevant = mock.Mock(description="quarterly fiscal audit committee schedule")
relevant.task_id = "t-pos"
positive = op._contributor_memory(relevant, {})
assert positive is not None, "positive control: relevant task must surface memory"
assert positive.source == "memory_selector.select_for_task"
# The actual invariant: the trivial task gets none of it.
task = mock.Mock(description="what time is it")
task.task_id = "t1"
session: dict = {}
collected = []
with broker_lock(op._context_broker()):
for name, cb, _bucket in op._context_broker()._contributors:
try:
block = cb(task, session)
except Exception:
block = None
if block is not None:
collected.append((name, block))
memory_names = {"memory", "persona_memories", "consolidated", "neurons", "graphs", "abstraction"}
for name, block in collected:
assert name not in memory_names or not block.content, f"trivial task must not produce memory block {name}"
def broker_lock(broker):
return broker._lock
def test_memory_blocks_all_come_from_selector(tmp_path):
"""Discharge (finding 5): the store is seeded so the contributor actually
returns a block — the source assertion is then positive, not vacuous."""
db = ms.connect()
try:
_add(db, "Kubernetes pods restart automatically on failure")
_add(db, "Kubernetes pods restart policy for the cluster")
finally:
db.close()
op = _operator(tmp_path)
task = mock.Mock(description="kubernetes pods restart automatically")
task.task_id = "t1"
produced: list = []
with broker_lock(op._context_broker()):
for name, cb, _bucket in op._context_broker()._contributors:
if name not in {"memory", "persona_memories", "consolidated", "neurons", "graphs", "abstraction"}:
continue
block = cb(task, {})
if block is not None:
produced.append(block)
assert block is None or block.source == "memory_selector.select_for_task", (
f"contributor {name} must delegate to the selector"
)
assert produced and any("Kubernetes" in b.content for b in produced), (
"seeded memory must flow through the selector-delegating contributor"
)
def test_history_rebased_on_task_state_repository(tmp_path):
"""The history block labels past-task content as context-only and its
priority stays strictly below the active task block (user=100).
Discharge (finding 5): a completed past task is SEEDED through the
canonical ledger so the priority/label assertions are positive."""
import inspect
op = _operator(tmp_path)
source = inspect.getsource(op._contributor_history)
assert "PAST TASK" in source, "past-task content must carry the context-only label"
assert "TaskStateRepository" in source or "_task_state" in source or "_conversation" in source, (
"history must rebase on the canonical TaskStateRepository/ConversationStateRepository"
)
from rune.orchestration.conversation_state import ConversationMessageRecord
from rune.orchestration.records import TaskStateRecord
from rune.rune_operator import OPERATOR_CHANNEL
past = TaskStateRecord(
title="deploy the kubernetes cluster to production",
channel_id=OPERATOR_CHANNEL,
status="completed",
)
assert op._task_state.import_record(past), "seed: past task record must import"
op._conversation.append(
ConversationMessageRecord(
role="user",
content="deploy the kubernetes cluster to production",
channel_id=OPERATOR_CHANNEL,
task_id=past.task_id,
)
)
op._conversation.append(
ConversationMessageRecord(
role="assistant",
content="Cluster deployed; all pods healthy in production.",
channel_id=OPERATOR_CHANNEL,
task_id=past.task_id,
)
)
block = op._contributor_history(mock.Mock(task_id="t-active"), {})
assert block is not None, "seeded completed past task must produce a history block"
assert block.priority < 100, "history priority must stay strictly below the active task block"
block_text = block.content if isinstance(block.content, str) else json.dumps(block.content, ensure_ascii=False)
assert "PAST TASK" in block_text, "seeded history block must carry the context-only label"
def test_recall_query_never_keyed_on_past_task_text(tmp_path):
"""The selector is queried with the ACTIVE task description only."""
op = _operator(tmp_path)
broker = op._context_broker()
with broker_lock(broker):
for name, cb, _bucket in broker._contributors:
if name != "memory":
continue
captured: dict = {}
def spy(query, types=None, budget=4):
captured["query"] = query
from rune.memory_selector import SelectionResult
return SelectionResult([], 0, 0, True, [])
broker.memory_selector.select_for_task = spy # type: ignore[method-assign]
task = mock.Mock(description="ACTIVE TASK DESCRIPTION")
task.task_id = "t1"
op._contributor_memory(task, {})
assert captured.get("query") == "ACTIVE TASK DESCRIPTION", (
"recall query must be keyed ONLY on the active task description"
)
def test_active_task_state_block_is_non_evictable(tmp_path):
"""The user block carries the active TaskState text and never evicts."""
op = _operator(tmp_path)
block = op._contributor_user(mock.Mock(description="active work"), {})
assert block.evictable is False
assert block.content == "active work"
def test_selector_unavailable_means_zero_memory_blocks(tmp_path):
"""Fail-closed: with no selector on the broker, the contributor abstains."""
op = _operator(tmp_path)
broker = op._context_broker()
with broker_lock(broker):
broker.memory_selector = None
task = mock.Mock(description="kubernetes pods restart automatically")
task.task_id = "t1"
assert op._contributor_memory(task, {}) is None
# ---------------------------------------------------------------------------
# Task 5 — memory sub-budget + trace fields + canary + docs
# ---------------------------------------------------------------------------
def test_memory_budget_default_is_min_cap_window_eighth():
from rune.context_broker import default_memory_budget
assert default_memory_budget(9600) == 1200, "min(1200, window // 8)"
assert default_memory_budget(3200) == 400, "small windows scale down"
assert default_memory_budget(None) == 1200, "no window -> cap only"
def test_memory_blocks_evicted_beyond_sub_budget(tmp_path):
"""ContextBroker owns the final memory budget: memory blocks beyond the
sub-budget are dropped even when the GLOBAL budget could fit them."""
from rune.context_broker import ContributionBlock, ContextBroker
broker = ContextBroker(
budget_resolver=lambda window: 10_000,
estimator=lambda text: len(text) // 4,
)
big_memory = "m" * 8000 # ~2000 tokens > the 1200-token sub-budget
broker.register_contributor(
"memory",
lambda task, session: ContributionBlock("memory", 70, big_memory, 0, "test"),
2,
)
broker.register_contributor(
"notes",
lambda task, session: ContributionBlock("notes", 65, "n" * 400, 0, "test"),
2,
)
task = mock.Mock(description="kubernetes pods restart")
task.task_id = "t1"
_capsule, trace = broker.assemble(task, {}, budget_tokens=10_000)
memory_records = [b for b in trace["blocks"] if b["name"] == "memory"]
assert memory_records and memory_records[0]["admitted"] is False, (
"a memory block above the sub-budget must be evicted"
)
assert "memory budget" in memory_records[0]["reason"]
assert trace["memory_tokens"] == 0
notes_records = [b for b in trace["blocks"] if b["name"] == "notes"]
assert notes_records and notes_records[0]["admitted"] is True, (
"non-memory blocks are unaffected by the memory sub-budget"
)
def test_memory_blocks_within_sub_budget_admitted(tmp_path):
from rune.context_broker import ContributionBlock, ContextBroker
broker = ContextBroker(
budget_resolver=lambda window: 10_000,
estimator=lambda text: len(text) // 4,
)
broker.register_contributor(
"memory",
lambda task, session: ContributionBlock("memory", 70, "m" * 400, 0, "test"),
2,
)
task = mock.Mock(description="kubernetes pods restart")
task.task_id = "t1"
_capsule, trace = broker.assemble(task, {}, budget_tokens=10_000)
memory_records = [b for b in trace["blocks"] if b["name"] == "memory"]
assert memory_records[0]["admitted"] is True
assert trace["memory_tokens"] > 0
assert trace["memory_budget"] == 1200
def test_lowest_priority_memory_block_evicted_first(tmp_path):
from rune.context_broker import ContributionBlock, ContextBroker
broker = ContextBroker(
budget_resolver=lambda window: 10_000,
estimator=lambda text: len(text) // 4,
)
broker.register_contributor(
"memory",
lambda task, session: ContributionBlock("memory", 70, "a" * 4800, 0, "test"),
2,
)
broker.register_contributor(
"persona_memories",
lambda task, session: ContributionBlock("persona_memories", 68, "b" * 4800, 0, "test"),
2,
)
task = mock.Mock(description="kubernetes pods restart")
task.task_id = "t1"
_capsule, trace = broker.assemble(task, {}, budget_tokens=10_000)
by_name = {b["name"]: b for b in trace["blocks"]}
assert by_name["memory"]["admitted"] is True, "higher-priority memory fits the sub-budget"
assert by_name["persona_memories"]["admitted"] is False, "lowest-priority memory evicted first"
def test_trace_v5_memory_fields_additive_defaults():
"""P1-03 additive fields (schema v5 — v4 was taken by P1-02 capsule
fields): defaults keep v1-v4 readers and rows fully compatible."""
from rune import inference_trace as it
assert it.INFERENCE_TRACE_SCHEMA_VERSION == 5
trace = it.InferenceTrace(
schema_version=it.INFERENCE_TRACE_SCHEMA_VERSION,
provider="ollama",
model="m",
task_id="t",
channel="c",
resolved_context_window=0,
input_budget=0,
model_calls=0,
prompt_tokens_estimated=0,
prompt_tokens_served=0,
output_tokens=0,
latency_ms=0.0,
model_time_ms=0.0,
per_block_tokens={},
dropped_blocks=[],
tools_exposed=[],
memories_exposed=[],
memory_tokens=0,
degraded=[],
cache=None,
cost_usd=None,
cost_basis="local-unpriced",
success=True,
error="",
)
assert trace.memory_candidates == 0
assert trace.memory_selected == 0
assert trace.memory_abstained is False
assert trace.memory_types_queried == []
def test_operator_trace_record_carries_memory_selection_fields(tmp_path, monkeypatch):
"""A scripted operator run persists the v5 memory-selection fields."""
monkeypatch.setenv("RUNE_HOME", str(tmp_path / "home-m"))
(tmp_path / "home-m" / "state").mkdir(parents=True, exist_ok=True)
from rune import inference_trace as it
storage = tmp_path / "operator-m.json"
op = ro.RuneOperator(str(storage))
trace = {
"model_id": "m",
"window": 40960,
"budget": 32768,
"blocks": [
{"name": "persona", "tokens": 10, "admitted": True, "reason": ""},
{"name": "user", "tokens": 5, "admitted": True, "reason": ""},
],
"admitted_total": 15,
"dropped": [],
"memory_tokens": 0,
"degraded": [],
"compaction": [],
"elapsed_ms": 1.0,
}
capsule = mock.Mock(
token_count=15,
active_objective="",
blocks=[],
to_messages=lambda: [{"role": "user", "content": "do it"}],
)
broker = mock.Mock(assemble=lambda task, session, model_id, **kwargs: (capsule, trace))
response = _mutating_response()
class _RT:
transport = mock.Mock(provider="ollama")
tool_names = frozenset()
def run(self, messages, **kwargs):
return response
with (
mock.patch.object(op, "_context_broker", return_value=broker),
mock.patch.object(ro.model_profiles, "get_or_create_profile", return_value=mock.Mock(safety_tier=0)),
mock.patch.object(ro.model_profiles, "record_interaction"),
mock.patch.object(ro, "LocalToolRuntime", return_value=_RT()),
mock.patch.object(ro, "OllamaChatTransport", return_value=mock.Mock(provider="ollama")),
mock.patch("rune.local_tool_runtime.context_length", lambda model_: 40960),
mock.patch.object(
ro.safety_override.SafetyOverride,
"get_params",
lambda self, text: {"tier": 0, "temperature": 0.7, "prefix": "", "suffix": ""},
),
mock.patch.object(ro.safety_override.SafetyOverride, "is_refusal", lambda self, text: False),
mock.patch.object(op, "_log_token_usage"),
mock.patch("rune.event_bus._store_path", lambda: tmp_path / "journal-m-events.jsonl"),
):
envelope = op.send_task("fix this code path")
assert envelope.get("success") is True
records = it.read_traces(trace_dir=tmp_path / "home-m" / "state")
assert records, "durable trace missing"
record = records[-1]
assert record["schema_version"] == 5
assert record["memory_candidates"] == 0
assert record["memory_selected"] == 0
assert record["memory_abstained"] is True, "no memory ran in this scripted broker -> abstained"
assert record["memory_types_queried"] == []
def test_memory_selection_doc_exists():
doc = ROOT / "docs" / "memory-selection.md"
assert doc.is_file()
text = doc.read_text()
assert "MemorySelector" in text
assert "select_for_task" in text
assert "RECALL_MIN_SCORE" in text
assert "abstain" in text.lower()
assert "memory budget" in text.lower()
def test_canary_p1_03_registered_in_ci():
canary = ROOT / "src" / "rune" / "canary_p1_03.py"
assert canary.is_file(), "canary must exist"
ci = ROOT / ".gitea" / "workflows" / "ci.yml"
assert "canary_p1_03.py" in ci.read_text(), "canary must be registered in the CI canary loop"
# ---------------------------------------------------------------------------
# Discharge (post-gate findings, #26) — red-first tests for the two-gate
# review findings. Findings 1-4 here; 5-9 strengthen existing tests/canary.
# ---------------------------------------------------------------------------
def _unit_vec(cos_w: float) -> list[float]:
"""Unit 256-dim vector at cosine `cos_w` from [1, 0, ...]."""
return [cos_w, math.sqrt(max(0.0, 1.0 - cos_w * cos_w))] + [0.0] * 254
def _fake_embed(vectors: dict[str, list[float]]):
"""Deterministic embedder: maps 'search_query: X'/'search_document: X'
back to the bare text and looks it up in `vectors`."""
def fake_embed(texts):
out = {}
for t in texts:
bare = t
for prefix in ("search_query: ", "search_document: "):
if t.startswith(prefix):
bare = t[len(prefix) :]
break
out[t] = vectors.get(bare)
return out
return fake_embed
def _add_row(
db,
text,
kind="fact",
memory_type=None,
importance=0.5,
temperature=None,
confidence=None,
embedding=None,
):
"""Full-control row seeder for the discharge tests (extends _add with
metadata + an optional dense vector)."""
from rune.memory_store import now_iso
cols = "text, importance, created_at, last_accessed, topic, entities, source, method, status, kind, memory_type"
params: list = [text, importance, now_iso(), now_iso(), "", "[]", "test", "curator", "active", kind, memory_type]
if temperature is not None:
cols += ", temperature"
params.append(temperature)
if confidence is not None:
cols += ", confidence"
params.append(confidence)
cur = db.execute(f"INSERT INTO entries ({cols}) VALUES ({','.join('?' * len(params))})", params)
eid = cur.lastrowid
db.execute("INSERT INTO entries_fts (rowid, text) VALUES (?,?)", (eid, text))
if embedding is not None:
db.execute("INSERT INTO entries_vec (rowid, embedding) VALUES (?,?)", (eid, json.dumps(embedding)))
db.commit()
return eid
# --- Finding 1: THE floor applies in EVERY recall mode ---------------------
def test_recall_lexical_only_applies_min_score_floor(monkeypatch):
"""Discharge #1: the lexical-only branch never consulted min_score — a
below-floor store row injected. The lexical relevance band is ~4.1-4.9
(the +5 offset scale), so an elevated floor (5.5) above the band proves
the branch enforces the floor contract for ANY min_score: seeded rows
whose best relevance (4.92) is below the floor must abstain."""
_no_embed(monkeypatch)
db = ms.connect()
try:
_add(db, "Kubernetes pods restart automatically on failure")
_add(db, "Kubernetes pods restart policy for the cluster")
_add(db, "Kubernetes pods restart behavior in the runbook")
results = ms.recall(db, "kubernetes pods restart", budget=8, min_score=5.5)
assert results == [], "lexical-only recall must apply min_score (below-floor rows abstain)"
finally:
db.close()
def test_selector_lexical_store_rows_below_floor_abstain(monkeypatch):
"""Discharge #1 at the selector: store rows below the caller's floor must
not inject through the lexical-only path (the store_scored exemption is
only sound when the store floored them — in EVERY mode)."""
_no_embed(monkeypatch)
db = ms.connect()
try:
_add(db, "Kubernetes pods restart automatically on failure")
_add(db, "Kubernetes pods restart policy for the cluster")
finally:
db.close()
from rune.memory_selector import MemorySelector
sel = MemorySelector(db_path=ms.DB_PATH, min_score=5.5)
result = sel.select_for_task("kubernetes pods restart")
assert result.blocks == [], "below-floor store rows must not inject through lexical-only recall"
assert result.abstained is True
def test_recall_hybrid_below_floor_row_abstains(monkeypatch):
"""Discharge #1: the hybrid branch (dense AND lexical both fired) never
consulted min_score either. A row that matches conjunctively AND sits in
the dense list at cos~0.37 (< the 0.42 floor) must NOT inject just
because BM25 matched — the numeric gate is ADDITIVE to the conjunctive
FTS gate, which stays as-is."""
vectors = {"kubernetes fiscal audit committee": _unit_vec(1.0)}
monkeypatch.setattr(ms, "_embed", _fake_embed(vectors))
db = ms.connect()
try:
# filler rows make the shared term distinctive (df/total < 0.05) so
# the weak-cosine row passes the dense meta-judgement into `dense`.
for i in range(20):
_add(db, f"filler alpha bravo charlie delta echo foxtrot golf hotel {i}")
_add_row(
db,
"kubernetes fiscal audit committee quarterly review",
embedding=_unit_vec(0.2),
)
results = ms.recall(db, "kubernetes fiscal audit committee", budget=8, min_score=0.42)
assert results == [], "hybrid recall must apply min_score (below-floor row abstains)"
finally:
db.close()
def test_recall_hybrid_above_floor_row_selected(monkeypatch):
"""Discharge #1 positive control: a hybrid row ABOVE the floor still
surfaces — the added numeric gate must not kill genuine matches."""
vectors = {"kubernetes fiscal audit committee": _unit_vec(1.0)}
monkeypatch.setattr(ms, "_embed", _fake_embed(vectors))
db = ms.connect()
try:
for i in range(20):
_add(db, f"filler alpha bravo charlie delta echo foxtrot golf hotel {i}")
_add_row(
db,
"kubernetes fiscal audit committee quarterly review",
embedding=_unit_vec(0.95),
)
results = ms.recall(db, "kubernetes fiscal audit committee", budget=8, min_score=0.42)
assert results, "above-floor hybrid row must surface"
assert any("kubernetes fiscal audit" in r["text"] for r in results)
finally:
db.close()
def test_recall_dense_only_below_floor_distractor_abstains(monkeypatch):
"""Regression guard for the existing dense-only gate: a vector-close but
content-unrelated row (cos~0.37 mapped, below the 0.42 floor, no shared
content word) must abstain — the calibrated floor is what rejects it."""
query = "summarize the quarterly revenue report"
vectors = {query: _unit_vec(1.0)}
monkeypatch.setattr(ms, "_embed", _fake_embed(vectors))
db = ms.connect()
try:
_add_row(
db,
"Reptiles bask on sunlit rocks to regulate their body temperature",
embedding=_unit_vec(0.2),
)
assert ms.recall(db, query, budget=8, min_score=0.42) == []
finally:
db.close()
def test_recall_dense_only_above_floor_paraphrase_selected(monkeypatch):
"""Regression guard twin: a genuine paraphrase above the floor surfaces
through dense-only recall (the floor must not over-abstain)."""
query = "summarize the quarterly revenue report"
vectors = {query: _unit_vec(1.0)}
monkeypatch.setattr(ms, "_embed", _fake_embed(vectors))
db = ms.connect()
try:
_add_row(
db,
"please give an overview of the money the business made this period",
embedding=_unit_vec(0.95),
)
results = ms.recall(db, query, budget=8, min_score=0.42)
assert results, "above-floor paraphrase must surface"
assert any("overview of the money" in r["text"] for r in results)
finally:
db.close()
# --- Finding 2: typed persona lane alive in production; write-time types ---
def test_contributor_memory_runs_typed_persona_query(tmp_path, monkeypatch):
"""Discharge #2a: the typed persona query (memory_types=['self',
'personality']) executes in the LIVE contributor path — the operator's
untyped select_for_task call used to leave the persona source dead."""
_no_embed(monkeypatch)
op = _operator(tmp_path)
broker = op._context_broker()
seen: list = []
original = ms.recall
def spy(db, query, **kwargs):
if kwargs.get("memory_types"):
seen.append(list(kwargs["memory_types"]))
return original(db, query, **kwargs)
monkeypatch.setattr(ms, "recall", spy)
task = mock.Mock(description="kubernetes pods restart")
task.task_id = "t1"
op._contributor_memory(task, {})
assert ["self", "personality"] in seen, "the typed persona query must execute in the live contributor path"
def test_persona_lane_merges_without_duplicate_candidates(monkeypatch):
"""Discharge #2a: the store source's second typed query merges into the
candidates — rows that BOTH queries return (unclassified rows match
untyped AND typed) must appear ONCE, not double-count (duplicates would
corrupt the irrelevant-memory rate and can produce repeated block text)."""
_no_embed(monkeypatch)
db = ms.connect()
try:
_add(db, "Kubernetes pods restart automatically on failure")
_add(db, "Kubernetes pods restart policy for the cluster")
finally:
db.close()
from rune.memory_selector import MemorySelector
sel = MemorySelector(db_path=ms.DB_PATH)
sel.add_source("neurons", lambda query, types, budget, min_score: [])
sel.add_source("graphs", lambda query, types, budget, min_score: [])
sel.add_source("abstraction", lambda query, types, budget, min_score: [])
sel.add_source("consolidated", lambda query, types, budget, min_score: [])
sel.add_source("persona", lambda query, types, budget, min_score: [])
result = sel.select_for_task("kubernetes pods restart")
texts = [b.content for b in result.blocks]
assert result.candidates_evaluated == 2, "two shared rows must be merged once each"
assert len(texts) == len(set(texts)), "merged candidates must not duplicate block text"
def test_persona_lane_still_abstains_on_trivial_task(monkeypatch):
"""Discharge #2a: the lane is thresholded like every source — a trivial
task through the UNTYPED production caller still gets zero memory."""
_no_embed(monkeypatch)
db = ms.connect()
try:
_add(db, "I speak in one clean sentence, evidence first", memory_type="personality", importance=0.95)
finally:
db.close()
from rune.memory_selector import MemorySelector
sel = MemorySelector(db_path=ms.DB_PATH)
result = sel.select_for_task("what time is it")
assert result.blocks == []
assert result.abstained is True
def test_add_entry_memory_type_round_trip(monkeypatch):
"""Discharge #2b: add_entry classifies at write time (additive optional
param, default None = unclassified/eligible everywhere)."""
_no_embed(monkeypatch)
db = ms.connect()
try:
assert ms.add_entry(db, "I speak in one clean sentence, evidence first", memory_type="personality")
assert ms.add_entry(db, "Kubernetes pods restart automatically on failure")
rows = {r["text"]: r["memory_type"] for r in db.execute("SELECT text, memory_type FROM entries")}
assert rows["I speak in one clean sentence, evidence first"] == "personality"
assert rows["Kubernetes pods restart automatically on failure"] is None, (
"default must stay NULL (unclassified = eligible for every query)"
)
finally:
db.close()
# --- Finding 3: sources honor the selector's pinned db_path ----------------
def test_persona_source_uses_pinned_db_path(tmp_path, monkeypatch):
"""Discharge #3: the persona source must query the selector's PINNED
store — not memory_store.connect()'s module default."""
_no_embed(monkeypatch)
pinned = str(tmp_path / "pinned.db")
pdb = ms.connect(pinned)
try:
_add(pdb, "I speak in one clean sentence, evidence first", memory_type="personality")
finally:
pdb.close()
from rune.memory_selector import MemorySelector
sel = MemorySelector(db_path=pinned)
sel.add_source("store", lambda query, types, budget, min_score: []) # isolate the persona source
result = sel.select_for_task("how do I speak in one clean sentence", types=["self", "personality"])
assert any("one clean sentence" in b.content for b in result.blocks), (
"persona source must read the PINNED db_path, not the module default"
)
def test_store_source_uses_pinned_db_path(tmp_path, monkeypatch):
"""Discharge #3 twin: the store source must honor the pinned db_path too
(same unbound-default hole)."""
_no_embed(monkeypatch)
pinned = str(tmp_path / "pinned-store.db")
pdb = ms.connect(pinned)
try:
_add(pdb, "Kubernetes pods restart automatically on failure")
_add(pdb, "Kubernetes pods restart policy for the cluster")
finally:
pdb.close()
from rune.memory_selector import MemorySelector
sel = MemorySelector(db_path=pinned)
sel.add_source("persona", lambda query, types, budget, min_score: []) # isolate the store source
result = sel.select_for_task("kubernetes pods restart")
assert any("Kubernetes" in b.content for b in result.blocks), (
"store source must read the PINNED db_path, not the module default"
)
# --- Finding 4: neuron backfill runs at MIGRATION time only ----------------
def test_backfill_runs_once_at_migration_not_every_connect(tmp_path):
"""Discharge #4: the per-connect neuron-backfill scan is gone. The
migration (ALTER + backfill) runs only when the column is actually
missing; a fresh connect on an already-migrated store must NOT re-run
the UPDATE (proven with a NULL marker row). Explicit ensure() calls
keep the frozen self-healing semantics (they re-classify unclassified
neurons, never touching explicit classifications)."""
db = ms.connect() # fresh store: migration ran here (empty table)
try:
_add(db, "Kubernetes pods restart automatically on failure", kind="neuron")
# Plant a NULL marker AFTER migration: a per-connect scan would flip
# it back to 'associative'.
db.execute("UPDATE entries SET memory_type=NULL WHERE kind='neuron'")
db.commit()
finally:
db.close()
# A fresh connect on the SAME store: no re-run (per-connect scan gone).
db2 = ms.connect()
try:
row = db2.execute("SELECT memory_type FROM entries WHERE kind='neuron'").fetchone()
assert row["memory_type"] is None, "second connect must not re-run the backfill UPDATE"
# Explicit ensure() keeps the frozen self-healing semantics...
assert ms.ensure_memory_type_column(db2) is False, "no second ALTER (idempotent)"
row = db2.execute("SELECT memory_type FROM entries WHERE kind='neuron'").fetchone()
assert row["memory_type"] == "associative", "explicit ensure() self-heals unclassified neurons"
# ...and never touches explicit classifications.
db2.execute("UPDATE entries SET memory_type='personality' WHERE kind='neuron'")
db2.commit()
ms.ensure_memory_type_column(db2)
row = db2.execute("SELECT memory_type FROM entries WHERE kind='neuron'").fetchone()
assert row["memory_type"] == "personality", "explicit classifications are never overwritten"
finally:
db2.close()
# ---------------------------------------------------------------------------
# Dichotomy wave: memory_selector FULL Rust core — fallback pin discipline
# ---------------------------------------------------------------------------
def test_mse_core_python_pin_honored(monkeypatch, _isolated_memory_env):
"""RUNE_MSE_CORE=python pins the fallback: the probe returns None and the
facade exercises the PYTHON oracle path (degrade-not-crash preserved)."""
from rune import mse_loader
from rune.memory_selector import MemorySelector, SelectionResult, _mse_core
monkeypatch.setenv("RUNE_MSE_CORE", "python")
assert mse_loader.core() is None, "the pin must be honored in the loader probe"
assert _mse_core() is None, "the facade must see the pinned-off core"
sel = MemorySelector(db_path=ms.DB_PATH)
result = sel.select_for_task("kubernetes pods restart")
assert isinstance(result, SelectionResult), "pinned fallback still selects"
def test_mse_core_delegates_when_unpinned(monkeypatch, _isolated_memory_env):
"""Without the pin, the facade delegates the decision math to the Rust
core — and the end-to-end outcome stays identical to the oracle's."""
from rune import mse_loader
from rune.memory_selector import MemorySelector, _mse_core
if not mse_loader.available():
pytest.skip("memory_selector cdylib not built in this environment")
monkeypatch.delenv("RUNE_MSE_CORE", raising=False)
_no_embed(monkeypatch)
assert _mse_core() is not None, "unpinned core must load"
db = ms.connect()
try:
_add(db, "Kubernetes pods restart automatically on failure")
finally:
db.close()
sel = MemorySelector(db_path=ms.DB_PATH)
result = sel.select_for_task("kubernetes pods restart")
assert result.abstained is False
assert result.candidates_evaluated > 0