Read-path mechanics of memory_store.py ported to memory-store-deep: - FtsQueryConjunctive: extended-Boolean AND (len>3 non-stop terms, len>2 fallback, quoted, first 8, space-joined) — msStopwords extracted verbatim from the live module - ChunkText: paragraph recombination + 1.5x hard-split - RankFusion: RRF k=15, three modes (hybrid/dense-only/lexical-only with min-max bm25 normalize), insertion-ordered ranks, NUMERIC ids out (Python int ids; the string map is internal) - ProjectChunkRows: -rrf sorted, text[:400], rrf round 4, budget cap - MapReduce: top-3 per chunk + the REDUCE pass (all mapped re-sorted by score) — the oracle caught my chunk-order-only first read - FuseResults: NormKey (lowercase whitespace-collapse) dedup, exact field shape, kind-wise min-max scale-alignment (the audit fix), final sort PARITY: truth_recall.json — 17 cases from the _py_* oracles; fixtures SHIP in the inputs. Embed surfaces stay Python-side (model-coupled).
121 lines
5.7 KiB
Python
121 lines
5.7 KiB
Python
#!/usr/bin/env python3
|
|
"""gen_memory_store_truth2.py — memory-store batch 2 truth battery
|
|
(contract BUILDER-2026-10-07T18:05:47Z-152c16).
|
|
|
|
The LIVE _py_* oracles of memory_store.py. Cases: FTS conjunctive builder
|
|
(stopword filtering, fallback, 8-cap), chunk_text (recombine + hard-split),
|
|
rank fusion (hybrid/dense-only/lexical-only), project_chunk_rows,
|
|
map_reduce, fuse_results (dedup + scale-alignment).
|
|
|
|
Usage: python3 scripts/gen_memory_store_truth2.py (from repo root)
|
|
"""
|
|
|
|
import json
|
|
import sys
|
|
from pathlib import Path
|
|
|
|
REPO = Path(__file__).resolve().parent.parent
|
|
sys.path.insert(0, str(REPO / "src"))
|
|
sys.path.insert(0, str(REPO / "src" / "rune"))
|
|
|
|
import memory_store as ms # noqa: E402
|
|
|
|
|
|
def main():
|
|
cases = []
|
|
|
|
def add(fn, name, inp, expected):
|
|
cases.append({"fn": fn, "name": name, "input": inp, "expected": expected})
|
|
|
|
# ── FTS conjunctive ───────────────────────────────────────────────────
|
|
add("fts", "significant_terms",
|
|
{"query": "the curator gates memory writes"},
|
|
{"q": ms._py_fts_query_conjunctive("the curator gates memory writes")})
|
|
add("fts", "stopwords_dropped",
|
|
{"query": "the and was with nick"},
|
|
{"q": ms._py_fts_query_conjunctive("the and was with nick")})
|
|
add("fts", "short_fallback",
|
|
{"query": "go is fun ai"},
|
|
{"q": ms._py_fts_query_conjunctive("go is fun ai")})
|
|
long_q = "alpha beta gamma delta epsilon zeta eta theta iota kappa"
|
|
add("fts", "cap_eight",
|
|
{"query": long_q},
|
|
{"q": ms._py_fts_query_conjunctive(long_q)})
|
|
add("fts", "empty_returns_raw",
|
|
{"query": "a an of"},
|
|
{"q": ms._py_fts_query_conjunctive("a an of")})
|
|
|
|
# ── chunk_text ────────────────────────────────────────────────────────
|
|
small = "one paragraph only"
|
|
add("chunk", "under_size", {"text": small, "size": 1500, "overlap": 150},
|
|
{"chunks": ms._py_chunk_text(small, 1500, 150)})
|
|
para = "\n\n".join(f"paragraph {i} " + "x" * 40 for i in range(30))
|
|
add("chunk", "recombine", {"text": para, "size": 400, "overlap": 150},
|
|
{"chunks": ms._py_chunk_text(para, 400, 150)})
|
|
noline = "y" * 3000
|
|
add("chunk", "hard_split", {"text": noline, "size": 1000, "overlap": 150},
|
|
{"chunks": ms._py_chunk_text(noline, 1000, 150)})
|
|
add("chunk", "empty", {"text": "", "size": 1500, "overlap": 150},
|
|
{"chunks": ms._py_chunk_text("", 1500, 150)})
|
|
|
|
# ── rank fusion ───────────────────────────────────────────────────────
|
|
dense = [[1, 0.9], [2, 0.8], [3, 0.7]]
|
|
bm25 = [[2, 12.0], [4, 8.0], [1, 3.0]]
|
|
add("fuse_ranks", "hybrid", {"dense": dense, "bm25": bm25},
|
|
ms._py_rank_fusion(dense, bm25))
|
|
add("fuse_ranks", "dense_only", {"dense": dense, "bm25": []},
|
|
ms._py_rank_fusion(dense, []))
|
|
add("fuse_ranks", "lexical_only", {"dense": [], "bm25": bm25},
|
|
ms._py_rank_fusion([], bm25))
|
|
add("fuse_ranks", "neither", {"dense": [], "bm25": []},
|
|
ms._py_rank_fusion([], []))
|
|
|
|
# ── project_chunk_rows ────────────────────────────────────────────────
|
|
rows = [
|
|
{"rowid": 1, "chunk_id": "c1", "text": "t" * 500, "wing": "w1", "room": "r1",
|
|
"source_path": "a.md", "page": 3},
|
|
{"rowid": 2, "chunk_id": "c2", "text": "short", "wing": "w1", "room": "r1",
|
|
"source_path": "b.md"},
|
|
]
|
|
ranks = {"2": 0.0625, "1": 0.05}
|
|
add("project", "budget_and_shape", {"ranks": ranks},
|
|
{"rows": ms._py_project_chunk_rows(ranks, rows, 6)})
|
|
|
|
# ── map_reduce ────────────────────────────────────────────────────────
|
|
entries = [{"id": i, "relevance": i * 0.1} for i in range(25)]
|
|
add("map_reduce", "top3_per_chunk", {"entries": entries, "chunk_size": 10},
|
|
{"mapped": ms._py_map_reduce(entries, 10)})
|
|
add("map_reduce", "under_threshold", {"entries": entries[:5], "chunk_size": 10},
|
|
{"mapped": ms._py_map_reduce(entries[:5], 10)})
|
|
|
|
# ── fuse_results ──────────────────────────────────────────────────────
|
|
ents = [
|
|
{"id": 1, "text": "nick prefers coffee", "topic": "human",
|
|
"relevance": 2.5, "confidence": 0.9},
|
|
{"id": 2, "text": "NICK PREFERS COFFEE", "topic": "human",
|
|
"relevance": 1.1, "confidence": 0.8}, # dedup hit
|
|
{"id": 3, "text": "rune gates memory writes", "topic": "project",
|
|
"relevance": 5.6, "confidence": 0.95},
|
|
]
|
|
res = [
|
|
{"chunk_id": "c1", "text": "the spine rebuild parity", "wing": "research",
|
|
"rrf": 0.0625, "confidence": 0.7},
|
|
{"chunk_id": "c2", "text": "curator provenance recovery", "wing": "research",
|
|
"rrf": 0.05},
|
|
]
|
|
add("fuse_results", "dedup_scale_align", {"entries": ents, "research": res},
|
|
{"merged": ms._py_fuse_results(ents, res)})
|
|
|
|
out = {
|
|
"oracle": "src/rune/memory_store.py _py_* oracles",
|
|
"generated": "2026-10-07",
|
|
"cases": cases,
|
|
}
|
|
target = REPO / "src/go/memory-store-deep" / "truth_recall.json"
|
|
target.write_text(json.dumps(out, indent=1, ensure_ascii=False) + "\n")
|
|
print(f"wrote {target} ({len(cases)} cases)")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|