1use crate::catalogue_cases::measurement_coverage;
4use crate::catalogue_evidence::{
5 clean, BenchmarkRow, ValidatedCatalogueEvidence, C_DIRECT_MODE, INPUT_LENGTHS, PYTHON_MODE,
6 RUST_CALLER_MODE, RUST_OWNED_MODE, RUST_PREPARED_MODE, RUST_STREAMING_MODE,
7};
8use crate::catalogue_statistics::validate_positive_timing_evidence;
9use crate::pattern_shapes::PATTERN_SHAPES;
10use serde_json::Value;
11use std::cmp::Ordering;
12use std::collections::{BTreeMap, BTreeSet};
13use std::fs;
14
15use std::path::Path;
16#[derive(Clone, Debug, PartialEq)]
17pub struct DiagnosticEvidence {
18 pub captured_at_utc: String,
19 pub baseline_commit: String,
20 pub final_commit: String,
21 pub commands: BTreeMap<String, String>,
22 pub environment: BTreeMap<String, String>,
23 pub tickets: Vec<DiagnosticTicket>,
24}
25
26#[derive(Clone, Debug, PartialEq)]
27pub struct DiagnosticTicket {
28 pub ticket: u64,
29 pub ranked_hypotheses: Vec<Value>,
30 pub profile_or_compiler_evidence: Value,
31 pub criterion_comparisons: Vec<Value>,
32 pub semantic_comparisons: Vec<Value>,
33 pub required_neighbor_coverage: Vec<Value>,
34}
35
36#[derive(Clone, Debug, PartialEq)]
37pub struct CriterionDiagnostics {
38 pub pre_commit: String,
39 pub final_commit: String,
40 pub environment: BTreeMap<String, String>,
41 pub measurements: Vec<CriterionDiagnosticMeasurement>,
42}
43
44#[derive(Clone, Debug, PartialEq)]
45pub struct CriterionDiagnosticMeasurement {
46 pub ticket: u64,
47 pub case_id: String,
48 pub role: String,
49 pub revision: String,
50 pub command: String,
51 pub cwd: String,
52 pub benchmark_id: String,
53 pub timed_boundary: String,
54 pub sample_count: usize,
55 pub observations_per_iteration: usize,
56 pub median_ns: f64,
57 pub ci95_lower_ns: f64,
58 pub ci95_upper_ns: f64,
59 pub throughput_observations_per_second: f64,
60}
61
62#[derive(Clone, Debug, PartialEq)]
63pub struct CycleRegressionEvidence {
64 pub command: String,
65 pub cwd: String,
66 pub os: String,
67 pub arch: String,
68 pub cpu: String,
69 pub seam: String,
70 pub measurements: Vec<CycleMeasurement>,
71 pub comparisons: Vec<CycleComparison>,
72}
73
74#[derive(Clone, Debug, PartialEq)]
75pub struct CycleMeasurement {
76 pub indicator: String,
77 pub input_length: usize,
78 pub variant: String,
79 pub source_provenance: String,
80 pub sample_count: usize,
81 pub median_ns: f64,
82 pub ci95_lower_ns: f64,
83 pub ci95_upper_ns: f64,
84 pub throughput_observations_per_second: f64,
85}
86
87#[derive(Clone, Debug, PartialEq)]
88pub struct CycleComparison {
89 pub indicator: String,
90 pub input_length: usize,
91 pub before_variant: String,
92 pub after_variant: String,
93 pub cursor_vs_baseline_percent: f64,
94 pub after_vs_baseline_percent: f64,
95 pub source_proof: String,
96 pub disposition: String,
97}
98
99pub fn read_diagnostic_evidence(path: &Path) -> Result<DiagnosticEvidence, String> {
100 let input =
101 fs::read_to_string(path).map_err(|error| format!("read {}: {error}", path.display()))?;
102 parse_diagnostic_evidence(&input)
103}
104
105pub fn parse_diagnostic_evidence(input: &str) -> Result<DiagnosticEvidence, String> {
106 let root: Value = serde_json::from_str(input)
107 .map_err(|error| format!("diagnostic evidence JSON: {error}"))?;
108 if json_string(&root, "schema")? != "fast-ta.issue-57-62.diagnostic-evidence.v1" {
109 return Err("unsupported diagnostic evidence schema".to_owned());
110 }
111 let baseline_revision = json_object(&root, "baseline_revision")?;
112 let final_revision = json_object(&root, "final_revision")?;
113 let commands = json_string_map(json_object(&root, "commands")?, "commands")?;
114 let environment = json_scalar_map(json_object(&root, "environment")?, "environment")?;
115 let artifacts = json_array(&root, "artifacts")?;
116 for required in [
117 "issue_57_62_criterion_diagnostics.json",
118 "issue_57_62_semantic_pre.tsv",
119 "issue_57_62_semantic_final.tsv",
120 ] {
121 if !artifacts.iter().any(|artifact| {
122 artifact
123 .get("path")
124 .and_then(Value::as_str)
125 .is_some_and(|path| path.ends_with(required))
126 }) {
127 return Err(format!(
128 "diagnostic evidence is missing artifact {required}"
129 ));
130 }
131 }
132 let mut tickets = Vec::new();
133 for value in json_array(&root, "tickets")? {
134 let ticket = json_u64(value, "ticket")?;
135 let ranked_hypotheses = json_array(value, "ranked_hypotheses")?.to_vec();
136 if !(3..=5).contains(&ranked_hypotheses.len()) {
137 return Err(format!(
138 "issue {ticket} must contain 3 to 5 ranked hypotheses"
139 ));
140 }
141 for (index, hypothesis) in ranked_hypotheses.iter().enumerate() {
142 if json_u64(hypothesis, "rank")? != index as u64 + 1 {
143 return Err(format!(
144 "issue {ticket} hypotheses are not consecutively ranked"
145 ));
146 }
147 for key in ["hypothesis", "prediction", "status", "evidence"] {
148 json_nonempty_string(hypothesis, key)?;
149 }
150 }
151 let profile = value
152 .get("profile_or_compiler_evidence")
153 .filter(|candidate| candidate.is_object())
154 .ok_or_else(|| format!("issue {ticket} is missing profile/compiler evidence"))?
155 .clone();
156 for key in [
157 "artifact",
158 "artifact_sha256",
159 "benchmark_command",
160 "profile_command",
161 "benchmark_id",
162 "case",
163 "cwd",
164 ] {
165 json_nonempty_string(&profile, key)?;
166 }
167 let criterion_comparisons =
168 json_array(value, "criterion_same_session_comparisons")?.to_vec();
169 let semantic_comparisons =
170 json_array(value, "semantic_same_run_rust_c_comparisons")?.to_vec();
171 let required_neighbor_coverage = json_array(value, "required_neighbor_coverage")?.to_vec();
172 if criterion_comparisons.is_empty()
173 || semantic_comparisons.is_empty()
174 || required_neighbor_coverage.is_empty()
175 {
176 return Err(format!(
177 "issue {ticket} is missing Criterion, semantic, or neighboring-workload evidence"
178 ));
179 }
180 for comparison in &criterion_comparisons {
181 if json_u64(comparison, "ticket")? != ticket {
182 return Err(format!(
183 "issue {ticket} contains a cross-ticket Criterion row"
184 ));
185 }
186 for key in ["case_id", "role", "disposition"] {
187 json_nonempty_string(comparison, key)?;
188 }
189 for key in [
190 "pre_median_ns",
191 "final_median_ns",
192 "change_percent",
193 "speedup",
194 "noise_gate_percent",
195 ] {
196 json_numeric(comparison, key)?;
197 }
198 }
199 for semantic in &semantic_comparisons {
200 if json_u64(semantic, "ticket")? != ticket {
201 return Err(format!(
202 "issue {ticket} contains a cross-ticket semantic row"
203 ));
204 }
205 json_nonempty_string(semantic, "case_id")?;
206 json_nonempty_string(semantic, "disposition")?;
207 json_u64(semantic, "input_length")?;
208 json_bool(semantic, "input_checksum_match")?;
209 json_bool(semantic, "output_checksum_match")?;
210 for revision in ["pre", "final"] {
211 format_json_timing(json_object(semantic, &format!("{revision}_fast_ta"))?)?;
212 format_json_timing(json_object(semantic, &format!("{revision}_ta_lib_c"))?)?;
213 json_numeric(semantic, &format!("{revision}_rust_over_c"))?;
214 }
215 }
216 for neighbor in &required_neighbor_coverage {
217 json_nonempty_string(neighbor, "workload")?;
218 json_nonempty_string(neighbor, "status")?;
219 }
220 tickets.push(DiagnosticTicket {
221 ticket,
222 ranked_hypotheses,
223 profile_or_compiler_evidence: profile,
224 criterion_comparisons,
225 semantic_comparisons,
226 required_neighbor_coverage,
227 });
228 }
229 let actual = tickets
230 .iter()
231 .map(|ticket| ticket.ticket)
232 .collect::<BTreeSet<_>>();
233 let expected = (57_u64..=62).collect::<BTreeSet<_>>();
234 if actual != expected || tickets.len() != expected.len() {
235 return Err(
236 "diagnostic evidence must contain issues 57 through 62 exactly once".to_owned(),
237 );
238 }
239 tickets.sort_by_key(|ticket| ticket.ticket);
240 Ok(DiagnosticEvidence {
241 captured_at_utc: json_nonempty_string(&root, "captured_at_utc")?,
242 baseline_commit: json_nonempty_string(baseline_revision, "commit")?,
243 final_commit: json_nonempty_string(final_revision, "commit")?,
244 commands,
245 environment,
246 tickets,
247 })
248}
249
250pub fn read_criterion_diagnostics(path: &Path) -> Result<CriterionDiagnostics, String> {
251 let input =
252 fs::read_to_string(path).map_err(|error| format!("read {}: {error}", path.display()))?;
253 parse_criterion_diagnostics(&input)
254}
255
256pub fn parse_criterion_diagnostics(input: &str) -> Result<CriterionDiagnostics, String> {
257 let root: Value = serde_json::from_str(input)
258 .map_err(|error| format!("Criterion diagnostics JSON: {error}"))?;
259 if json_string(&root, "schema")? != "fast-ta.issue-57-62.criterion-diagnostics.v1" {
260 return Err("unsupported Criterion diagnostics schema".to_owned());
261 }
262 let mut measurements = Vec::new();
263 for value in json_array(&root, "measurements")? {
264 let median = json_object(value, "median")?;
265 let measurement = CriterionDiagnosticMeasurement {
266 ticket: json_u64(value, "ticket")?,
267 case_id: json_nonempty_string(value, "case_id")?,
268 role: json_nonempty_string(value, "role")?,
269 revision: json_nonempty_string(value, "revision")?,
270 command: json_nonempty_string(value, "command")?,
271 cwd: json_nonempty_string(value, "cwd")?,
272 benchmark_id: json_nonempty_string(value, "benchmark_id")?,
273 timed_boundary: json_nonempty_string(value, "timed_boundary")?,
274 sample_count: json_u64(value, "sample_count")? as usize,
275 observations_per_iteration: json_u64(value, "observations_per_iteration")? as usize,
276 median_ns: json_f64(median, "point_estimate_ns")?,
277 ci95_lower_ns: json_f64(median, "ci95_lower_ns")?,
278 ci95_upper_ns: json_f64(median, "ci95_upper_ns")?,
279 throughput_observations_per_second: json_f64(
280 value,
281 "throughput_observations_per_second",
282 )?,
283 };
284 if !(57..=62).contains(&measurement.ticket)
285 || !matches!(measurement.revision.as_str(), "pre" | "final")
286 {
287 return Err("Criterion measurement has unsupported ticket or revision".to_owned());
288 }
289 validate_positive_timing_evidence(
290 measurement.median_ns,
291 measurement.ci95_lower_ns,
292 measurement.ci95_upper_ns,
293 measurement.throughput_observations_per_second,
294 measurement.sample_count,
295 measurement.observations_per_iteration,
296 )
297 .map_err(|error| format!("Criterion {}: {error}", measurement.case_id))?;
298 measurements.push(measurement);
299 }
300 if measurements.is_empty() {
301 return Err("Criterion diagnostics has no measurements".to_owned());
302 }
303 let grouped = measurements
304 .iter()
305 .map(|measurement| {
306 (
307 measurement.ticket,
308 measurement.case_id.as_str(),
309 measurement.revision.as_str(),
310 )
311 })
312 .collect::<BTreeSet<_>>();
313 for measurement in &measurements {
314 let other = if measurement.revision == "pre" {
315 "final"
316 } else {
317 "pre"
318 };
319 if !grouped.contains(&(measurement.ticket, measurement.case_id.as_str(), other)) {
320 return Err(format!(
321 "Criterion {} is missing its {other} measurement",
322 measurement.case_id
323 ));
324 }
325 }
326 let mut comparison_keys = BTreeSet::new();
327 for comparison in json_array(&root, "comparisons")? {
328 let ticket = json_u64(comparison, "ticket")?;
329 let case_id = json_nonempty_string(comparison, "case_id")?;
330 if !comparison_keys.insert((ticket, case_id.clone())) {
331 return Err(format!("duplicate Criterion comparison for {case_id}"));
332 }
333 let pre = measurements
334 .iter()
335 .find(|measurement| {
336 measurement.ticket == ticket
337 && measurement.case_id == case_id
338 && measurement.revision == "pre"
339 })
340 .ok_or_else(|| format!("Criterion comparison {case_id} has no pre measurement"))?;
341 let final_measurement = measurements
342 .iter()
343 .find(|measurement| {
344 measurement.ticket == ticket
345 && measurement.case_id == case_id
346 && measurement.revision == "final"
347 })
348 .ok_or_else(|| format!("Criterion comparison {case_id} has no final measurement"))?;
349 if json_f64(comparison, "pre_median_ns")? != pre.median_ns
350 || json_f64(comparison, "final_median_ns")? != final_measurement.median_ns
351 {
352 return Err(format!(
353 "Criterion comparison {case_id} medians do not match its measurements"
354 ));
355 }
356 json_nonempty_string(comparison, "disposition")?;
357 }
358 if comparison_keys.len() * 2 != grouped.len() {
359 return Err("Criterion comparisons do not cover every measurement pair".to_owned());
360 }
361 Ok(CriterionDiagnostics {
362 pre_commit: json_nonempty_string(json_object(&root, "pre_revision")?, "commit")?,
363 final_commit: json_nonempty_string(json_object(&root, "final_revision")?, "commit")?,
364 environment: json_scalar_map(json_object(&root, "environment")?, "environment")?,
365 measurements,
366 })
367}
368
369pub fn read_cycle_regression(path: &Path) -> Result<CycleRegressionEvidence, String> {
370 let input =
371 fs::read_to_string(path).map_err(|error| format!("read {}: {error}", path.display()))?;
372 parse_cycle_regression(&input)
373}
374
375pub fn parse_cycle_regression(input: &str) -> Result<CycleRegressionEvidence, String> {
376 let mut run = None;
377 let mut measurements = Vec::new();
378 let mut comparisons = Vec::new();
379 for (index, line) in input
380 .lines()
381 .enumerate()
382 .filter(|(_, line)| !line.is_empty())
383 {
384 let value: Value = serde_json::from_str(line)
385 .map_err(|error| format!("cycle regression JSONL row {}: {error}", index + 1))?;
386 match json_nonempty_string(&value, "record_type")?.as_str() {
387 "run" => {
388 if run.is_some() {
389 return Err("cycle regression has multiple run records".to_owned());
390 }
391 if json_string(&value, "schema")? != "fast-ta.issue61.cycle-regression.v1" {
392 return Err("unsupported cycle regression schema".to_owned());
393 }
394 let host = json_object(&value, "host")?;
395 run = Some((
396 json_nonempty_string(&value, "command")?,
397 json_nonempty_string(&value, "cwd")?,
398 json_nonempty_string(host, "os")?,
399 json_nonempty_string(host, "arch")?,
400 json_nonempty_string(host, "cpu")?,
401 json_nonempty_string(&value, "seam")?,
402 ));
403 }
404 "measurement" => {
405 let ci = json_array(&value, "median_95ci_ns")?;
406 if ci.len() != 2 {
407 return Err("cycle measurement CI must have two bounds".to_owned());
408 }
409 let measurement = CycleMeasurement {
410 indicator: json_nonempty_string(&value, "indicator")?,
411 input_length: json_u64(&value, "size")? as usize,
412 variant: json_nonempty_string(&value, "variant")?,
413 source_provenance: json_nonempty_string(&value, "source_provenance")?,
414 sample_count: json_u64(&value, "samples")? as usize,
415 median_ns: json_f64(&value, "median_ns")?,
416 ci95_lower_ns: ci[0]
417 .as_f64()
418 .ok_or_else(|| "cycle CI lower bound is not numeric".to_owned())?,
419 ci95_upper_ns: ci[1]
420 .as_f64()
421 .ok_or_else(|| "cycle CI upper bound is not numeric".to_owned())?,
422 throughput_observations_per_second: json_f64(
423 &value,
424 "throughput_observations_per_second",
425 )?,
426 };
427 validate_positive_timing_evidence(
428 measurement.median_ns,
429 measurement.ci95_lower_ns,
430 measurement.ci95_upper_ns,
431 measurement.throughput_observations_per_second,
432 measurement.sample_count,
433 measurement.input_length,
434 )
435 .map_err(|error| format!("cycle {}: {error}", measurement.indicator))?;
436 measurements.push(measurement);
437 }
438 "comparison" => comparisons.push(CycleComparison {
439 indicator: json_nonempty_string(&value, "indicator")?,
440 input_length: json_u64(&value, "size")? as usize,
441 before_variant: json_nonempty_string(&value, "before_variant")?,
442 after_variant: json_nonempty_string(&value, "after_variant")?,
443 cursor_vs_baseline_percent: json_f64(&value, "cursor_vs_b156ac1_median_percent")?,
444 after_vs_baseline_percent: json_f64(&value, "after_vs_b156ac1_percent")?,
445 source_proof: json_nonempty_string(&value, "after_source_proof")?,
446 disposition: json_nonempty_string(&value, "disposition")?,
447 }),
448 other => return Err(format!("unsupported cycle record type {other:?}")),
449 }
450 }
451 let (command, cwd, os, arch, cpu, seam) =
452 run.ok_or_else(|| "cycle regression has no run record".to_owned())?;
453 if measurements.is_empty() || comparisons.is_empty() {
454 return Err("cycle regression is missing measurements or comparisons".to_owned());
455 }
456 for comparison in &comparisons {
457 for variant in ["b156ac1_modulo", comparison.before_variant.as_str()] {
458 if !measurements.iter().any(|measurement| {
459 measurement.indicator == comparison.indicator
460 && measurement.input_length == comparison.input_length
461 && measurement.variant == variant
462 }) {
463 return Err(format!(
464 "cycle comparison {} {} is missing variant {variant}",
465 comparison.indicator, comparison.input_length
466 ));
467 }
468 }
469 }
470 Ok(CycleRegressionEvidence {
471 command,
472 cwd,
473 os,
474 arch,
475 cpu,
476 seam,
477 measurements,
478 comparisons,
479 })
480}
481
482fn json_array<'a>(value: &'a Value, key: &str) -> Result<&'a [Value], String> {
483 value
484 .get(key)
485 .and_then(Value::as_array)
486 .map(Vec::as_slice)
487 .ok_or_else(|| format!("JSON value is missing array field {key:?}"))
488}
489
490fn json_object<'a>(value: &'a Value, key: &str) -> Result<&'a Value, String> {
491 value
492 .get(key)
493 .filter(|value| value.is_object())
494 .ok_or_else(|| format!("JSON value is missing object field {key:?}"))
495}
496
497fn json_string_map(value: &Value, name: &str) -> Result<BTreeMap<String, String>, String> {
498 value
499 .as_object()
500 .expect("json_object checked the value")
501 .iter()
502 .map(|(key, value)| {
503 value
504 .as_str()
505 .filter(|value| !value.is_empty())
506 .map(|value| (key.clone(), value.to_owned()))
507 .ok_or_else(|| format!("{name}.{key} must be a non-empty string"))
508 })
509 .collect()
510}
511
512fn json_scalar_map(value: &Value, name: &str) -> Result<BTreeMap<String, String>, String> {
513 value
514 .as_object()
515 .expect("json_object checked the value")
516 .iter()
517 .map(|(key, value)| {
518 let rendered = match value {
519 Value::String(value) if !value.is_empty() => value.clone(),
520 Value::Number(value) => value.to_string(),
521 Value::Bool(value) => value.to_string(),
522 _ => return Err(format!("{name}.{key} must be a non-empty scalar")),
523 };
524 Ok((key.clone(), rendered))
525 })
526 .collect()
527}
528
529#[derive(Clone, Debug, PartialEq)]
530pub struct PlatformQualification {
531 pub artifact: String,
532 pub platform: String,
533 pub precision: String,
534 pub runtime: String,
535 pub profile: String,
536 pub cpu: String,
537 pub os: String,
538 pub commit: String,
539 pub workflow_run_id: String,
540 pub workflow_run_url: String,
541 pub workflow_job: String,
542 pub active_backend: String,
543 pub feature_flags: String,
544 pub measurements: Vec<QualificationMeasurement>,
545}
546
547#[derive(Clone, Debug, PartialEq)]
548pub struct QualificationMeasurement {
549 pub mode: String,
550 pub backend: String,
551 pub input_length: usize,
552 pub equivalent_to_scalar: bool,
553 pub semantic_status: String,
554 pub timing_status: String,
555 pub median_ns: f64,
556 pub ci95_lower_ns: f64,
557 pub ci95_upper_ns: f64,
558 pub throughput_observations_per_second: f64,
559 pub sample_count: usize,
560 pub timed_boundary: String,
561}
562
563pub fn read_platform_qualification(path: &Path) -> Result<PlatformQualification, String> {
564 let input =
565 fs::read_to_string(path).map_err(|error| format!("read {}: {error}", path.display()))?;
566 parse_platform_qualification(&input, &path.display().to_string())
567}
568
569pub fn parse_platform_qualification(
570 input: &str,
571 artifact: &str,
572) -> Result<PlatformQualification, String> {
573 let mut metadata = None;
574 let mut has_aggregate_validation = false;
575 let mut validated_backends = BTreeSet::new();
576 let mut measurements = Vec::new();
577 for (index, line) in input
578 .lines()
579 .enumerate()
580 .filter(|(_, line)| !line.is_empty())
581 {
582 let value: Value = serde_json::from_str(line)
583 .map_err(|error| format!("{artifact} JSONL row {}: {error}", index + 1))?;
584 match json_string(&value, "record")?.as_str() {
585 "metadata" => {
586 if metadata.is_some() {
587 return Err(format!("{artifact} has more than one metadata record"));
588 }
589 let active_backend = value
590 .get("active_backend")
591 .and_then(Value::as_str)
592 .or_else(|| value.get("simd_backend").and_then(Value::as_str))
593 .ok_or_else(|| format!("{artifact} metadata is missing a runtime backend"))?
594 .to_owned();
595 let feature_flags = value
596 .get("features")
597 .and_then(Value::as_str)
598 .filter(|features| !features.is_empty())
599 .map(str::to_owned)
600 .or_else(|| {
601 let cargo = value
602 .get("cargo_features")?
603 .as_str()
604 .filter(|features| !features.is_empty())?;
605 let target = value
606 .get("target_features")?
607 .as_str()
608 .filter(|features| !features.is_empty())?;
609 Some(format!("cargo_features={cargo}; target_features={target}"))
610 })
611 .or_else(|| {
612 let flags = ["scalar_feature_flags", "simd_feature_flags"]
613 .into_iter()
614 .map(|key| {
615 value
616 .get(key)
617 .and_then(Value::as_str)
618 .filter(|flag| !flag.is_empty())
619 .map(|flag| format!("{key}={flag}"))
620 })
621 .collect::<Option<Vec<_>>>()?;
622 Some(flags.join("; "))
623 })
624 .ok_or_else(|| {
625 format!("{artifact} metadata is missing string field \"features\"")
626 })?;
627 let profile = value
628 .get("profile")
629 .and_then(Value::as_str)
630 .or_else(|| value.get("rust_profile").and_then(Value::as_str))
631 .filter(|profile| !profile.is_empty())
632 .ok_or_else(|| {
633 format!("{artifact} metadata is missing string field \"profile\"")
634 })?
635 .to_owned();
636 metadata = Some((
637 json_string(&value, "platform")?,
638 json_nonempty_string(&value, "precision")?,
639 json_string(&value, "runtime")?,
640 profile,
641 json_string(&value, "cpu")?,
642 json_nonempty_string(&value, "os")?,
643 json_string(&value, "commit")?,
644 json_identifier(&value, "workflow_run_id")?,
645 json_string(&value, "workflow_run_url")?,
646 json_identifier_alias(&value, "workflow_job", "workflow_job_id")?,
647 active_backend,
648 feature_flags,
649 ));
650 }
651 "measurement" => {
652 let measurement = QualificationMeasurement {
653 mode: json_string(&value, "mode")?,
654 backend: json_string(&value, "backend")?,
655 input_length: json_u64(&value, "input_length")? as usize,
656 equivalent_to_scalar: json_bool(&value, "equivalent_to_scalar")?,
657 semantic_status: json_string(&value, "semantic_status")?,
658 timing_status: json_string(&value, "timing_status")?,
659 median_ns: json_f64(&value, "median_ns")?,
660 ci95_lower_ns: json_f64(&value, "ci95_lower_ns")?,
661 ci95_upper_ns: json_f64(&value, "ci95_upper_ns")?,
662 throughput_observations_per_second: json_f64(
663 &value,
664 "throughput_observations_per_second",
665 )?,
666 sample_count: json_u64(&value, "sample_count")? as usize,
667 timed_boundary: json_string(&value, "timed_boundary")?,
668 };
669 if !INPUT_LENGTHS.contains(&measurement.input_length) {
670 return Err(format!(
671 "{artifact} has unsupported input length {}",
672 measurement.input_length
673 ));
674 }
675 validate_positive_timing_evidence(
676 measurement.median_ns,
677 measurement.ci95_lower_ns,
678 measurement.ci95_upper_ns,
679 measurement.throughput_observations_per_second,
680 measurement.sample_count,
681 measurement.input_length,
682 )
683 .map_err(|error| format!("{artifact} measurement row {}: {error}", index + 1))?;
684 measurements.push(measurement);
685 }
686 "validation" => match validate_qualification_validation(&value, artifact, index + 1)? {
687 Some(backend) if !validated_backends.insert(backend.clone()) => {
688 return Err(format!(
689 "{artifact} has duplicate validation records for backend {backend:?}"
690 ));
691 }
692 Some(_) => {}
693 None if has_aggregate_validation => {
694 return Err(format!(
695 "{artifact} has more than one aggregate validation record"
696 ));
697 }
698 None => has_aggregate_validation = true,
699 },
700 other => return Err(format!("{artifact} has unsupported record type {other:?}")),
701 }
702 }
703 if !has_aggregate_validation && validated_backends.is_empty() {
704 return Err(format!("{artifact} has no validation records"));
705 }
706 let (
707 platform,
708 precision,
709 runtime,
710 profile,
711 cpu,
712 os,
713 commit,
714 workflow_run_id,
715 workflow_run_url,
716 workflow_job,
717 active_backend,
718 feature_flags,
719 ) = metadata.ok_or_else(|| format!("{artifact} has no metadata record"))?;
720 if measurements.is_empty() {
721 return Err(format!("{artifact} has no measurement records"));
722 }
723 for measurement in &measurements {
724 let is_direct_c =
725 measurement.backend == "ta-lib-c" && measurement.mode == "direct C caller-owned";
726 let needs_backend_validation = measurement.equivalent_to_scalar && !is_direct_c;
727 if needs_backend_validation
728 && !has_aggregate_validation
729 && !validated_backends.contains(&measurement.backend)
730 {
731 return Err(format!(
732 "{artifact} reports scalar equivalence for backend {:?} without a matching validation record",
733 measurement.backend
734 ));
735 }
736 }
737 Ok(PlatformQualification {
738 artifact: artifact.to_owned(),
739 platform,
740 precision,
741 runtime,
742 cpu,
743 os,
744 profile,
745 commit,
746 workflow_run_id,
747 workflow_run_url,
748 workflow_job,
749 active_backend,
750 feature_flags,
751 measurements,
752 })
753}
754
755fn json_string(value: &Value, key: &str) -> Result<String, String> {
756 value
757 .get(key)
758 .and_then(Value::as_str)
759 .map(str::to_owned)
760 .ok_or_else(|| format!("JSON record is missing string field {key:?}"))
761}
762
763fn json_nonempty_string(value: &Value, key: &str) -> Result<String, String> {
764 let parsed = json_string(value, key)?;
765 if parsed.is_empty() {
766 return Err(format!("JSON record has empty string field {key:?}"));
767 }
768 Ok(parsed)
769}
770
771fn json_u64(value: &Value, key: &str) -> Result<u64, String> {
772 value
773 .get(key)
774 .and_then(Value::as_u64)
775 .ok_or_else(|| format!("JSON record is missing integer field {key:?}"))
776}
777
778fn json_identifier(value: &Value, key: &str) -> Result<String, String> {
779 match value.get(key) {
780 Some(Value::String(value)) if !value.is_empty() => Ok(value.clone()),
781 Some(Value::Number(value)) if value.is_u64() => Ok(value.to_string()),
782 _ => Err(format!(
783 "JSON record is missing string or integer field {key:?}"
784 )),
785 }
786}
787
788fn json_identifier_alias(value: &Value, key: &str, alias: &str) -> Result<String, String> {
789 json_identifier(value, key).or_else(|_| json_identifier(value, alias))
790}
791
792fn json_f64(value: &Value, key: &str) -> Result<f64, String> {
793 value
794 .get(key)
795 .and_then(Value::as_f64)
796 .ok_or_else(|| format!("JSON record is missing numeric field {key:?}"))
797}
798
799fn validate_qualification_validation(
800 value: &Value,
801 artifact: &str,
802 row_number: usize,
803) -> Result<Option<String>, String> {
804 let invalid = |reason: &str| format!("{artifact} validation row {row_number} {reason}");
805 if value.get("exact_scalar_equivalence").is_some() {
806 for key in [
807 "public_boundary",
808 "exact_scalar_equivalence",
809 "error_semantics_verified",
810 "mismatched_length_error_equal_to_scalar",
811 "non_finite_error_equal_to_scalar",
812 ] {
813 if !json_bool(value, key)? {
814 return Err(invalid(&format!("has {key}=false")));
815 }
816 }
817 let backend = json_nonempty_string(value, "backend")?;
818 let observed_backend = json_string(value, "observed_backend")?;
819 if backend != observed_backend {
820 return Err(invalid("did not observe its requested backend"));
821 }
822 for key in ["precision", "mode"] {
823 if json_string(value, key)?.is_empty() {
824 return Err(invalid(&format!("has empty {key}")));
825 }
826 }
827 return Ok(Some(backend));
828 } else if value.get("errors_match_scalar").is_some() {
829 for key in [
830 "public_boundary",
831 "unequal_lengths_verified",
832 "non_finite_verified",
833 "short_output_verified",
834 "errors_match_scalar",
835 ] {
836 if !json_bool(value, key)? {
837 return Err(invalid(&format!("has {key}=false")));
838 }
839 }
840 let backend = json_nonempty_string(value, "backend")?;
841 for key in [
842 "unequal_lengths_error",
843 "non_finite_error",
844 "short_output_error",
845 ] {
846 if json_string(value, key)?.is_empty() {
847 return Err(invalid(&format!("has empty {key}")));
848 }
849 }
850 return Ok(Some(backend));
851 } else {
852 for key in ["unequal_lengths_verified", "non_finite_verified"] {
853 if !json_bool(value, key)? {
854 return Err(invalid(&format!("has {key}=false")));
855 }
856 }
857 for key in [
858 "scalar_unequal_lengths_error",
859 "scalar_non_finite_error",
860 "simd_unequal_lengths_error",
861 "simd_non_finite_error",
862 ] {
863 if json_string(value, key)?.is_empty() {
864 return Err(invalid(&format!("has empty {key}")));
865 }
866 }
867 }
868 Ok(None)
869}
870
871fn json_bool(value: &Value, key: &str) -> Result<bool, String> {
872 value
873 .get(key)
874 .and_then(Value::as_bool)
875 .ok_or_else(|| format!("JSON record is missing boolean field {key:?}"))
876}
877
878pub fn render_report(rows: &[BenchmarkRow]) -> Result<String, String> {
879 if rows.is_empty() {
880 return Err(
881 "cannot render an Indicator Catalogue matrix report without raw rows".to_owned(),
882 );
883 }
884 let first = &rows[0];
885 let mut report =
886 String::from("Pinned representative Indicator Catalogue performance matrix\n\n");
887 report.push_str(&format!(
888 "TA-Lib {} ({}) | Python {} binding {} / core {} | NumPy {} | float {}-bit\n",
889 first.ta_lib_version,
890 first.ta_lib_revision,
891 first.python_version,
892 first.python_binding_version,
893 first.python_ta_lib_version,
894 first.numpy_version,
895 first.float_width
896 ));
897 report.push_str(&format!(
898 "Commit {} (dirty: {}) | {} | {} {} | {}\n",
899 first.commit, first.dirty, first.cpu, first.os, first.arch, first.rustc
900 ));
901 report.push_str(if first.dirty {
902 "Run classification: diagnostic only; a dirty run cannot replace the canonical baseline.\n"
903 } else {
904 "Run classification: clean reference run; completeness and publication status follow.\n"
905 });
906 report.push_str("95% intervals are deterministic bootstrap confidence intervals for the median (10,000 resamples). Outliers use Tukey's 1.5 IQR fences. Rust/C ratios below use only same-run caller-owned rows with identical case, parameters, fixture, and input length.\n\n");
907 let coverage = measurement_coverage()?;
908 report.push_str(&format!(
909 "Executable measurement coverage: {}/{} implemented Indicator Definitions ({:.1}%); {} implemented definitions are not measured by this representative matrix.\n\n",
910 coverage.measured_count,
911 coverage.implemented_count,
912 coverage.measured_percent(),
913 coverage.unmeasured_count
914 ));
915 report.push_str("| Family | Measured | Implemented |\n|---|---:|---:|\n");
916 for (family, measured, implemented) in coverage.measured_by_family() {
917 report.push_str(&format!("| {family} | {measured} | {implemented} |\n"));
918 }
919 report.push('\n');
920
921 report.push_str("Representative matrix\n\n| Family | Definition | Parameters | Output |\n|---|---|---|---|\n");
922 let mut matrix = BTreeSet::new();
923 for row in rows {
924 matrix.insert((
925 row.indicator_family.clone(),
926 row.case_id.clone(),
927 row.parameters.clone(),
928 format!(
929 "{} x{}",
930 row.output_kind,
931 row.output_arity
932 .map_or_else(|| "NA".to_owned(), |value| value.to_string())
933 ),
934 ));
935 }
936 for (family, case_id, parameters, output) in matrix {
937 report.push_str(&format!(
938 "| {family} | {case_id} | {parameters} | {output} |\n"
939 ));
940 }
941
942 let case_ids = rows
943 .iter()
944 .map(|row| row.case_id.as_str())
945 .collect::<BTreeSet<_>>();
946 report.push_str("\nPattern Recognition execution-shape coverage\n\n| Definition | Execution shape | Rationale |\n|---|---|---|\n");
947 for shape in PATTERN_SHAPES {
948 if case_ids.contains(shape.case_id) {
949 report.push_str(&format!(
950 "| {} | {} | {} |\n",
951 shape.case_id, shape.execution_shape, shape.rationale
952 ));
953 }
954 }
955
956 let pairs = primary_pairs(rows);
957 report.push_str("\nSame-run geometric Rust/C caller-owned summary\n\n| Input | Mode | Comparable cases | Geometric Rust/C latency ratio | Semantics |\n|---:|---|---:|---:|---|\n");
958 for input_length in INPUT_LENGTHS {
959 let ratios = pairs
960 .iter()
961 .filter(|pair| pair.input_length == input_length)
962 .map(|pair| pair.ratio)
963 .collect::<Vec<_>>();
964 if ratios.is_empty() {
965 report.push_str(&format!("| {input_length} | {RUST_CALLER_MODE} vs {C_DIRECT_MODE} | 0 | unavailable | no comparable measured pairs |\n"));
966 } else {
967 let geometric =
968 (ratios.iter().map(|ratio| ratio.ln()).sum::<f64>() / ratios.len() as f64).exp();
969 report.push_str(&format!("| {input_length} | {RUST_CALLER_MODE} vs {C_DIRECT_MODE} | {} | {geometric:.3}x | comparable only |\n", ratios.len()));
970 }
971 }
972
973 report.push_str("\nLarge-throughput optimization ordering\n\n| Rank | Definition | Rust/C latency ratio | Disposition |\n|---:|---|---:|---|\n");
974 let mut large = pairs
975 .into_iter()
976 .filter(|pair| pair.input_length == 65_536)
977 .collect::<Vec<_>>();
978 large.sort_by(|left, right| {
979 right
980 .ratio
981 .partial_cmp(&left.ratio)
982 .unwrap_or(Ordering::Equal)
983 .then_with(|| left.case_id.cmp(&right.case_id))
984 });
985 if large.is_empty() {
986 report.push_str("| - | - | unavailable | no comparable measured pairs |\n");
987 } else {
988 for (index, pair) in large.iter().enumerate() {
989 let disposition = if pair.ratio > 1.05 {
990 "remaining comparative gap above 5%"
991 } else if pair.ratio < 0.95 {
992 "fast-ta faster"
993 } else {
994 "parity band"
995 };
996 report.push_str(&format!(
997 "| {} | {} | {:.3}x | {disposition} |\n",
998 index + 1,
999 pair.case_id,
1000 pair.ratio
1001 ));
1002 }
1003 }
1004
1005 report.push_str("\nDetailed raw-row projection\n\n| Definition | Input | Implementation | Mode | Semantic | Comparison | Median | 95% CI | Throughput | Output Range |\n|---|---:|---|---|---|---|---:|---:|---:|---:|\n");
1006 let mut ordered = rows.to_vec();
1007 ordered.sort_by(|left, right| {
1008 left.case_id
1009 .cmp(&right.case_id)
1010 .then_with(|| left.input_length.cmp(&right.input_length))
1011 .then_with(|| left.implementation.cmp(&right.implementation))
1012 .then_with(|| left.mode.cmp(&right.mode))
1013 });
1014 for row in &ordered {
1015 let (median, ci, throughput) = if let Some(stats) = &row.stats {
1016 (
1017 format!("{:.3} us", stats.median_ns / 1_000.0),
1018 format!(
1019 "[{:.3}, {:.3}] us",
1020 stats.ci95_lower_ns / 1_000.0,
1021 stats.ci95_upper_ns / 1_000.0
1022 ),
1023 format!(
1024 "{:.3} Mobs/s",
1025 stats.throughput_observations_per_second / 1.0e6
1026 ),
1027 )
1028 } else {
1029 (
1030 "unavailable".to_owned(),
1031 clean(&row.timing_reason),
1032 "unavailable".to_owned(),
1033 )
1034 };
1035 let range = match (row.output_begin, row.output_count) {
1036 (Some(begin), Some(count)) => format!("{begin}..{}", begin + count),
1037 _ => "unavailable".to_owned(),
1038 };
1039 let semantic = if row.semantic_reason.is_empty() {
1040 row.semantic_status.clone()
1041 } else {
1042 format!("{}: {}", row.semantic_status, clean(&row.semantic_reason))
1043 };
1044 let comparison = if row.comparison_reason.is_empty() {
1045 row.comparison_status.clone()
1046 } else {
1047 format!(
1048 "{}: {}",
1049 row.comparison_status,
1050 clean(&row.comparison_reason)
1051 )
1052 };
1053 report.push_str(&format!(
1054 "| {} | {} | {} | {} | {} | {} | {} | {} | {} | {} |\n",
1055 row.case_id,
1056 row.input_length,
1057 row.implementation,
1058 row.mode,
1059 semantic,
1060 comparison,
1061 median,
1062 ci,
1063 throughput,
1064 range
1065 ));
1066 }
1067
1068 report.push_str("\nSuppressed or unavailable results\n\n");
1069 let failures = ordered
1070 .iter()
1071 .filter(|row| row.semantic_status != "verified" || row.timing_status != "measured")
1072 .collect::<Vec<_>>();
1073 if failures.is_empty() {
1074 report.push_str("None. Every matrix row passed semantic verification before timing.\n");
1075 } else {
1076 for row in failures {
1077 report.push_str(&format!(
1078 "- {}/{}/{}: semantic={} ({}) timing={} ({})\n",
1079 row.case_id,
1080 row.input_length,
1081 row.mode,
1082 row.semantic_status,
1083 clean(&row.semantic_reason),
1084 row.timing_status,
1085 clean(&row.timing_reason)
1086 ));
1087 }
1088 }
1089 Ok(report)
1090}
1091
1092pub fn render_validated_report_with_comparison(
1094 evidence: &ValidatedCatalogueEvidence,
1095 baseline: &ValidatedCatalogueEvidence,
1096 diagnostic_evidence: &DiagnosticEvidence,
1097 criterion_diagnostics: &CriterionDiagnostics,
1098 cycle_regression: &CycleRegressionEvidence,
1099 platform_qualifications: &[PlatformQualification],
1100) -> Result<String, String> {
1101 render_report_with_comparison(
1102 evidence.rows(),
1103 baseline.rows(),
1104 diagnostic_evidence,
1105 criterion_diagnostics,
1106 cycle_regression,
1107 platform_qualifications,
1108 )
1109}
1110
1111fn render_report_with_comparison(
1112 rows: &[BenchmarkRow],
1113 baseline_rows: &[BenchmarkRow],
1114 diagnostic_evidence: &DiagnosticEvidence,
1115 criterion_diagnostics: &CriterionDiagnostics,
1116 cycle_regression: &CycleRegressionEvidence,
1117 platform_qualifications: &[PlatformQualification],
1118) -> Result<String, String> {
1119 if baseline_rows.is_empty() {
1120 return Err("clean pre-optimization baseline rows are required".to_owned());
1121 }
1122 if baseline_rows.iter().any(|row| row.dirty) {
1123 return Err("the canonical pre-optimization baseline must be clean".to_owned());
1124 }
1125 if criterion_diagnostics.pre_commit != diagnostic_evidence.baseline_commit
1126 || criterion_diagnostics.final_commit != diagnostic_evidence.final_commit
1127 {
1128 return Err("diagnostic and Criterion revision provenance do not match".to_owned());
1129 }
1130 let platform_set = platform_qualifications
1131 .iter()
1132 .map(|qualification| {
1133 (
1134 qualification.platform.as_str(),
1135 qualification.precision.as_str(),
1136 )
1137 })
1138 .collect::<BTreeSet<_>>();
1139 let required_platforms = [
1140 ("x86_64", "f64"),
1141 ("x86_64", "f32"),
1142 ("aarch64", "f64"),
1143 ("aarch64", "f32"),
1144 ("wasm32-unknown-unknown", "f64"),
1145 ]
1146 .into_iter()
1147 .collect::<BTreeSet<_>>();
1148 if platform_qualifications.len() != 5 || platform_set != required_platforms {
1149 return Err(
1150 "exactly x86 f64/f32, AArch64 f64/f32, and WASM f64 qualifications are required"
1151 .to_owned(),
1152 );
1153 }
1154 let report = render_report(rows)?;
1155 let marker = "\nDetailed raw-row projection\n";
1156 let (summary, details) = report
1157 .split_once(marker)
1158 .ok_or_else(|| "generated report is missing the detailed-row marker".to_owned())?;
1159 let first = rows
1160 .first()
1161 .ok_or_else(|| "cannot render a comparison report without raw rows".to_owned())?;
1162 let baseline_first = baseline_rows
1163 .first()
1164 .ok_or_else(|| "clean pre-optimization baseline rows are required".to_owned())?;
1165 let mut comparison = String::new();
1166
1167 let verified = rows
1168 .iter()
1169 .filter(|row| row.semantic_status == "verified")
1170 .count();
1171 let measured = rows
1172 .iter()
1173 .filter(|row| row.timing_status == "measured")
1174 .count();
1175 let sample_counts = rows
1176 .iter()
1177 .filter_map(|row| row.stats.as_ref().map(|stats| stats.sample_count))
1178 .collect::<BTreeSet<_>>();
1179 let clean_run = rows.iter().all(|row| !row.dirty);
1180 comparison.push_str(
1181 "\nRun completeness and semantic gate\n\n| Raw rows | Semantic verified | Measured | Sample counts | Provenance |\n|---:|---:|---:|---|---|\n",
1182 );
1183 comparison.push_str(&format!(
1184 "| {} | {verified} | {measured} | {} | {} |\n",
1185 rows.len(),
1186 sample_counts
1187 .iter()
1188 .map(usize::to_string)
1189 .collect::<Vec<_>>()
1190 .join(", "),
1191 if clean_run {
1192 "clean canonical final run"
1193 } else {
1194 "dirty diagnostic run"
1195 }
1196 ));
1197 comparison.push_str(&format!(
1198 "\nCanonical comparison baseline\n\nThe committed clean pre-optimization matrix is the sole comparison baseline: commit {} (dirty: {}), {} rows, {} on {} {}. The historical post-scalar dirty diagnostic is not an input to this report.\n",
1199 baseline_first.commit,
1200 baseline_first.dirty,
1201 baseline_rows.len(),
1202 clean(&baseline_first.cpu),
1203 clean(&baseline_first.os),
1204 clean(&baseline_first.arch)
1205 ));
1206
1207 let current_pairs = primary_pairs(rows);
1208 let current_by_case = current_pairs
1209 .iter()
1210 .cloned()
1211 .map(|pair| ((pair.case_id.clone(), pair.input_length), pair))
1212 .collect::<BTreeMap<_, _>>();
1213
1214 comparison.push_str(
1215 "\nPer-case caller-owned Rust/C latency ratios\n\n| Definition | 256 | 4,096 | 65,536 | 65,536 disposition |\n|---|---:|---:|---:|---|\n",
1216 );
1217 let case_ids = current_pairs
1218 .iter()
1219 .map(|pair| pair.case_id.clone())
1220 .collect::<BTreeSet<_>>();
1221 for case_id in case_ids {
1222 let ratios = INPUT_LENGTHS.map(|input_length| {
1223 current_by_case
1224 .get(&(case_id.clone(), input_length))
1225 .map(|pair| pair.ratio)
1226 });
1227 let large_disposition = match ratios[2] {
1228 Some(ratio) if ratio > 1.05 => "remaining gap above the 5% band",
1229 Some(ratio) if ratio < 0.95 => "fast-ta faster",
1230 Some(_) => "parity band",
1231 None => "unavailable",
1232 };
1233 comparison.push_str(&format!(
1234 "| {case_id} | {} | {} | {} | {large_disposition} |\n",
1235 format_ratio(ratios[0]),
1236 format_ratio(ratios[1]),
1237 format_ratio(ratios[2])
1238 ));
1239 }
1240
1241 comparison.push_str(
1242 "\nExecution-path cost summaries\n\nRatios are geometric path/C latency indices over matching cases. Only the caller-owned Rust/C row is a kernel comparison; the other rows expose distinct public or user-facing costs.\n\n| Input | Path | Cases | Geometric path/C ratio | Interpretation |\n|---:|---|---:|---:|---|\n",
1243 );
1244 let paths = [
1245 (
1246 "fast-ta",
1247 RUST_OWNED_MODE,
1248 "Owned Compact Output",
1249 "API-owned compact allocation included",
1250 ),
1251 (
1252 "fast-ta",
1253 RUST_CALLER_MODE,
1254 "caller-owned Rust/C kernel",
1255 "primary comparable kernel seam",
1256 ),
1257 (
1258 "fast-ta",
1259 RUST_PREPARED_MODE,
1260 "Prepared reuse",
1261 "preparation and caller output allocation excluded",
1262 ),
1263 (
1264 "fast-ta",
1265 RUST_STREAMING_MODE,
1266 "Streaming reset plus ticks",
1267 "separate stateful execution cost",
1268 ),
1269 (
1270 "TA-Lib Python",
1271 PYTHON_MODE,
1272 "official Python NumPy API",
1273 "user-facing API-owned output cost",
1274 ),
1275 ];
1276 for input_length in INPUT_LENGTHS {
1277 for (implementation, mode, label, interpretation) in paths {
1278 let ratios = path_ratios(rows, implementation, mode, input_length);
1279 if ratios.is_empty() {
1280 comparison.push_str(&format!(
1281 "| {input_length} | {label} | 0 | unavailable | {interpretation} |\n"
1282 ));
1283 } else {
1284 comparison.push_str(&format!(
1285 "| {input_length} | {label} | {} | {:.3}x | {interpretation} |\n",
1286 ratios.len(),
1287 geometric_mean(&ratios)
1288 ));
1289 }
1290 }
1291 }
1292
1293 comparison.push_str(&format!(
1294 "\nDurable issue 57–62 diagnostic evidence\n\nGenerated only from the diagnostic and Criterion JSON artifacts. The retired optimization-evidence TSV is not a numeric or narrative source. Capture: {}. Baseline revision: `{}`. Final diagnostic revision: `{}`.\n\nDiagnostic environment: {}.\n\nExact top-level reproduction commands\n\n| Purpose | Command |\n|---|---|\n",
1295 clean(&diagnostic_evidence.captured_at_utc),
1296 diagnostic_evidence.baseline_commit,
1297 diagnostic_evidence.final_commit,
1298 diagnostic_evidence
1299 .environment
1300 .iter()
1301 .map(|(key, value)| format!("{key}={}", clean(value)))
1302 .collect::<Vec<_>>()
1303 .join("; ")
1304 ));
1305 for (purpose, command) in &diagnostic_evidence.commands {
1306 comparison.push_str(&format!("| {} | `{}` |\n", clean(purpose), clean(command)));
1307 }
1308 for ticket in &diagnostic_evidence.tickets {
1309 let profile = &ticket.profile_or_compiler_evidence;
1310 comparison.push_str(&format!(
1311 "\nIssue {} diagnostic record\n\nPre-change sampled/compiler artifact: `{}` (`sha256:{}`). Benchmark ID: `{}`. Working directory: `{}`.\n\n- Benchmark command: `{}`\n- Capture command: `{}`\n",
1312 ticket.ticket,
1313 clean(&json_nonempty_string(profile, "artifact")?),
1314 clean(&json_nonempty_string(profile, "artifact_sha256")?),
1315 clean(&json_nonempty_string(profile, "benchmark_id")?),
1316 clean(&json_nonempty_string(profile, "cwd")?),
1317 clean(&json_nonempty_string(profile, "benchmark_command")?),
1318 clean(&json_nonempty_string(profile, "profile_command")?)
1319 ));
1320 if let Ok(hot_leaves) = json_array(profile, "ranked_hot_leaves") {
1321 comparison.push_str(
1322 "\nPre-change sampled hot leaves\n\n| Rank | Symbol | Samples |\n|---:|---|---:|\n",
1323 );
1324 for (index, leaf) in hot_leaves.iter().enumerate() {
1325 comparison.push_str(&format!(
1326 "| {} | {} | {} |\n",
1327 index + 1,
1328 clean(&json_nonempty_string(leaf, "symbol")?),
1329 json_u64(leaf, "samples")?
1330 ));
1331 }
1332 }
1333 if let Some(compiler) = profile.get("compiler_evidence") {
1334 comparison.push_str(&format!(
1335 "\nCompiler/objdump evidence: `{}` (`sha256:{}`). Command: `{}`. Finding: {}. Instruction count: {}; packed f64 add/divide: {}/{}; scalar validation load sites: {}.\n",
1336 clean(&json_nonempty_string(compiler, "artifact")?),
1337 clean(&json_nonempty_string(compiler, "artifact_sha256")?),
1338 clean(&json_nonempty_string(compiler, "command")?),
1339 clean(&json_nonempty_string(compiler, "finding")?),
1340 json_u64(compiler, "instruction_count")?,
1341 json_u64(compiler, "packed_f64_add_instructions")?,
1342 json_u64(compiler, "packed_f64_divide_instructions")?,
1343 json_u64(compiler, "scalar_validation_load_sites")?
1344 ));
1345 }
1346 comparison.push_str(
1347 "\nRanked falsifiable hypotheses\n\n| Rank | Hypothesis | Prediction | Status | Evidence |\n|---:|---|---|---|---|\n",
1348 );
1349 for hypothesis in &ticket.ranked_hypotheses {
1350 comparison.push_str(&format!(
1351 "| {} | {} | {} | {} | {} |\n",
1352 json_u64(hypothesis, "rank")?,
1353 clean(&json_nonempty_string(hypothesis, "hypothesis")?),
1354 clean(&json_nonempty_string(hypothesis, "prediction")?),
1355 clean(&json_nonempty_string(hypothesis, "status")?),
1356 clean(&json_nonempty_string(hypothesis, "evidence")?)
1357 ));
1358 }
1359 comparison.push_str(
1360 "\nRequired target and neighboring-workload dispositions\n\n| Workload | Disposition |\n|---|---|\n",
1361 );
1362 for neighbor in &ticket.required_neighbor_coverage {
1363 comparison.push_str(&format!(
1364 "| {} | {} |\n",
1365 clean(&json_nonempty_string(neighbor, "workload")?),
1366 clean(&json_nonempty_string(neighbor, "status")?)
1367 ));
1368 }
1369 }
1370
1371 comparison.push_str(&format!(
1372 "\nCriterion same-session before/after diagnostics\n\nAll values are parsed from the durable Criterion JSON. Environment: {}.\n\n| Ticket | Workload / role | Exact command and provenance | Pre median [95% CI] / throughput | Final median [95% CI] / throughput | Change | Disposition |\n|---:|---|---|---:|---:|---:|---|\n",
1373 criterion_diagnostics
1374 .environment
1375 .iter()
1376 .map(|(key, value)| format!("{key}={}", clean(value)))
1377 .collect::<Vec<_>>()
1378 .join("; ")
1379 ));
1380 let criterion_keys = criterion_diagnostics
1381 .measurements
1382 .iter()
1383 .map(|measurement| (measurement.ticket, measurement.case_id.as_str()))
1384 .collect::<BTreeSet<_>>();
1385 for (ticket_number, case_id) in criterion_keys {
1386 let pre = criterion_diagnostics
1387 .measurements
1388 .iter()
1389 .find(|measurement| {
1390 measurement.ticket == ticket_number
1391 && measurement.case_id == case_id
1392 && measurement.revision == "pre"
1393 })
1394 .expect("validated pre Criterion pair");
1395 let final_measurement = criterion_diagnostics
1396 .measurements
1397 .iter()
1398 .find(|measurement| {
1399 measurement.ticket == ticket_number
1400 && measurement.case_id == case_id
1401 && measurement.revision == "final"
1402 })
1403 .expect("validated final Criterion pair");
1404 let disposition = diagnostic_evidence
1405 .tickets
1406 .iter()
1407 .find(|ticket| ticket.ticket == ticket_number)
1408 .and_then(|ticket| {
1409 ticket
1410 .criterion_comparisons
1411 .iter()
1412 .find(|value| value.get("case_id").and_then(Value::as_str) == Some(case_id))
1413 })
1414 .and_then(|value| value.get("disposition"))
1415 .and_then(Value::as_str)
1416 .ok_or_else(|| {
1417 format!("issue {ticket_number} {case_id} has no diagnostic disposition")
1418 })?;
1419 let change = (final_measurement.median_ns / pre.median_ns - 1.0) * 100.0;
1420 comparison.push_str(&format!(
1421 "| {ticket_number} | {} / {} | `{}`<br>cwd `{}`<br>benchmark `{}`<br>{} samples; {} | {:.3} us [{:.3}, {:.3}] / {:.3} Mobs/s | {:.3} us [{:.3}, {:.3}] / {:.3} Mobs/s | {change:+.1}% | {} |\n",
1422 clean(case_id),
1423 clean(&pre.role),
1424 clean(&pre.command),
1425 clean(&pre.cwd),
1426 clean(&pre.benchmark_id),
1427 pre.sample_count,
1428 clean(&pre.timed_boundary),
1429 pre.median_ns / 1_000.0,
1430 pre.ci95_lower_ns / 1_000.0,
1431 pre.ci95_upper_ns / 1_000.0,
1432 pre.throughput_observations_per_second / 1.0e6,
1433 final_measurement.median_ns / 1_000.0,
1434 final_measurement.ci95_lower_ns / 1_000.0,
1435 final_measurement.ci95_upper_ns / 1_000.0,
1436 final_measurement.throughput_observations_per_second / 1.0e6,
1437 clean(disposition)
1438 ));
1439 }
1440
1441 comparison.push_str(
1442 "\nSame-run semantic Rust/C pairs\n\nThese values and checksums are parsed from the semantic pair records embedded in the durable diagnostic JSON.\n\n| Ticket | Definition | Input | Revision | fast-ta median [95% CI] / throughput | TA-Lib C median [95% CI] / throughput | Rust/C | Checksums / disposition |\n|---:|---|---:|---|---:|---:|---:|---|\n",
1443 );
1444 for ticket in &diagnostic_evidence.tickets {
1445 for semantic in &ticket.semantic_comparisons {
1446 for revision in ["pre", "final"] {
1447 let rust = json_object(semantic, &format!("{revision}_fast_ta"))?;
1448 let c = json_object(semantic, &format!("{revision}_ta_lib_c"))?;
1449 let ratio = json_numeric(semantic, &format!("{revision}_rust_over_c"))?;
1450 comparison.push_str(&format!(
1451 "| {} | {} | {} | {revision} | {} | {} | {:.3}x | input_match={}; output_match={}; {} |\n",
1452 ticket.ticket,
1453 clean(&json_nonempty_string(semantic, "case_id")?),
1454 json_u64(semantic, "input_length")?,
1455 format_json_timing(rust)?,
1456 format_json_timing(c)?,
1457 ratio,
1458 json_bool(semantic, "input_checksum_match")?,
1459 json_bool(semantic, "output_checksum_match")?,
1460 clean(&json_nonempty_string(semantic, "disposition")?)
1461 ));
1462 }
1463 }
1464 }
1465
1466 comparison.push_str(&format!(
1467 "\nIssue 61 Hilbert cycle regression control\n\nCommand: `{}`. Working directory: `{}`. Host: {} / {} / {}. Timed seam: {}.\n\n| Indicator | Input | Cursor pre median [95% CI] / throughput | Final clean-revert median [95% CI] / throughput | Cursor vs baseline | Final vs baseline | Source proof and disposition |\n|---|---:|---:|---:|---:|---:|---|\n",
1468 clean(&cycle_regression.command),
1469 clean(&cycle_regression.cwd),
1470 clean(&cycle_regression.cpu),
1471 clean(&cycle_regression.os),
1472 clean(&cycle_regression.arch),
1473 clean(&cycle_regression.seam)
1474 ));
1475 for cycle_comparison in &cycle_regression.comparisons {
1476 let before = cycle_regression
1477 .measurements
1478 .iter()
1479 .find(|measurement| {
1480 measurement.indicator == cycle_comparison.indicator
1481 && measurement.input_length == cycle_comparison.input_length
1482 && measurement.variant == cycle_comparison.before_variant
1483 })
1484 .expect("validated cycle pre measurement");
1485 let after = cycle_regression
1486 .measurements
1487 .iter()
1488 .find(|measurement| {
1489 measurement.indicator == cycle_comparison.indicator
1490 && measurement.input_length == cycle_comparison.input_length
1491 && measurement.variant == "b156ac1_modulo"
1492 })
1493 .expect("validated cycle final measurement");
1494 comparison.push_str(&format!(
1495 "| {} | {} | {} | {} | {:+.1}% | {:+.1}% | {} — {} |\n",
1496 clean(&cycle_comparison.indicator),
1497 cycle_comparison.input_length,
1498 format_cycle_timing(before),
1499 format_cycle_timing(after),
1500 cycle_comparison.cursor_vs_baseline_percent,
1501 cycle_comparison.after_vs_baseline_percent,
1502 clean(&cycle_comparison.source_proof),
1503 clean(&cycle_comparison.disposition)
1504 ));
1505 }
1506
1507 let baseline_by_row = baseline_rows
1508 .iter()
1509 .map(|row| (comparison_row_key(row), row))
1510 .collect::<BTreeMap<_, _>>();
1511 let mut changes = rows
1512 .iter()
1513 .filter_map(|current| {
1514 let baseline = baseline_by_row.get(&comparison_row_key(current))?;
1515 let before = baseline.stats.as_ref()?;
1516 let after = current.stats.as_ref()?;
1517 let change = (after.median_ns / before.median_ns - 1.0) * 100.0;
1518 (change.abs() > 5.0).then_some((*baseline, current, change))
1519 })
1520 .collect::<Vec<_>>();
1521 changes.sort_by(|left, right| {
1522 left.1
1523 .case_id
1524 .cmp(&right.1.case_id)
1525 .then_with(|| left.1.input_length.cmp(&right.1.input_length))
1526 .then_with(|| left.1.implementation.cmp(&right.1.implementation))
1527 .then_with(|| left.1.mode.cmp(&right.1.mode))
1528 });
1529 comparison.push_str(&format!(
1530 "\nComplete >5% clean pre/final classification\n\n{} matching raw rows changed by more than 5%. This list is exhaustive for measured rows shared by the two committed clean artifacts. An investigation classification is not a same-run causal claim; the matrices were separate clean runs, and external C/Python movement is retained as a control.\n\n| Definition | Input | Implementation | Mode | Pre median | Final median | Change | Classification |\n|---|---:|---|---|---:|---:|---:|---|\n",
1531 changes.len()
1532 ));
1533 for (baseline, current, change) in changes {
1534 let before = baseline.stats.as_ref().expect("change row has stats");
1535 let after = current.stats.as_ref().expect("change row has stats");
1536 comparison.push_str(&format!(
1537 "| {} | {} | {} | {} | {:.3} us | {:.3} us | {change:+.1}% | {} |\n",
1538 current.case_id,
1539 current.input_length,
1540 current.implementation,
1541 current.mode,
1542 before.median_ns / 1_000.0,
1543 after.median_ns / 1_000.0,
1544 clean_change_classification(current, change)
1545 ));
1546 }
1547
1548 comparison.push_str(
1549 "\nRuntime platform qualification from committed JSONL\n\nThese rows are parsed from the named JSONL artifacts only after their validation records and numeric timing evidence pass schema checks. Speedup is scalar median divided by the matching backend median only when mode, precision, input size, and timed boundary match. A value below 1x means the accelerated backend was slower on this runner. Rows without a scalar measurement at the same boundary are not compared.\n\n| Artifact | Platform | Precision | Profile / features | Runtime / CPU / OS | Active backend | Equivalence | Workflow provenance | Commit |\n|---|---|---|---|---|---|---|---|---|\n",
1550 );
1551 for qualification in platform_qualifications {
1552 let equivalent = qualification.measurements.iter().all(|measurement| {
1553 measurement.equivalent_to_scalar
1554 && measurement.semantic_status == "verified"
1555 && measurement.timing_status == "measured"
1556 });
1557 comparison.push_str(&format!(
1558 "| {} | {} | {} | {} / {} | {} / {} / {} | {} | {} | run [{}]({}), job {} | {} |\n",
1559 clean(&qualification.artifact),
1560 clean(&qualification.platform),
1561 clean(&qualification.precision),
1562 clean(&qualification.profile),
1563 clean(&qualification.feature_flags),
1564 clean(&qualification.runtime),
1565 clean(&qualification.cpu),
1566 clean(&qualification.os),
1567 clean(&qualification.active_backend),
1568 if equivalent {
1569 "all measurement and validation rows verified"
1570 } else {
1571 "qualification contains an unverified row"
1572 },
1573 qualification.workflow_run_id,
1574 clean(&qualification.workflow_run_url),
1575 qualification.workflow_job,
1576 qualification.commit
1577 ));
1578 }
1579 comparison.push_str(
1580 "\n| Platform | Precision | Input | Mode | Backend | Median [95% CI] | Throughput | Speedup vs matching scalar | Disposition |\n|---|---|---:|---|---|---:|---:|---:|---|\n",
1581 );
1582 for qualification in platform_qualifications {
1583 let mut measurements = qualification.measurements.iter().collect::<Vec<_>>();
1584 measurements.sort_by(|left, right| {
1585 left.input_length
1586 .cmp(&right.input_length)
1587 .then_with(|| left.mode.cmp(&right.mode))
1588 .then_with(|| left.backend.cmp(&right.backend))
1589 });
1590 for measurement in measurements {
1591 let scalar = qualification.measurements.iter().find(|candidate| {
1592 candidate.mode == measurement.mode
1593 && candidate.input_length == measurement.input_length
1594 && candidate.backend == "scalar"
1595 && candidate.timed_boundary == measurement.timed_boundary
1596 });
1597 let speedup = scalar.map(|scalar| scalar.median_ns / measurement.median_ns);
1598 let disposition = qualification_disposition(measurement, speedup);
1599 comparison.push_str(&format!(
1600 "| {} | {} | {} | {} | {} | {:.3} us [{:.3}, {:.3}] | {:.3} Mobs/s | {} | {disposition} |\n",
1601 clean(&qualification.platform),
1602 clean(&qualification.precision),
1603 measurement.input_length,
1604 clean(&measurement.mode),
1605 clean(&measurement.backend),
1606 measurement.median_ns / 1_000.0,
1607 measurement.ci95_lower_ns / 1_000.0,
1608 measurement.ci95_upper_ns / 1_000.0,
1609 measurement.throughput_observations_per_second / 1.0e6,
1610 format_ratio(speedup)
1611 ));
1612 }
1613 }
1614
1615 comparison.push_str(
1616 "\nValidation and allocation boundaries\n\nThe Rust matrix timings retain public finite-input validation, capacity, Output Range, and validation-before-mutation contracts. Validation and computation were not timed separately in the catalogue matrix; the direct C row is a comparative kernel reference, not evidence that Rust validation should be removed.\n\n| Implementation | Mode | Timed allocation/boundary evidence from raw rows |\n|---|---|---|\n",
1617 );
1618 let boundaries = rows
1619 .iter()
1620 .map(|row| {
1621 (
1622 row.implementation.clone(),
1623 row.mode.clone(),
1624 row.timed_boundary.clone(),
1625 )
1626 })
1627 .collect::<BTreeSet<_>>();
1628 for (implementation, mode, boundary) in boundaries {
1629 comparison.push_str(&format!(
1630 "| {implementation} | {mode} | {} |\n",
1631 clean(&boundary)
1632 ));
1633 }
1634
1635 comparison.push_str(&format!(
1636 "\nFinal AArch64 qualification\n\nThe clean final matrix exercised the public TYPPRICE caller-owned path on {} / {} with architecture `{}` and commit {}. This is the only AArch64 timing claim; scalar fallback remains available. x86_64 and WASM claims above come only from their committed runtime JSONL artifacts.\n",
1637 clean(&first.cpu),
1638 clean(&first.os),
1639 clean(&first.arch),
1640 first.commit
1641 ));
1642
1643 Ok(format!("{summary}{comparison}{marker}{details}"))
1644}
1645
1646fn json_numeric(value: &Value, key: &str) -> Result<f64, String> {
1647 value
1648 .get(key)
1649 .and_then(|value| {
1650 value
1651 .as_f64()
1652 .or_else(|| value.as_str().and_then(|value| value.parse().ok()))
1653 })
1654 .filter(|value| value.is_finite())
1655 .ok_or_else(|| format!("JSON value is missing finite numeric field {key:?}"))
1656}
1657
1658fn format_json_timing(value: &Value) -> Result<String, String> {
1659 Ok(format!(
1660 "{:.3} us [{:.3}, {:.3}] / {:.3} Mobs/s",
1661 json_numeric(value, "median_ns")? / 1_000.0,
1662 json_numeric(value, "ci95_lower_ns")? / 1_000.0,
1663 json_numeric(value, "ci95_upper_ns")? / 1_000.0,
1664 json_numeric(value, "throughput_observations_per_second")? / 1.0e6
1665 ))
1666}
1667
1668fn format_cycle_timing(value: &CycleMeasurement) -> String {
1669 format!(
1670 "{:.3} us [{:.3}, {:.3}] / {:.3} Mobs/s",
1671 value.median_ns / 1_000.0,
1672 value.ci95_lower_ns / 1_000.0,
1673 value.ci95_upper_ns / 1_000.0,
1674 value.throughput_observations_per_second / 1.0e6
1675 )
1676}
1677
1678fn comparison_row_key(
1679 row: &BenchmarkRow,
1680) -> (String, String, String, String, usize, String, usize) {
1681 (
1682 row.implementation.clone(),
1683 row.case_id.clone(),
1684 row.mode.clone(),
1685 row.parameters.clone(),
1686 row.input_length,
1687 row.fixture.clone(),
1688 row.float_width,
1689 )
1690}
1691
1692fn clean_change_classification(row: &BenchmarkRow, change: f64) -> &'static str {
1693 if row.implementation != "fast-ta" {
1694 return "external C/Python reference-path movement between clean runs; retained as host/run control, not attributed to fast-ta source";
1695 }
1696 if row.mode == RUST_STREAMING_MODE {
1697 return "untouched Streaming neighbor; batch optimization does not explain this clean cross-run movement; no causal claim";
1698 }
1699 if row.case_id == "CDLDOJI" && change > 5.0 {
1700 return "investigated clean regression: batch-only, source-correlated with migration to the shared single-setting helper; unresolved";
1701 }
1702 if row.case_id == "HT_DCPHASE" && change > 5.0 {
1703 return "investigated clean large-input regression despite ring-wrap source change; unresolved";
1704 }
1705 if change < -5.0 {
1706 return "clean batch improvement; targeted kernel work or shared SIMD finite-slice validation applies";
1707 }
1708 "clean batch regression above 5%; classified as unresolved"
1709}
1710
1711fn qualification_disposition(
1712 measurement: &QualificationMeasurement,
1713 speedup: Option<f64>,
1714) -> &'static str {
1715 if !measurement.equivalent_to_scalar || measurement.semantic_status != "verified" {
1716 "invalid for performance comparison: equivalence not verified"
1717 } else if measurement.backend == "scalar" {
1718 "scalar reference"
1719 } else if let Some(speedup) = speedup {
1720 if speedup > 1.05 {
1721 "practical benefit on this runner"
1722 } else if speedup < 0.95 {
1723 "slower than scalar on this runner; no practical benefit"
1724 } else {
1725 "within the 5% band on this runner"
1726 }
1727 } else {
1728 "no matching scalar row with the same timed boundary"
1729 }
1730}
1731
1732fn format_ratio(ratio: Option<f64>) -> String {
1733 ratio.map_or_else(|| "unavailable".to_owned(), |ratio| format!("{ratio:.3}x"))
1734}
1735
1736fn geometric_mean(ratios: &[f64]) -> f64 {
1737 (ratios.iter().map(|ratio| ratio.ln()).sum::<f64>() / ratios.len() as f64).exp()
1738}
1739
1740fn path_ratios(
1741 rows: &[BenchmarkRow],
1742 implementation: &str,
1743 mode: &str,
1744 input_length: usize,
1745) -> Vec<f64> {
1746 type Key = (String, String, usize, String, String);
1747 let mut c = BTreeMap::<Key, f64>::new();
1748 for row in rows {
1749 if row.implementation != "TA-Lib C"
1750 || row.mode != C_DIRECT_MODE
1751 || row.input_length != input_length
1752 || row.semantic_status != "verified"
1753 || row.timing_status != "measured"
1754 {
1755 continue;
1756 }
1757 if let Some(stats) = &row.stats {
1758 c.insert(
1759 (
1760 row.case_id.clone(),
1761 row.parameters.clone(),
1762 row.input_length,
1763 row.fixture.clone(),
1764 row.input_checksum.clone(),
1765 ),
1766 stats.median_ns,
1767 );
1768 }
1769 }
1770 rows.iter()
1771 .filter(|row| {
1772 row.implementation == implementation
1773 && row.mode == mode
1774 && row.input_length == input_length
1775 && row.semantic_status == "verified"
1776 && row.timing_status == "measured"
1777 })
1778 .filter_map(|row| {
1779 let stats = row.stats.as_ref()?;
1780 let key = (
1781 row.case_id.clone(),
1782 row.parameters.clone(),
1783 row.input_length,
1784 row.fixture.clone(),
1785 row.input_checksum.clone(),
1786 );
1787 c.get(&key).map(|c_ns| stats.median_ns / c_ns)
1788 })
1789 .collect()
1790}
1791
1792#[derive(Clone, Debug)]
1793struct PrimaryPair {
1794 case_id: String,
1795 input_length: usize,
1796 ratio: f64,
1797}
1798
1799fn primary_pairs(rows: &[BenchmarkRow]) -> Vec<PrimaryPair> {
1800 type Key = (String, String, usize, String, String);
1801 let mut rust = BTreeMap::<Key, f64>::new();
1802 let mut c = BTreeMap::<Key, f64>::new();
1803 for row in rows {
1804 if row.semantic_status != "verified"
1805 || row.timing_status != "measured"
1806 || row.comparison_status != "comparable"
1807 {
1808 continue;
1809 }
1810 let Some(stats) = &row.stats else { continue };
1811 let key = (
1812 row.case_id.clone(),
1813 row.parameters.clone(),
1814 row.input_length,
1815 row.fixture.clone(),
1816 row.input_checksum.clone(),
1817 );
1818 if row.implementation == "fast-ta" && row.mode == RUST_CALLER_MODE {
1819 rust.insert(key, stats.median_ns);
1820 } else if row.implementation == "TA-Lib C" && row.mode == C_DIRECT_MODE {
1821 c.insert(key, stats.median_ns);
1822 }
1823 }
1824 rust.into_iter()
1825 .filter_map(|(key, rust_ns)| {
1826 c.get(&key).map(|c_ns| PrimaryPair {
1827 case_id: key.0,
1828 input_length: key.2,
1829 ratio: rust_ns / c_ns,
1830 })
1831 })
1832 .collect()
1833}