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