4. Min Threshold for Precision
Problem
Fin gates its final answer on a certainty/confidence score: if a generated response's certainty doesn't meet a required threshold, Fin asks a disambiguating clarification question instead of answering directly, rather than risking a wrong answer.
Given historical (certainty_score, was_correct) pairs from past answered queries, find the minimum certainty threshold such that, among all responses with certainty at or above that threshold, the fraction that were actually correct (precision) is at or above a target. The minimum threshold that still hits the bar answers the most queries directly (fewer needless clarification questions) while staying safe. Consider every distinct certainty score present as a candidate threshold, and aim for a sort-once, single-pass O(n log n) solution, not a brute-force O(n²).
Source: src/4_min_threshold_for_precision.py
def min_threshold_for_precision(scored_outcomes: list[tuple[float, bool]], target_precision: float) -> float | None:
...
Examples:
>>> min_threshold_for_precision([(0.9, True), (0.8, True), (0.7, False), (0.6, True)], 1.0)
0.8
>>> min_threshold_for_precision([(0.9, False), (0.8, True)], 1.0)
None
Step-by-Step Approach
- Reframe the question: "find the minimum threshold t such that filtering to score ≥ t and computing precision on the survivors hits target_precision" is a search over the discrete set of distinct certainty scores present in the data.
- Sort all outcomes descending by certainty score once — this lets you sweep from the highest threshold down to the lowest while incrementally accumulating counts, instead of recomputing precision from scratch for every candidate threshold (the O(n²) brute force).
- Walk the sorted list left to right, grouping consecutive entries that share the same score — a threshold t must include every entry with score == t together, so they need to be processed as one group, not one at a time.
- Maintain running
correctandtotalcounters as you extend the "at-or-above-t" window group by group; after finishing a group,correct / totalis exactly the precision at or above that group's score. - Because the smallest qualifying threshold is what's wanted, don't stop at the first threshold that satisfies the target — keep scanning and keep overwriting a "best so far" variable every time the running precision clears the target, so the last (smallest) qualifying threshold wins.
- Return
Noneif no threshold ever clears the bar, including for empty input.
The key insight: as t decreases, both correct and total in the "at-or-above-t" set only grow, but the ratio correct / total is not monotonic in t — it can rise or fall as the sweep proceeds. That rules out stopping early at the first success, but the sort-then-single-pass structure still gets the answer in O(n log n) instead of the O(n²) of recomputing precision fresh for every candidate threshold.
Reference solution
def min_threshold_for_precision(scored_outcomes: list[tuple[float, bool]], target_precision: float) -> float | None:
# sort once descending, single pass accumulating running correct/total, O(n log n) time, O(n) space
if not scored_outcomes:
return None
# descending via negated key
ordered = sorted(scored_outcomes, key=lambda pair: -pair[0])
best = None
correct = 0
total = 0
i = 0
n = len(ordered)
while i < n:
t = ordered[i][0]
# group all entries tied at this score together
while i < n and ordered[i][0] == t:
total += 1
if ordered[i][1]:
correct += 1
i += 1
if correct / total >= target_precision:
# overwrite so the last (smallest) qualifying threshold wins
best = t
return best
Key Functions & Tricks
sorted(scored_outcomes, key=lambda pair: -pair[0])— descending sort via negated key- Grouping equal-score entries with a nested
while— manual group-by over pre-sorted run ordered[i][0] == t— safe float equality since t is drawn from the same listcorrect / total— true division always yields a precise float ratiobest = Nonesentinel with overwrite-on-success — keeps the last (smallest) threshold that clears the bar
How to Recognize This Pattern
The signal: "find the min/max X such that some computed property is at or above a target," where the property is a running aggregate (like a ratio) over the elements included so far. This family of "find the threshold satisfying a feasibility condition" problems is often solved with binary search on the answer when the feasibility predicate is monotonic — true for every t below some crossover point, false above it (or vice versa). That's the classic pattern this category is named for. The twist in this problem is that precision-above-threshold is not guaranteed monotonic in t: a threshold that clears the bar can be sandwiched between two thresholds that don't, since adding one more low-certainty-but-correct answer to the window can push precision back up. A single binary search would risk landing on the wrong side of a non-monotonic bump and returning an incorrect answer. The safe, general-purpose technique when predicate monotonicity isn't guaranteed is exactly this sort-once, single-pass sweep with running aggregates — still O(n log n), and correct regardless of monotonicity. The pitfall to watch for: assuming "stricter threshold always means higher precision" and reaching for binary search on that assumption without first checking whether the predicate is actually monotonic on the specific data.