metrale_bench/gate/
group.rs

1// SPDX-License-Identifier: MIT OR Apache-2.0
2
3//! 2026-09-26: Benchmark groups: one gate satisfied by a complete partition of shard runs.
4//!
5//! Owner: bench gate.
6//! Invariants:
7//! - [`select_partition`] returns only a partition holding one record per distinct
8//!   index, `count` of them, all measured at one commit. It relies on each index being
9//!   below its count, which `GateRecord::shard` ensures for the records `check_group`
10//!   passes.
11//!
12//! A group id is a gate id: `coverage::REQUIRED`, BENCH.toml and
13//! `.github/pr-taxonomy.json` name it, and every shard is that benchmark run with
14//! `--param shard=i/n`, filed under the group. `check_one` hands a group id to
15//! `check_group`, which skips whole-draw records, judges each shard of the chosen
16//! partition by the per-record rules of a plain gate record (required subject, still
17//! standing, run status, clean tree, signature), refuses a shard with transport
18//! failures or without per-subset tallies, and sums per-subset counts
19//! ([`crate::benchmarks::bfcl::aggregate`]) rather than averaging shard scores.
20//!
21//! The aggregate is exact over its shards' counts, but shards need not answer as the
22//! whole draw run in one order would: the samples measured to differ are listed in
23//! `crate::benchmarks::bfcl::sensitive`, and a run records how many it scored as
24//! `known_partition_sensitive`.
25
26/// 2026-09-26: One shard record, as the partition rule sees it: which slice it measured,
27/// at which commit, when, and the caller's handle to the record.
28#[derive(Clone, Debug, PartialEq, Eq)]
29pub struct ShardRecord {
30    pub index: usize,
31    pub count: usize,
32    pub git_sha: String,
33    pub recorded_at: u64,
34    /// 2026-09-26: The caller's handle; `check_group` uses the position in its list.
35    pub handle: usize,
36}
37
38/// 2026-09-26: The chosen partition: its shard count, the one commit it was measured
39/// at, and the caller's handles in index order.
40#[derive(Clone, Debug, PartialEq, Eq)]
41pub struct Partition {
42    pub count: usize,
43    pub git_sha: String,
44    pub handles: Vec<usize>,
45}
46
47/// 2026-09-26: The newest complete partition among `shards`, or why there is none.
48///
49/// Records are grouped by `(count, commit)`, keeping the newest record per index, so a
50/// re-run shard replaces its earlier record instead of being counted twice. A group is
51/// complete when it holds `count` distinct indices. Among complete groups the one whose
52/// newest record is newest wins; a tie goes to the larger count. Records at two commits
53/// are never combined.
54///
55/// # Errors
56/// [`GroupFault::Missing`] when `shards` is empty or no group is complete; `held` then
57/// lists, per `(count, commit)`, the indices present.
58pub fn select_partition(
59    group: &'static str,
60    shards: &[ShardRecord],
61) -> Result<Partition, GroupFault> {
62    if shards.is_empty() {
63        return Err(GroupFault::Missing {
64            group,
65            held: Vec::new(),
66        });
67    }
68    let held = held_by(shards);
69    // 2026-09-26: Every complete partition, ranked by the age of its newest record.
70    let mut complete: Vec<(u64, &PartitionKey, &PerIndex<'_>)> = held
71        .iter()
72        .filter(|(key, per_index)| per_index.len() == key.0)
73        .map(|(key, per_index)| {
74            let newest = per_index.values().map(|s| s.recorded_at).max().unwrap_or(0);
75            (newest, key, per_index)
76        })
77        .collect();
78    complete.sort_by(|a, b| b.0.cmp(&a.0).then_with(|| b.1.0.cmp(&a.1.0)));
79    match complete.into_iter().next() {
80        Some((_, (count, git_sha), per_index)) => Ok(Partition {
81            count: *count,
82            git_sha: git_sha.clone(),
83            handles: per_index.values().map(|s| s.handle).collect(),
84        }),
85        None => Err(GroupFault::Missing {
86            group,
87            held: held
88                .iter()
89                .map(|((count, sha), per_index)| {
90                    (*count, sha.clone(), per_index.keys().copied().collect())
91                })
92                .collect(),
93        }),
94    }
95}
96
97/// 2026-09-26: `(count, commit)`: what a partition is keyed by.
98pub type PartitionKey = (usize, String);
99/// 2026-09-26: The newest record per index within one partition.
100pub type PerIndex<'a> = std::collections::BTreeMap<usize, &'a ShardRecord>;
101
102/// 2026-09-26: Per `(count, commit)`, the newest record per index. On equal
103/// `recorded_at` the record that comes first in `shards` is kept.
104pub fn held_by(shards: &[ShardRecord]) -> std::collections::BTreeMap<PartitionKey, PerIndex<'_>> {
105    let mut held: std::collections::BTreeMap<PartitionKey, PerIndex<'_>> =
106        std::collections::BTreeMap::new();
107    for s in shards {
108        let slot = held
109            .entry((s.count, s.git_sha.clone()))
110            .or_default()
111            .entry(s.index)
112            .or_insert(s);
113        if s.recorded_at > slot.recorded_at {
114            *slot = s;
115        }
116    }
117    held
118}
119
120/// 2026-09-26: A gate whose measurement is produced by a partition of shard runs.
121#[derive(Clone, Copy, Debug, PartialEq, Eq)]
122pub struct BenchmarkGroup {
123    /// 2026-09-26: The gate id, which is also the benchmark every shard runs.
124    pub id: &'static str,
125}
126
127/// 2026-09-26: Every group.
128pub const GROUPS: &[BenchmarkGroup] = &[
129    BenchmarkGroup { id: "bfcl-subset" },
130    BenchmarkGroup {
131        id: "bfcl-subset-echolp",
132    },
133];
134
135/// 2026-09-26: The group a benchmark id names, if any.
136pub fn find(id: &str) -> Option<&'static BenchmarkGroup> {
137    GROUPS.iter().find(|g| g.id == id)
138}
139
140/// 2026-09-26: Why a group is not satisfied.
141#[derive(Clone, Debug, PartialEq, Eq)]
142pub enum GroupFault {
143    /// 2026-09-26: No complete partition at one commit.
144    Missing {
145        group: &'static str,
146        /// 2026-09-26: `(count, commit, indices present)` for every `(count, commit)`
147        /// among the records.
148        held: Vec<(usize, String, Vec<usize>)>,
149    },
150}
151
152impl std::fmt::Display for GroupFault {
153    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
154        match self {
155            Self::Missing { group, held } if held.is_empty() => write!(
156                f,
157                "{group} is a benchmark group and has no shard record at this commit. \
158                 A group is satisfied only by a COMPLETE partition of its draw \
159                 (`--param shard=i/n` for every i in 0..n at one commit): an \
160                 aggregate over a subset is computed on a sample set the thresholds \
161                 were never drawn against, which is a different measurement, not a \
162                 partial one."
163            ),
164            Self::Missing { group, held } => write!(
165                f,
166                "{group} is a benchmark group and no shard partition is complete at one \
167                 commit: {}. A group is satisfied only by a COMPLETE partition of its \
168                 draw — every index 0..n once, all at one commit — since an aggregate \
169                 over a subset is computed on a sample set the thresholds were never \
170                 drawn against, which is a different measurement, not a partial one; \
171                 and a group is ONE measurement.",
172                held.iter()
173                    .map(|(n, sha, idx)| {
174                        let missing: Vec<String> = (0..*n)
175                            .filter(|i| !idx.contains(i))
176                            .map(|i| i.to_string())
177                            .collect();
178                        format!(
179                            "{n}-way at {} holds {:?}, missing {}",
180                            sha.chars().take(10).collect::<String>(),
181                            idx,
182                            missing.join(",")
183                        )
184                    })
185                    .collect::<Vec<_>>()
186                    .join("; ")
187            ),
188        }
189    }
190}
191
192/// 2026-09-26: Which id's BENCH.toml entry describes how to run this benchmark:
193/// `benchmark_id` itself, since a shard runs under its group's id.
194pub fn serve_baseline_id(benchmark_id: &str) -> &str {
195    benchmark_id
196}