Skip to main content

spec_driven_docs/services/
budget.rs

1//! What the budget gates measure, read without judging.
2//!
3//! The gates decide pass or fail. This takes the same measurements and
4//! hands them to whoever needs the number: `sdd debt` to record a ceiling,
5//! and the planner to report a finding about a corpus written before the
6//! convention arrived. One measurement, two readers, no second definition
7//! of what a budget is.
8
9use camino::Utf8Path;
10
11use crate::domain::debt::Measurement;
12use crate::domain::gate_id::GateId;
13use crate::error::AppError;
14use crate::gates::GateCtx;
15
16use crate::domain::debt::BUDGET_GATES;
17
18/// What one budget gate measures at a root.
19///
20/// # Errors
21///
22/// Whatever the gate refuses while reading the tree.
23pub fn measure_gate(root: &Utf8Path, id: GateId) -> Result<Vec<Measurement>, AppError> {
24    let ctx: GateCtx = crate::commands::gate::context_at(root, id)?;
25    let measured = match id {
26        GateId::AdrWordCap => crate::gates::adr_word_cap::measure(&ctx),
27        GateId::AgentsDigestSize => crate::gates::agents_digest_size::measure(&ctx),
28        GateId::ChapterSizeCap => crate::gates::chapter_size_cap::measure(&ctx),
29        GateId::SpecSizeCap => crate::gates::spec_size_cap::measure(&ctx),
30        _ => Ok(Vec::new()),
31    };
32    Ok(measured?)
33}
34
35/// Every measurement the budget gates take at a root.
36///
37/// # Errors
38///
39/// Whatever a gate refuses while reading the tree.
40pub fn measure_all(root: &Utf8Path) -> Result<Vec<Measurement>, AppError> {
41    let mut all = Vec::new();
42    for id in BUDGET_GATES {
43        all.extend(measure_gate(root, *id)?);
44    }
45    Ok(all)
46}