fix(#2594): fold unparseable-approval-row warnings into one aggregated line

This commit is contained in:
damocles 2026-07-19 18:41:40 +02:00 committed by mara
commit 2a5c4d441f

View file

@ -335,20 +335,36 @@ impl ApprovalLookup {
}
}
/// Collect approval rows, dropping (and logging) any that fail to
/// deserialize. A single malformed / unknown-kind row must never blank
/// the whole list: `collect::<Result<Vec>>()` is all-or-nothing, so one
/// bad row used to make `pending()` / `recent_resolved()` error out
/// wholesale — the dashboard then rendered an empty approvals queue.
/// Collect approval rows, dropping any that fail to deserialize. A single
/// malformed / unknown-kind row must never blank the whole list:
/// `collect::<Result<Vec>>()` is all-or-nothing, so one bad row used to make
/// `pending()` / `recent_resolved()` error out wholesale — the dashboard then
/// rendered an empty approvals queue.
///
/// Drops are aggregated by error message and logged **once per call** rather
/// than one line per row: a batch of legacy unknown-kind rows (e.g. the
/// retired `apply_commit` approvals from the removed non-PR config flow) sit
/// `pending` forever and would otherwise flood the journal with an identical
/// warning on every dashboard render. Aggregating keeps the signal (how many,
/// which error) without the flood.
fn collect_lenient(rows: impl Iterator<Item = rusqlite::Result<Approval>>) -> Vec<Approval> {
rows.filter_map(|r| match r {
Ok(a) => Some(a),
Err(e) => {
tracing::warn!(error = ?e, "skipping unparseable approval row");
None
let mut out = Vec::new();
let mut dropped: std::collections::HashMap<String, usize> = std::collections::HashMap::new();
for r in rows {
match r {
Ok(a) => out.push(a),
Err(e) => *dropped.entry(e.to_string()).or_default() += 1,
}
})
.collect()
}
if !dropped.is_empty() {
let total: usize = dropped.values().sum();
tracing::warn!(
dropped = total,
by_error = ?dropped,
"skipped unparseable approval rows"
);
}
out
}
fn row_to_approval(row: &rusqlite::Row<'_>) -> rusqlite::Result<Approval> {