mixle.system.scorecard module¶
System-level scorecard for held-out question sets.
Named SystemScorecard (not Scorecard) to avoid colliding with
mixle.task.scorecard.Scorecard – a different, narrower comparison (one student solution vs its
teacher on a task); this one evaluates a whole System (teacher, captured cache,
degraded modes, budget, all of it) end to end.
- DEFAULT_SCORER_VERSION = 'substring/v2'
Bumped whenever
_default_scorer()’s judgement changes, so cards judged by different versions of the default judge get differentquestion_set_identity()values and cannot be compared.
- question_set_identity(question_set, *, scorer=None)[source]
The identity two scorecards must share before
detect_regression()may compare them.A regression comparison is only meaningful between cards measured on the SAME held-out set with the SAME judge: a “perfect” card over a different (or empty) question set, or the same set scored by a laxer scorer, is not evidence that a round did not regress. Digesting the
(query, expected)pairs in order plus the scorer’s identity turns that documented precondition into somethingdetect_regression()can actually check, instead of silently accepting mismatched evidence.The pairs are digested by CONTENT (
mixle.data.hashing.dataset_hash(), order-sensitive), never byrepr(MXR-080-1902).Query.fingerprintis typedAny, andreprof an ordinary object embeds its memory address, so two equal question sets built from equal fingerprint objects digested differently – anddetect_regression()then reported an improved round against the same held-out set ascomparable=False, regressed=True, a fabricated regression on the exact gate this identity exists to make trustworthy.dataset_hashencodes aQuerystructurally by its declared dataclass fields and refuses (rather than repr-ing) any value it cannot encode canonically, which is what makes an identity computed in one process match one computed in another.Note that this changes the digest of every question set relative to the
repr-based scheme, so an identity persisted by an older build will not match one computed here. That is unavoidable and correct: the old digest’s whole problem is that it did not identify what it claimed to.
- class SystemScorecard(quality, realized_cost, grounded_fraction, n, question_set_id='')[source]
Bases:
objectOne evaluation of a
Systemagainst a fixed held-out question set.Every metric is validated on construction: a card carrying NaN/out-of-range numbers or a negative case count is not a weaker measurement, it is not a measurement at all, and
detect_regression()silently treated such a card as “no regression” (fail-open on the exact gate meant to catch a worsening round).question_set_idbinds the card to the held-out set and judge it was measured with (seequestion_set_identity()).- Parameters:
- evaluate(system, question_set, *, scorer=None)[source]
Evaluate
systemover a fixed[(query, expected_answer), ...]set.Every
expectedis validated up front: a blank reference cannot discriminate, and a question set containing one is rejected rather than scored (it used to make every non-Nonereply correct and reportquality=1.0).quality– fraction of questionsscorerjudges correct. The default judge is_default_scorer(), a deliberately weak lexical baseline (case-insensitive substring match) that cannot see negation or paraphrase; read its docstring before treatingqualityas authoritative, and pass a task-specificscorerwhere correctness actually matters.grounded_fraction– fraction answered WITHOUT a degraded mode (teacher or captured, not a store-only fallback / refusal / failure): the fraction of answers you can actually trust came from a real answer path, not a fault-boundary guess.realized_cost– total spend units (total_units()) across the set.question_set_id– the identity of the held-out set and judge this card was measured with, sodetect_regression()can refuse to compare cards from different evidence.
There is deliberately NO
calibrationfield. One used to exist and was assignedqualityverbatim: a deterministic system that emits no confidence at all scored a perfect “calibration”, anddetect_regression()never compared the field anyway, so a drop from 1.0 to 0.0 was not a regression.answer()carries no per-answer confidence to calibrate against, so there is nothing here to compute; when it does, add a real calibration statistic to THIS function and a matching axis todetect_regression()in the same change, rather than re-adding a copied number that reads as evidence of something never measured.This is a genuinely read-only pass: every call goes through
answer()withread_only=True, so evaluating a held-outquestion_setcan never itself teachsystemthe held-out answers (no promotion into the harvest a laterimprove()could capture, no change tosystem.total_spend). Without that, a held-out set would stop being held-out the moment it was first evaluated: a laterimprove()could promote its answers into the captured cache, and re-evaluating the “held-out” set afterward would be trivially free and perfect. Never callsystem.answerwithoutread_only=Truefrom this function.
- class RegressionReport(regressed, reasons=<factory>, comparable=True)[source]
Bases:
objectWhether
currentis worse thanbaselineon any tracked axis, and exactly why.comparableis False when the two cards are not evidence about the same thing (different held-out set/judge, different case counts, an unidentified card). An incomparable pair is reported asregressed=True: a comparison that could not be made is not a passed comparison.
- detect_regression(baseline, current, *, tolerance=1e-9)[source]
Compare two scorecards from the SAME held-out set across improve-rounds.
Never silently accepts a round that answers worse, less groundedly, or for more cost than the round before it – each tracked axis that got worse (beyond
tolerance) is named inreasons.The “same held-out set” precondition is enforced, not merely documented: both cards must carry the same non-empty
question_set_identity()and the same case count. Comparing a card against evidence from a different (or empty) question set cannot show that a round did not regress, so such a pair comes backcomparable=False, regressed=Truerather than a clean bill of health.tolerancemust itself be finite and nonnegative – a NaN tolerance makes every ordered comparison below false, which silently turned this gate into an unconditional “no regression”.- Parameters:
baseline (SystemScorecard)
current (SystemScorecard)
tolerance (float)
- Return type:
RegressionReport