Move all three skills into skills/; add root README; fix paths
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
312742cfef
commit
d95e5d452d
84 files changed
+97
-31
No files matched your search
@@ -0,0 +1,50 @@
|
||||
"""Confidence bands: the single source of truth for the cut points.
|
||||
|
||||
Copy this file into the backend. Everything that needs a band (the review queue,
|
||||
an exported sheet, the approve gate) imports from here, so they never disagree
|
||||
about what counts as red.
|
||||
|
||||
GREEN >= 0.95 clean print, straight through
|
||||
AMBER 0.90-0.95 slightly unclear, check it
|
||||
RED < 0.90 handwriting or a messy scan
|
||||
BLANK a mandatory field with no value
|
||||
UNSCORED no word scores came back for the value
|
||||
|
||||
The approve gate: every field that isn't green must be verified by a person before the
|
||||
run can be approved (needs_review). Amber is not sampled; it is checked like red.
|
||||
|
||||
Calibration (from the prototype these rules came from): crisp print scored 0.90 and
|
||||
up, handwriting clustered in 0.80-0.89, and 0.70-0.79 was empty. 0.90 sits in that
|
||||
gap. 0.95 splits off the slightly unclear 0.90-0.95 reads from clean print.
|
||||
|
||||
What a band claims: the score is the model's own legibility rating. Green means the
|
||||
text was read cleanly, NOT that the value is correct; a confident misread scores
|
||||
green. Red is the useful direction: it reliably surfaces handwriting.
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import Iterable, Optional
|
||||
|
||||
GREEN_THRESHOLD = 0.95
|
||||
CONFIDENCE_THRESHOLD = 0.90
|
||||
BANDS = ("green", "amber", "red", "blank", "unscored")
|
||||
|
||||
|
||||
def band_of(score: float) -> str:
|
||||
if score >= GREEN_THRESHOLD:
|
||||
return "green"
|
||||
return "amber" if score >= CONFIDENCE_THRESHOLD else "red"
|
||||
|
||||
|
||||
def field_band(word_scores: Optional[Iterable[float]], value: Optional[str], mandatory: bool = False) -> str:
|
||||
"""A field's band. It takes its WORST word score, so one shaky word can't hide in
|
||||
a clean-looking field. A blank mandatory field is flagged whatever its score."""
|
||||
if mandatory and not (value or "").strip():
|
||||
return "blank"
|
||||
scores = list(word_scores or [])
|
||||
return band_of(min(scores)) if scores else "unscored"
|
||||
|
||||
|
||||
def needs_review(band: str) -> bool:
|
||||
"""Every band but green must be verified by a person before the run can be approved."""
|
||||
return band != "green"
|
||||
Reference in new issue
Block a user