soup diagnose — seven failure-mode probes, one verdict

After you finish training, the question is no longer "did the loss go down" — it's "did I quietly break something." soup diagnose (v0.56.0) is a post-training model report card that runs 7 pure-function failure-mode probes:

ProbeWhat it catches
forgettingPer-task Δ accuracy with tolerance band — extends v0.25 eval/forgetting
refusaladvbench / xstest delta over caller-supplied generators (_MAX_REFUSAL_SCAN = 8192)
formatJSON / regex / tool-call validity over the RLVR verifier set, with an explicit ReDoS probe (compiled.search("a" * 128))
mode_collapsePairwise n-gram-Jaccard distance over K completions (k ∈ [2, 32], ngram_n ∈ [1, 8])
memorizationTraining-prefix echo via partial-prompt continuation (_MAX_SCAN_ROWS = 1000)
contaminationn-gram overlap with public benchmarks (combined-complexity cap rejects when training rows × benchmark corpus > 1e9)
citationcitation-recall regression on RAFT-shaped rows: does the answer still cite the supporting [doc-id]? (v0.71.10)

Every probe is a pure function over a generator callable, which is why the same code path serves both modes. Since v0.71.7 soup diagnose can supply that generator itself: pass --base-model (with --dataset, and optionally --tokenizer, --device, --citation-style and --shuffle-seed) and it loads the model and runs the probes for you. Without --base-model it stays a pure scorer over evidence you supply, and you wire in your own GeneratorFn around a serve backend.

Usage

bash
soup diagnose <run-id> \
  --evidence ./evidence.json \
  --output ./diagnose.json \
  --badge ./badge.svg \
  --attach-to-registry registry-id

--attach-to-registry attaches nothing at v0.75.2. The report and the badge are written first, then the command passes three positional arguments to a registry helper that takes only the entry id positionally, so it prints a yellow Warning: could not attach to registry: TypeError: attach_artifact() takes 1 positional argument but 3 were given and carries on with exit 0. Without --output it is skipped with its own warning.

Verdict thresholds (composed in compose_report):

  • ≥ 0.85 → OK
  • ≥ 0.60 → MINOR
  • < 0.60 → MAJOR

Output: a frozen FailureReport (run_id / base / adapter / scores / overall / soup_version / extras) plus an embeddable SVG badge from render_badge_svg, one cell per probe (html-escaped — safe for HF model cards). Missing modes fill via neutral_score.

soup train --diagnose-gate

bash
soup train --diagnose-gate ./evidence.json

Runs after training has finished: the "Training Complete!" panel has printed, the adapter is already saved and the tracker has already recorded the run as finished. It reads the evidence JSON you pass (a scores object keyed by mode, each entry with a score and optionally a verdict and evidence string), runs no probe itself, and scores any mode you leave out as a neutral OK. If any supplied mode is MAJOR it prints the offending modes and exits 2, so a CI step fails. It does not withhold or delete the checkpoint, and the --help text for the flag ("refuses to mark the run successful") overstates it. The diagnose_report artifact kind is registered in the v0.26 registry alongside eval_suite and canaries from v0.55.

See also

  • Eval-gated training — pre-training gate at epoch boundaries
  • Quant-check — quant-specific regression check
  • Eval design — design the evidence your gate scores
  • Eval depth (v0.65) — 4 deeper failure-mode probes (behavior, capability, checklist, irt-subset) that stack on top of the 7 diagnose probes
  • Post-train x-rays (v0.66) — 4 mechanistic-interpretability probes (sae-diff, sleeper, interference, pack) — failure-mode coverage 7 → 11

Soup is free and Apache-2.0. If it saved you a training run, starring the repo costs nothing and helps most. You can also fund the GPU time behind the work a 4 GB laptop cannot reach.