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}