1use std::fmt::Write as _;
14
15use serde::Serialize;
16
17use super::model::{
18 EconomicsInterval, EconomicsMetric, EconomicsMetricStatus, EconomicsPairStatus,
19 EconomicsSummary,
20};
21use super::stats::{level_text, percent_text};
22use super::{wire, CONTEXT_REDUCTION};
23
24fn signed_count(v: f64) -> String {
27 if !v.is_finite() {
28 return "n/a".into();
29 }
30 let whole = v.round();
31 if whole == 0.0 {
32 "0".into()
33 } else {
34 format!("{whole:+.0}")
35 }
36}
37
38pub fn amount(v: f64, unit: &str) -> String {
57 if unit == "ratio" {
58 percent_text(v)
59 } else {
60 format!("{} {unit}", signed_count(v))
61 }
62}
63
64pub fn value(m: &EconomicsMetric) -> String {
80 match m.value {
81 None => "not measured".into(),
82 Some(v) => amount(v, &m.unit),
83 }
84}
85
86pub fn interval_text(i: &EconomicsInterval, unit: &str) -> String {
102 format!(
103 "{}: {} to {}",
104 level_text(i.level_bp),
105 amount(i.low, unit),
106 amount(i.high, unit)
107 )
108}
109
110pub fn words<T: Serialize>(value: &T) -> String {
123 wire(value).replace('_', " ")
124}
125
126fn cell(s: &str) -> String {
127 s.replace('|', "\\|").replace('\n', " ")
128}
129
130pub fn markdown(s: &EconomicsSummary) -> String {
149 let mut o = String::new();
150 let _ = writeln!(o, "# Token economics: benchmark report\n");
151 let _ = writeln!(o, "Generated from recorded evidence by `majordomus generate economics`. Every figure below is computed by one calculator (`apps/majordomus-cli/src/economics`) from the raw runs under `.ai/repo/benchmarks/economics/runs/`; nothing here is typed by hand.\n");
152 let _ = writeln!(o, "## Verdict\n");
153 let _ = writeln!(o, "{}\n", s.verdict.statement);
154 if !s.verdict.unmet.is_empty() {
155 let _ = writeln!(o, "The publication rule is not met:\n");
156 for u in &s.verdict.unmet {
157 let _ = writeln!(o, "- {u}");
158 }
159 let _ = writeln!(o);
160 }
161 if !s.diagnostics.is_empty() {
162 let _ = writeln!(o, "## Records that could not be read\n");
163 let _ = writeln!(o, "Nothing in them is counted anywhere below.\n");
164 for d in &s.diagnostics {
165 let _ = writeln!(o, "- {d}");
166 }
167 let _ = writeln!(o);
168 }
169 if !s.present {
170 return o;
171 }
172 let _ = writeln!(o, "## Question and methodology\n");
173 if let Some(q) = &s.question {
174 let _ = writeln!(o, "{q}\n");
175 }
176 let _ = writeln!(
177 o,
178 "Methodology version {}; primary metric `{}`. The methodology is `.ai/repo/benchmarks/economics/methodology.yaml`.\n",
179 s.methodology.unwrap_or(0),
180 s.primary_metric.clone().unwrap_or_default()
181 );
182 let _ = writeln!(o, "### Control and treatment\n");
183 for v in &s.variants {
184 let _ = writeln!(
185 o,
186 "- **{}** ({}, `{}`): {}",
187 v.title, v.role, v.id, v.description
188 );
189 if !v.excludes.is_empty() {
190 let _ = writeln!(o, " Excludes: {}.", v.excludes.join(", "));
191 }
192 }
193 let _ = writeln!(o);
194 if let Some(p) = &s.publication {
195 let _ = writeln!(o, "### When a total-token claim may be published\n");
196 let _ = writeln!(
197 o,
198 "At least {} valid matched pairs; at least {} task categories with {} valid pairs each; at least {} repetitions of every task and variant; at least {} in 10000 attempted pairs valid; a bootstrap interval no wider than {} in 10000; evidence {}; no run recorded from a working tree with uncommitted changes.\n",
199 p.min_valid_pairs,
200 p.min_categories,
201 p.min_pairs_per_category,
202 p.min_repetitions,
203 p.min_valid_pair_rate_bp,
204 p.max_interval_width_bp,
205 if p.require_current { "current" } else { "of any age" }
206 );
207 }
208 let _ = writeln!(o, "## Evidence\n");
209 let _ = writeln!(o, "| suite | kind | freshness | runs | valid pairs | attempted | control failed | treatment failed | both failed | other | revisions | harness | models |");
210 let _ = writeln!(o, "|---|---|---|---|---|---|---|---|---|---|---|---|---|");
211 for v in &s.suites {
212 let _ = writeln!(
213 o,
214 "| {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} |",
215 v.id,
216 v.kind,
217 words(&v.freshness),
218 v.runs,
219 v.pairs.valid,
220 v.pairs.attempted,
221 v.pairs.control_failed,
222 v.pairs.treatment_failed,
223 v.pairs.both_failed,
224 v.pairs.other,
225 v.revisions
226 .iter()
227 .map(|r| format!("`{}`", &r[..r.len().min(12)]))
228 .collect::<Vec<_>>()
229 .join(" "),
230 v.harnesses.join(", "),
231 v.models_reported.join(", ")
232 );
233 }
234 let _ = writeln!(o);
235 for v in s.suites.iter().filter(|v| v.freshness_detail.is_some()) {
236 let _ = writeln!(
237 o,
238 "- `{}`: {}",
239 v.id,
240 v.freshness_detail.as_deref().unwrap_or("")
241 );
242 }
243 let _ = writeln!(o, "\n## Metrics\n");
244 let _ = writeln!(
245 o,
246 "| metric | value | status | class | n | interval | what it is not |"
247 );
248 let _ = writeln!(o, "|---|---|---|---|---|---|---|");
249 for m in &s.metrics {
250 let class = match m.inputs {
251 Some(i) => format!("{} from {}", m.class.word(), i.word()),
252 None => m.class.word().to_string(),
253 };
254 let interval = m
255 .interval
256 .as_ref()
257 .map(|i| interval_text(i, &m.unit))
258 .unwrap_or_else(|| "—".into());
259 let _ = writeln!(
260 o,
261 "| `{}` | {} | {} | {} | {} | {} | {} |",
262 m.id,
263 value(m),
264 words(&m.status),
265 class,
266 m.n,
267 interval,
268 cell(m.not.as_deref().unwrap_or(""))
269 );
270 }
271 let _ = writeln!(o, "\nFormulas and warnings:\n");
272 for m in &s.metrics {
273 let _ = writeln!(o, "- `{}`: {}.", m.id, m.formula);
274 if let Some(i) = &m.interval {
275 let _ = writeln!(
276 o,
277 " - interval: {}; {} resamples, seed {}.",
278 i.method, i.resamples, i.seed
279 );
280 }
281 for w in &m.warnings {
282 let _ = writeln!(o, " - {w}");
283 }
284 }
285 let _ = writeln!(o);
286 if !s.segments.is_empty() {
287 let _ = writeln!(o, "## Segments\n");
288 let _ = writeln!(o, "Median per-pair total-token reduction over valid pairs, by segment: positive means Majordomus used fewer tokens, and a negative reduction means Majordomus used more tokens.\n");
289 let _ = writeln!(
290 o,
291 "| dimension | segment | valid pairs | median reduction | lowest | highest |"
292 );
293 let _ = writeln!(o, "|---|---|---|---|---|---|");
294 for g in &s.segments {
295 if let Some(d) = &g.token_reduction {
296 let _ = writeln!(
297 o,
298 "| {} | {} | {} | {} | {} | {} |",
299 g.dimension,
300 g.value,
301 g.n,
302 percent_text(d.median),
303 percent_text(d.min),
304 percent_text(d.max)
305 );
306 }
307 }
308 let _ = writeln!(o);
309 }
310 let live: Vec<_> = s.pairs.iter().collect();
311 if !live.is_empty() {
312 let _ = writeln!(o, "## Pairs\n");
313 let _ = writeln!(o, "Every declared pair, valid or not. Tokens are the provider-reported totals of every session of the run.\n");
314 let _ = writeln!(o, "| task | category | rep | status | control tokens | treatment tokens | token reduction | cost reduction | first-request overhead | reasons |");
315 let _ = writeln!(o, "|---|---|---|---|---|---|---|---|---|---|");
316 for p in live {
317 let _ = writeln!(
318 o,
319 "| {} | {} | {} | {} | {} | {} | {} | {} | {} | {} |",
320 p.task,
321 p.category,
322 p.repetition,
323 words(&p.status),
324 p.control_usage
325 .as_ref()
326 .map(|u| u.total.to_string())
327 .unwrap_or_else(|| "—".into()),
328 p.treatment_usage
329 .as_ref()
330 .map(|u| u.total.to_string())
331 .unwrap_or_else(|| "—".into()),
332 p.token_reduction
333 .map(percent_text)
334 .unwrap_or_else(|| "—".into()),
335 p.cost_reduction
336 .map(percent_text)
337 .unwrap_or_else(|| "—".into()),
338 p.first_request_overhead
339 .map(|x| signed_count(x as f64))
340 .unwrap_or_else(|| "—".into()),
341 cell(&p.reasons.join("; "))
342 );
343 }
344 let _ = writeln!(o, "\n\"Token reduction\" is `1 - treatment / control` on total tokens, and \"cost reduction\" the same on the harness's cost projection: positive means Majordomus used fewer tokens, and a negative reduction means Majordomus used more tokens. \"First-request overhead\" is not a reduction: it is the treatment's first-request input minus the control's, so positive means Majordomus added tokens before the model acted. An excluded pair shows its reductions so that the outlier rule's effect is visible; only valid pairs enter the metrics.\n");
345 let valid = s
346 .pairs
347 .iter()
348 .filter(|p| p.status == EconomicsPairStatus::Valid)
349 .count();
350 let _ = writeln!(
351 o,
352 "{valid} of {} declared pair(s) are valid.\n",
353 s.pairs.len()
354 );
355 }
356 if let Some(c) = &s.context {
357 let _ = writeln!(o, "## Context selection (deterministic)\n");
358 let _ = writeln!(
359 o,
360 "At revision `{}`, {} seeds (the issues of this repository's plan) were compiled by `majordomus devcontext` under its default budget of {} (bytes-over-four) tokens. Counted with {} ({}): {} candidate tokens (files the compiler judged relevant), {} selected; {} tokens reached in all. The compiler's own estimate of the selected tokens was {}; {} seed(s) exceed the budget when counted.\n",
361 &c.revision[..c.revision.len().min(12)],
362 c.seeds,
363 c.budget_tokens,
364 c.tokenizer.encoding,
365 c.tokenizer.implementation,
366 c.candidate_tokens,
367 c.selected_tokens,
368 c.considered_tokens,
369 c.estimated_selected_tokens,
370 c.seeds_over_budget_counted
371 );
372 let _ = writeln!(o, "This is context *selection*, not total token savings: it says what the compiler put in front of a worker out of what it found relevant, not what a session consumed.\n");
373 let unmeasured = s
374 .metrics
375 .iter()
376 .find(|m| m.id == CONTEXT_REDUCTION)
377 .filter(|m| m.status == EconomicsMetricStatus::NotMeasured);
378 if let Some(m) = unmeasured {
379 let _ = writeln!(
380 o,
381 "No figure is taken from this record: `{}` is not measured ({}).\n",
382 m.id,
383 m.warnings.join("; ")
384 );
385 }
386 }
387 if !s.history.is_empty() {
388 let _ = writeln!(o, "## History\n");
389 let _ = writeln!(
390 o,
391 "| suite | methodology | revision | recorded | metric | value | n |"
392 );
393 let _ = writeln!(o, "|---|---|---|---|---|---|---|");
394 for h in &s.history {
395 let _ = writeln!(
396 o,
397 "| {} | {} | `{}` | {} | `{}` | {} | {} |",
398 h.suite,
399 h.methodology,
400 &h.revision[..h.revision.len().min(12)],
401 h.at,
402 h.metric,
403 percent_text(h.value),
404 h.n
405 );
406 }
407 let _ = writeln!(o);
408 }
409 let _ = writeln!(o, "## Hypotheses\n");
410 let _ = writeln!(o, "Stated before any evidence existed, so that the evidence can refute them. They are not results.\n");
411 for h in &s.hypotheses {
412 let _ = writeln!(o, "- `{}` ({}): {}", h.id, h.status, h.statement);
413 }
414 let _ = writeln!(o, "\n## Reproduce\n");
415 let _ = writeln!(o, "```sh");
416 let _ = writeln!(o, "majordomus economics references # every task fails on its start and passes on its reference; no model");
417 let _ = writeln!(
418 o,
419 "majordomus economics measure # the context suite; deterministic, no model"
420 );
421 let _ = writeln!(o, "majordomus economics run --suite pilot # live sessions; needs a Claude Code login and spends usage");
422 let _ = writeln!(
423 o,
424 "majordomus economics summary # recompute every figure from the recorded runs"
425 );
426 let _ = writeln!(o, "majordomus economics explain effective_token_reduction");
427 let _ = writeln!(o, "```\n");
428 let _ = writeln!(o, "## Limitations\n");
429 let _ = writeln!(o, "- One fixture repository, small by design; a large repository is where context selection matters most, and it is not measured here.");
430 let _ = writeln!(o, "- One harness (Claude Code) and the model each suite names. Tokens are the provider's; counts from different providers are never compared directly.");
431 let _ = writeln!(o, "- Sessions are stochastic. A pair is one sample of each arm; only the distribution over many pairs says anything.");
432 let _ = writeln!(
433 o,
434 "- Cost is the harness's own projection at run time, not a bill."
435 );
436 let _ = writeln!(
437 o,
438 "- Context reduction is measured against what the compiler itself judged relevant."
439 );
440 let _ = writeln!(o, "- The context suite counts the corpus at the revision it recorded, not at the current one: a later change to the plan or to the files it selects from moves nothing until the suite is measured again.");
441 let _ = writeln!(o, "- The treatment is Majordomus as a user who installs only the shell tool gets it, and its generated bootstrap advises commands that installation cannot run (`majordomus worktree`). What a session spends on them is part of what that user gets, and it is measured as such, not corrected for.");
442 o
443}
444
445#[cfg(test)]
446mod tests {
447 use super::*;
448 use crate::economics::model::{EconomicsClass, EconomicsPair, EconomicsVerdict};
449
450 fn metric(unit: &str, value: Option<f64>) -> EconomicsMetric {
451 EconomicsMetric {
452 id: "effective_token_reduction".into(),
453 title: "Effective token reduction".into(),
454 class: EconomicsClass::Derived,
455 inputs: Some(EconomicsClass::Observed),
456 unit: unit.into(),
457 formula: "1 - treatment / control".into(),
458 not: None,
459 value,
460 status: EconomicsMetricStatus::Preliminary,
461 n: 3,
462 distribution: None,
463 interval: None,
464 suite: "pilot".into(),
465 evidence: vec![],
466 warnings: vec![],
467 }
468 }
469
470 fn pair(reasons: &[&str]) -> EconomicsPair {
471 EconomicsPair {
472 suite: "pilot".into(),
473 task: "vat-rounding".into(),
474 category: "bugfix".into(),
475 sessions: 1,
476 repetition: 1,
477 control: None,
478 treatment: None,
479 status: EconomicsPairStatus::Incomparable,
480 reasons: reasons.iter().map(|r| r.to_string()).collect(),
481 control_usage: None,
482 treatment_usage: None,
483 token_reduction: None,
484 cost_reduction: None,
485 tool_call_reduction: None,
486 continuation_reduction: None,
487 first_request_overhead: None,
488 }
489 }
490
491 fn summary(present: bool, pairs: Vec<EconomicsPair>) -> EconomicsSummary {
492 EconomicsSummary {
493 present,
494 methodology: Some(1),
495 question: Some("How many tokens does a session consume?".into()),
496 primary_metric: Some("effective_token_reduction".into()),
497 verdict: EconomicsVerdict {
498 publishable: false,
499 statement: "No verified total-token-savings claim is available.".into(),
500 unmet: vec!["at least 30 valid matched pairs".into()],
501 },
502 metrics: vec![metric("ratio", Some(0.2))],
503 suites: vec![],
504 pairs,
505 segments: vec![],
506 context: None,
507 history: vec![],
508 variants: vec![],
509 hypotheses: vec![],
510 publication: None,
511 diagnostics: vec![],
512 }
513 }
514
515 #[test]
516 fn a_ratio_is_a_signed_percentage_with_one_decimal() {
517 assert_eq!(value(&metric("ratio", Some(0.2))), "+20.0%");
518 assert_eq!(value(&metric("ratio", Some(-0.125))), "-12.5%");
519 assert_eq!(value(&metric("ratio", Some(0.0))), "0.0%");
520 assert_eq!(
521 value(&metric("ratio", Some(-0.0004))),
522 "0.0%",
523 "never -0.0%"
524 );
525 }
526
527 #[test]
528 fn a_count_carries_its_unit_and_an_absent_value_is_not_measured() {
529 assert_eq!(value(&metric("tokens", Some(1500.0))), "+1500 tokens");
530 assert_eq!(value(&metric("calls", Some(-4.0))), "-4 calls");
531 assert_eq!(value(&metric("ratio", None)), "not measured");
532 assert_eq!(value(&metric("tokens", None)), "not measured");
533 }
534
535 #[test]
536 fn without_a_methodology_the_report_stops_after_the_verdict() {
537 let text = markdown(&summary(false, vec![pair(&["control run missing"])]));
538 assert!(text.contains("## Verdict"));
539 assert!(text.contains("No verified total-token-savings claim is available."));
540 assert!(text.contains("- at least 30 valid matched pairs"));
541 assert!(text
542 .trim_end()
543 .ends_with("- at least 30 valid matched pairs"));
544 for later in [
545 "## Question and methodology",
546 "## Evidence",
547 "## Metrics",
548 "## Pairs",
549 ] {
550 assert!(
551 !text.contains(later),
552 "{later} rendered without a methodology"
553 );
554 }
555 assert!(!text.contains("## Limitations"));
556 }
557
558 #[test]
559 fn a_pipe_inside_a_reason_is_escaped_in_the_pairs_table() {
560 let text = markdown(&summary(
561 true,
562 vec![pair(&["model a|b differs", "no usage"])],
563 ));
564 let row = text
565 .lines()
566 .find(|l| l.starts_with("| vat-rounding |"))
567 .expect("the pair has a row");
568 assert!(row.ends_with("| model a\\|b differs; no usage |"), "{row}");
569 let unescaped = row.replace("\\|", "");
570 assert_eq!(unescaped.matches('|').count(), 11, "{row}");
571 }
572
573 fn valid(reduction: f64) -> EconomicsPair {
574 EconomicsPair {
575 status: EconomicsPairStatus::Valid,
576 reasons: vec![],
577 token_reduction: Some(reduction),
578 cost_reduction: Some(reduction),
579 first_request_overhead: Some(0),
580 ..pair(&[])
581 }
582 }
583
584 #[test]
585 fn a_pair_shows_its_reduction_with_the_sign_the_calculator_gave_it() {
586 let text = markdown(&summary(
587 true,
588 vec![valid(-0.1), valid(0.25), valid(-0.0001)],
589 ));
590 assert!(
591 text.contains("| token reduction | cost reduction |"),
592 "{text}"
593 );
594 assert!(!text.contains("token change"), "{text}");
595 let rows: Vec<&str> = text
596 .lines()
597 .filter(|l| l.starts_with("| vat-rounding |"))
598 .collect();
599 assert_eq!(rows.len(), 3);
600 assert!(
601 rows[0].contains("| valid | — | — | -10.0% | -10.0% | 0 |"),
602 "{}",
603 rows[0]
604 );
605 assert!(rows[1].contains("| +25.0% | +25.0% |"), "{}", rows[1]);
606 assert!(rows[2].contains("| 0.0% | 0.0% |"), "{}", rows[2]);
607 assert!(!text.contains("-0.0%") && !text.contains("+-"), "{text}");
608 assert!(text.contains("a negative reduction means Majordomus used more tokens"));
609 }
610
611 #[test]
612 fn a_state_is_spelt_as_it_serialises_and_an_interval_at_its_declared_level() {
613 use crate::economics::model::{
614 EconomicsFreshness, EconomicsInterval, EconomicsPairCounts, EconomicsSuiteView,
615 };
616 let mut s = summary(
617 true,
618 vec![EconomicsPair {
619 status: EconomicsPairStatus::ControlFailed,
620 ..pair(&[])
621 }],
622 );
623 s.metrics[0].interval = Some(EconomicsInterval {
624 level_bp: 9750,
625 low: -0.05,
626 high: 0.3,
627 method: "cluster bootstrap over tasks".into(),
628 resamples: 2000,
629 seed: 7,
630 });
631 s.suites.push(EconomicsSuiteView {
632 id: "pilot".into(),
633 kind: "live".into(),
634 version: 1,
635 title: "Pilot".into(),
636 model: None,
637 freshness: EconomicsFreshness::NoEvidence,
638 freshness_detail: None,
639 runs: 0,
640 pairs: EconomicsPairCounts::default(),
641 revisions: vec![],
642 harnesses: vec![],
643 models_reported: vec![],
644 });
645 let text = markdown(&s);
646 assert!(text.contains("| pilot | live | no evidence |"), "{text}");
647 assert!(text.contains("| control failed |"), "{text}");
648 assert!(text.contains("| 97.5%: -5.0% to +30.0% |"), "{text}");
649 assert!(
650 text.contains(" - interval: cluster bootstrap over tasks; 2000 resamples, seed 7.")
651 );
652 for debug in ["noevidence", "ControlFailed", "NoEvidence"] {
653 assert!(!text.contains(debug), "{debug} in {text}");
654 }
655 }
656
657 #[test]
658 fn records_that_could_not_be_read_are_listed_even_without_a_methodology() {
659 let mut s = summary(false, vec![]);
660 s.diagnostics = vec!["runs/pilot/r1.json: expected value at line 1".into()];
661 let text = markdown(&s);
662 assert!(text.contains("## Records that could not be read"));
663 assert!(text.contains("- runs/pilot/r1.json: expected value at line 1"));
664 s.diagnostics.clear();
665 assert!(
666 !markdown(&s).contains("could not be read"),
667 "no problem, no section"
668 );
669 }
670
671 #[test]
672 fn the_limitations_name_the_shell_only_bootstrap_and_the_recorded_revision() {
673 let text = markdown(&summary(true, vec![]));
674 let limits = &text[text.find("## Limitations").expect("a limitations section")..];
675 assert!(limits.contains("`majordomus worktree`"), "{limits}");
676 assert!(limits.contains("measured as such"), "{limits}");
677 assert!(
678 limits.contains("at the revision it recorded, not at the current one"),
679 "{limits}"
680 );
681 }
682
683 #[test]
684 fn the_metrics_table_spells_the_value_as_value_does() {
685 let text = markdown(&summary(true, vec![]));
686 assert!(text.contains(
687 "| `effective_token_reduction` | +20.0% | preliminary | derived from observed | 3 | — |"
688 ));
689 assert!(!text.contains("## Pairs"));
690 }
691}