Running an evaluation

Benchmark first

Begin with BEIR SciFact: it is small enough for a development loop and jointly tests ranking against scientific evidence judgments. Add ArguAna for opposition retrieval, then one large and one out-of-domain BEIR task before treating a retrieval change as general.

Score a ranked run

Create JSONL with one query per line. IDs must be the corpus IDs, not array positions.

{"query_id":"q1","ranked_ids":["d2","d1"],"relevance":{"d1":2,"d2":1}}
{"query_id":"q2","ranked_ids":["d8","d4"],"relevance":{"d4":1}}
$ python benchmarks/evaluate_retrieval.py results/scifact.jsonl --k 10
{
  "k": 10,
  "mrr": 0.75,
  "ndcg": 0.7138,
  "precision": 0.15,
  "queries": 2,
  "recall": 1.0
}

Compare the right layer

For an index change, freeze parsed passages and compare candidate recall, final ranking, latency, and bytes. For a parser change, score structure first and then rebuild the same index. For a memory policy change, freeze the answer model and context budget. For an evidence-policy change, keep retrieval results fixed. This isolates the component responsible for a movement.

Regression gate

A gate contains a minimum quality threshold and maximum resource budget. It also contains invariants: no unauthorized ID may enter candidates, evidence IDs must resolve to the pinned source revision, deleted records must disappear after replay, and repeated execution with a deterministic component must produce the same report.