launchbound_report/
render.rs1use crate::Report;
5use std::fmt::Write;
6
7pub fn launchbound_metal_notice() -> &'static str {
9 "NO convergence gate exists on the Metal path: the same bug class is NOT checked"
10}
11
12pub fn render_text(report: &Report) -> String {
19 let mut out = String::new();
20 let device = report
21 .device
22 .as_ref()
23 .map(|d| format!("{} (cc {}, driver {})", d.name, d.cc, d.driver_version))
24 .unwrap_or_else(|| "no device — nothing measured yet".into());
25 let _ = writeln!(
26 out,
27 "launchbound report — {} · gate cc {} · {} · {}",
28 report.kernel, report.gate_cc, report.measurement_kind, device
29 );
30 if report.convergence_gate == "none" {
33 let _ = writeln!(out, "\n*** {} ***", launchbound_metal_notice());
34 }
35
36 match &report.chosen {
37 Some(chosen) => {
38 let s = &chosen.summary;
39 let _ = writeln!(
40 out,
41 "\nCHOSEN: {} {}\n {:.4} ms [{:.4}, {:.4}] (n={}, {} outliers rejected)",
42 chosen.id,
43 chosen.config,
44 s.median_ms,
45 s.ci95_lo_ms,
46 s.ci95_hi_ms,
47 s.n,
48 s.outliers_rejected
49 );
50 if !report.indistinguishable_from_chosen.is_empty() {
51 let _ = writeln!(
52 out,
53 " statistically indistinguishable from: {}",
54 report.indistinguishable_from_chosen.join(", ")
55 );
56 }
57 }
58 None => {
59 let _ = writeln!(
60 out,
61 "\nCHOSEN: none — no admitted candidate has a measurement"
62 );
63 }
64 }
65
66 if !report.rejected_faster.is_empty() {
67 let _ = writeln!(
68 out,
69 "\nREFUSED BUT FASTER — an autotuner without a convergence gate would have\nhanded you one of these:"
70 );
71 for r in &report.rejected_faster {
72 let s = &r.summary;
73 let _ = writeln!(
74 out,
75 " {} {}\n {:.4} ms [{:.4}, {:.4}] — {:.2}x faster than the chosen config",
76 r.id, r.config, s.median_ms, s.ci95_lo_ms, s.ci95_hi_ms, r.speedup_vs_chosen
77 );
78 for rule in &r.rules {
79 let _ = writeln!(
80 out,
81 " REFUSED {} at {}: {}",
82 rule.rule,
83 rule.span.as_deref().unwrap_or("<no span>"),
84 rule.reason
85 );
86 }
87 }
88 if let Some(reason) = &report.allow_unsafe_reason {
89 let _ = writeln!(
90 out,
91 " (measured under --allow-unsafe; recorded reason: {reason:?})"
92 );
93 }
94 }
95
96 let _ = writeln!(out, "\nALL CANDIDATES:");
97 for c in &report.candidates {
98 let timing = match (&c.summary, c.measurement_status.as_str()) {
99 (Some(s), "ok") => format!(
100 "{:.4} ms [{:.4}, {:.4}]",
101 s.median_ms, s.ci95_lo_ms, s.ci95_hi_ms
102 ),
103 (_, "timeout") => "TIMED OUT (presumed hung — the failure the gate predicts)".into(),
104 (_, "error") => format!("error: {}", c.measurement_error.as_deref().unwrap_or("?")),
105 _ => "unmeasured".into(),
106 };
107 let mark = match c.verdict.as_str() {
108 "clean" => " ",
109 "admitted_with_caveats" => "~",
110 "disqualified" => "x",
111 "ungated" => "u",
112 _ => "!",
113 };
114 let _ = writeln!(out, " {mark} {} {} {timing}", c.id, c.config);
115 for rule in &c.rules {
116 let _ = writeln!(
117 out,
118 " {} at {}: {}",
119 rule.rule,
120 rule.span.as_deref().unwrap_or("<no span>"),
121 rule.reason
122 );
123 }
124 }
125
126 let t = &report.totals;
127 let _ = writeln!(
128 out,
129 "\n{} candidates: {} admitted, {} refused; {} measured ok; {:.1} GPU-seconds consumed",
130 t.candidates, t.admitted, t.refused, t.measured_ok, t.gpu_seconds
131 );
132 out
133}