You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
feat(model): per-head calibrated thresholds, with a precision floor (#261)
Every head decided it fired at a flat 0.5. That is a coin-flip line, not a quality bar, and it
was silently withholding real matches from the thin heads: with 13 positives against 2400
negatives a forest hedges even with balanced class weights, so a genuine pine match could land
at 0.42 and never be shown. Each head now carries its own cut-off, fitted on OUT-OF-FOLD
probabilities at training time and stored in its manifest.
The first attempt maximised F1 and was wrong in an instructive way. On a badly imbalanced head
F1 peaks in a low-precision regime, because recall climbs faster than precision falls: blackberry
tuned itself to 0.18, where 96% of its calls were false, and sweet fired on 1317 of 8855
molecules at 18% precision. A high AUROC gives no protection here — AUROC is computed on ranking
and is insensitive to class imbalance, precision is not. coffee has AUROC 0.960 and out-of-fold
precision 0.46; both are true of the same head.
So the threshold must now clear a 50% precision floor: a call labelled confident has to be right
more often than not. Thresholds moved hard in BOTH directions — pine UP to 0.75 where it is
100% precise, rosemary down to 0.16 — and no head sits at either bound, so the data is choosing
rather than the clamp.
73 of 167 aroma heads cannot reach the floor at any threshold. They are marked INDICATIVE, not
deleted: they keep their score, their place in the 178-dim profile, their chips, their map colour
and their molecules, because firing well above base rate is real evidence. What changes is that
they are never dressed up as a confident call — the read returns `indicative` plus the head's
measured precision, and the UI hatches their bar. Hiding them would have deleted reach from 73
notes to paper over a labelling problem. All five mouthfeel heads clear the floor (0.57-1.00).
Applied everywhere a threshold was hard-coded, not just the live read: the precomputed profile
index, the flavor map and the export card each had their own 0.5, and leaving those would have
made a molecule's chips disagree with its own modal. The UI's likely/possible/weak levels are
now read against each head's own threshold too, for the same reason.
audit_generalization.py scores at the calibrated thresholds and grew a fourth verdict:
PRECISION-LIMITED, for a head that is strict on purpose. Calling pine "under-confident" at 0.75
would be exactly backwards — loosening it trades away the accuracy it was tuned for.
Signed-off-by: Austin L. <86896075+rvnminers-A-and-N@users.noreply.github.com>
0 commit comments