Failure Modes/Chapter 22 of 35

Fabricated benchmarks

5 min readEdit on GitHub

The most damaging failure mode in AI-augmented ML. The agent produces a number that looks like a measurement but came from nowhere. The number lands in a model card, a slide, a blog post, a tweet. Then someone tries to reproduce it.

Hard rule, not suggestion: no number ships unless a script measured it and the script lives in the repo.

How fabrication happens

Three pathways. All common.

1. The agent estimates instead of running

Prompt: "What's the inference latency of this model on an L4?"

Bad output: "Approximately 45ms per token, based on typical L4 performance for similar models."

The agent has invented a number. It is plausible. It is not measured. It will be wrong by a factor of 2 or more.

2. The agent confuses a similar number for the actual one

You ask for the F1 of model A on dataset X. The agent finds an F1 in the codebase — for model B on dataset Y — and reports it for model A on dataset X. Numerically it looks defensible. It is wrong.

3. The agent runs once and reports a noisy single value

Cold-start, single trial, no warmup, no comparison. The number is real but unreliable. The third decimal place is noise; the first might be too.

The rule

Every number in user-facing material must trace to a runnable measurement script committed to the repo OR a cited source with a working URL.

Disclaimers like "approximate," "preliminary," or "internal estimate" do not make fabricated numbers acceptable. They make them worse — they suggest data exists that does not.

When you do not have a measurement: leave the cell empty, write "TBD," or omit the table. Empty is honest. Fake is not.

Methodology checklist (so the measurement is also real)

Having a script is necessary, not sufficient. The script's protocol must be sound:

Metric typeRequired protocol
Throughput / latencyWarmup ≥3 calls; report best-of-N (N≥3); state protocol in result
Quality (F1, accuracy, etc.)Confidence interval from CV or seed variance; state corpus, license, registers
Comparison vs. competitorPin and report the competitor's version; record bench date
Cost ($/inference, $/train)Hardware spec, cloud SKU, market price as of date

Single-run results without warmup are noise. They have caused public embarrassment when "135× speedup" turned into "21× speedup" after fixing the cold-start artifact (caught on a project of mine in April 2026).

A bench script template

# benchmarks/run_latency.py
import json, time, statistics, argparse
from pathlib import Path

def bench(model, inputs, n_warmup: int = 3, n_trials: int = 7) -> dict:
    for _ in range(n_warmup):
        model(inputs[0])
    timings = []
    for x in inputs[:n_trials]:
        t0 = time.perf_counter()
        model(x)
        timings.append(time.perf_counter() - t0)
    return {
        "n_warmup": n_warmup,
        "n_trials": n_trials,
        "median_s": statistics.median(timings),
        "min_s": min(timings),
        "max_s": max(timings),
        "stddev_s": statistics.stdev(timings) if len(timings) > 1 else 0.0,
        "raw_s": timings,
    }

if __name__ == "__main__":
    ap = argparse.ArgumentParser()
    ap.add_argument("--out", required=True)
    args = ap.parse_args()
    # ... load model, build inputs ...
    result = bench(model, inputs)
    Path(args.out).write_text(json.dumps(result, indent=2))

Now any number in a doc cites: "median 23ms over 7 trials after 3 warmups, measured by benchmarks/run_latency.py, see benchmarks/results/2026-05-04.json."

That is what a defensible benchmark looks like.

Auditing existing docs

The agent can help here. A subagent prompt:

#.claude/agents/benchmark-auditor.md
For each numeric claim in the given file:

1. Find the script that would have produced it (search benchmarks/, eval/).
2. If no script exists, flag it.
3. If a script exists, run it and compare. Flag any > 1% drift.
4. Report a table: claim | source | currently-measured | drift.

Do not edit the file. Just produce the report.

Run before any release. Be willing to delete claims that cannot be verified.

What to do when you find a fabricated number

In your own work:

  1. Remove the number. Replace with "TBD" or empty.
  2. Decide whether to measure it (yes if it matters, no if it does not).
  3. Update the doc with the measured value (in the same commit).
  4. Add a CLAUDE.md rule that would have prevented it.

In someone else's work that depends on yours: politely flag, share the measurement script, encourage them to update.

The cultural piece

Fabricated benchmarks erode trust faster than any other error. A broken function gets fixed in an afternoon. A wrong benchmark in a public artifact survives in screenshots, citations, and reposts long after you correct the original.

Publish fewer numbers; make every published number defendable. The reputation compounds.