Evaluation harness (§56)¶
Because state is structured, evaluation is multi-level — not just
answer == expected:
Evidence quality · Claim verification · Confidence calibration · Provenance grounding · Calculation correctness · Answer coverage · Source coverage
reactifact.eval is the deterministic, LLM-free harness that scores a run's final
state. Each metric is a pure function over the resulting Context (+
optional ground truth), so truthfulness is measured where it lives — the
artifact graph — not the smoothness of the text.
Running a suite¶
from reactifact.eval import EvalCase, calculation_correctness, core_metrics, run_suite
cases = [
EvalCase(
name="calc-question",
run=_run_knowledge_calc, # executes the pipeline → Context
expected={"sources": ["costs:", "pricing:", "guide:"]},
),
]
report = run_suite(cases, metrics={
**core_metrics, # answer/provenance/evidence/claim
"calc": calculation_correctness(values=(5480, 3580)),
"sources": source_coverage(),
})
print(report.render())
eval · multi-level report (§56)
[calc-question] overall 1.000
answer_present 1.000
provenance_grounded 1.000
evidence_quality 1.000
claim_verification 1.000
calc 1.000
sources 1.000
suite overall: 1.000
Metrics¶
Artifact classes are matched by name (Answer, Evidence, …), so the
harness needs no domain imports — the domain stays out of the framework.
| Metric | What it answers | Built-in |
|---|---|---|
answer_present |
did the run produce an answer at all? | plain fn |
provenance_grounded |
is every answer backed by an existing supported_by (§34)? |
plain fn |
evidence_quality(threshold=0.5) |
share of evidence scoring at/above the bar | plain fn |
claim_verification(valid=("verified",)) |
share of claims that passed verification (§35) | plain fn |
confidence_calibration() |
Brier score of Claim.confidence against actual correctness (§56) |
factory (needs expected.claim_correctness) |
answer_coverage() |
coverage of the expected answer text by the answer | factory (needs expected.answer) |
calculation_correctness(values=…) |
share of calculations matching ground truth (§67) | factory |
source_coverage() |
share of the answer's sources matched by markers | factory (needs expected.sources) |
core_metrics bundles the four non-generative ones. A metric that lacks ground
truth returns None and is reported as skipped (EvalResult.skipped), never
as a silent zero.
Types¶
Metric— one measured 0..1 score with a reportingweight.EvalCase— name + arun() -> Context+ optionalexpectedground truth.EvalResult(per case) /EvalReport(suite) —overall()(weighted mean),to_dict(),render().
Where to look¶
The end-to-end tests in tests/test_eval.py evaluate the knowledge
calculation question offline (no LLM) and assert a fully grounded, computed
report — the same shape you can point at any example pipeline.