metrale_telemetry/spec_confidence.rs
1// SPDX-License-Identifier: MIT OR Apache-2.0
2
3//! 2026-10-04: Draft outcomes by drafter confidence: for each draft a verify step reached
4//! (every draft before it was accepted), its top-1 log-probability bucket and whether it was
5//! accepted. `met bench spec-cost` fits the acceptance calibration of `--spec-cost-model
6//! measured` from these counts, so P(accept | bucket) is conditional on reaching the draft,
7//! which is how the planner chains it.
8//!
9//! Owner: telemetry.
10//! Invariants: a non-finite log-probability is counted in `overflow`, never in a bucket; a
11//! positive one (rounding above 0) lands in the last bucket.
12
13use crate::instrument::Counter;
14
15/// 2026-10-04: Ascending upper edges of the buckets, in natural-log probability; a draft
16/// lands in the first bucket whose edge is >= its log-probability. Fine near 0, where most
17/// MTP drafts sit; the last edge is 0.
18pub const EDGES: [f32; 10] = [
19 -4.0, -2.0, -1.0, -0.5, -0.25, -0.1, -0.05, -0.02, -0.005, 0.0,
20];
21
22#[derive(Debug)]
23pub struct ConfidenceOutcomes {
24 /// 2026-10-04: `cells[b][accepted]`: reached drafts in bucket `b`.
25 cells: [[Counter; 2]; EDGES.len()],
26 pub overflow: Counter,
27}
28
29impl Default for ConfidenceOutcomes {
30 fn default() -> Self {
31 Self::new()
32 }
33}
34
35impl ConfidenceOutcomes {
36 pub const fn new() -> Self {
37 Self {
38 cells: [const { [const { Counter::new() }; 2] }; EDGES.len()],
39 overflow: Counter::new(),
40 }
41 }
42
43 /// 2026-10-04: The bucket of log-probability `lp`; `None` when it is not finite.
44 pub fn bucket(lp: f32) -> Option<usize> {
45 if !lp.is_finite() {
46 return None;
47 }
48 Some(
49 EDGES
50 .iter()
51 .position(|&e| lp <= e)
52 .unwrap_or(EDGES.len() - 1),
53 )
54 }
55
56 pub(crate) fn record(&self, lp: f32, accepted: bool) {
57 match Self::bucket(lp) {
58 Some(b) => self.cells[b][usize::from(accepted)].add(1),
59 None => self.overflow.add(1),
60 }
61 }
62
63 /// 2026-10-04: Reached drafts in bucket `b` with outcome `accepted`.
64 pub fn count(&self, b: usize, accepted: bool) -> u64 {
65 self.cells
66 .get(b)
67 .map_or(0, |c| c[usize::from(accepted)].get())
68 }
69
70 pub fn is_empty(&self) -> bool {
71 self.cells.iter().flatten().all(|c| c.get() == 0)
72 }
73}
74
75#[cfg(test)]
76#[path = "spec_confidence_tests.rs"]
77mod tests;