Skip to main content

stt_optimize/advisors/
mod.rs

1//! Evidence-based flag advisors: each module inspects the analysis result
2//! (and, where useful, trial-encodes the loader sample through the real
3//! encoder) and returns [`Advice`] entries for stt-build flags beyond the
4//! zoom/bucket basics.
5//!
6//! Contract: every advisor exposes
7//! `pub fn advise(result: &AnalysisResult, data: &LoadedData) -> anyhow::Result<Vec<Advice>>`.
8//! Advice with `lossy: true` is NEVER auto-applied by `stt-build --auto` and
9//! never lands in `to_command` — it is surfaced loudly for the user to opt in
10//! (the no-thinning principle).
11
12pub mod budget;
13pub mod layout;
14pub mod quantize;
15pub mod temporal;
16
17use serde::{Deserialize, Serialize};
18
19use crate::analysis::AnalysisResult;
20use crate::loader::LoadedData;
21
22/// Advisor confidence in a recommendation.
23#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
24#[serde(rename_all = "lowercase")]
25pub enum AdviceConfidence {
26    High,
27    Medium,
28    Low,
29}
30
31impl std::fmt::Display for AdviceConfidence {
32    /// Lowercase, matching the serde wire form (`high`/`medium`/`low`).
33    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
34        f.write_str(match self {
35            AdviceConfidence::High => "high",
36            AdviceConfidence::Medium => "medium",
37            AdviceConfidence::Low => "low",
38        })
39    }
40}
41
42/// One evidence-based flag recommendation.
43#[derive(Debug, Clone, Serialize, Deserialize)]
44pub struct Advice {
45    /// The stt-build flag, e.g. `--quantize-coords` (name must exist in
46    /// docs/api/cli-reference.md).
47    pub flag: String,
48    /// Flag value, `None` for bare switches.
49    pub value: Option<String>,
50    /// One-line, evidence-based rationale (numbers from this dataset, not
51    /// folklore).
52    pub why: String,
53    /// Measured or estimated effect, e.g. `"-36% sample encode (measured)"`.
54    pub projected: Option<String>,
55    /// Lossy/destructive levers are never auto-applied and never join
56    /// `to_command`.
57    pub lossy: bool,
58    /// How sure the advisor is.
59    pub confidence: AdviceConfidence,
60}
61
62/// Run every advisor. Order: quantize, temporal, layout, budget.
63pub fn run_all(result: &AnalysisResult, data: &LoadedData) -> anyhow::Result<Vec<Advice>> {
64    let mut advice = Vec::new();
65    advice.extend(quantize::advise(result, data)?);
66    advice.extend(temporal::advise(result, data)?);
67    advice.extend(layout::advise(result, data)?);
68    advice.extend(budget::advise(result, data)?);
69    Ok(advice)
70}