Tutorial contract
A fasterai tutorial is a claim about what the library does to a real model. This page is the contract those claims are held to, and it is also the enforcement: the hidden cells below parse every tutorial in nbs/tutorials/ (plus quickstart and overview) and assert the rules that follow. They run in the default test suite, so a page that breaks the contract turns CI red before it reaches the site.
The voice
A tutorial reports what one run measured. It does not rank, advise or promise.
| Instead of | Write |
|---|---|
| “the best criteria for this” | “in this run, large_final ended at 92.69% (1370/1478)” |
| “always fold batch norm before export” | “folding rewrites the convolution weights; this page folds before exporting” |
| “up to 4x faster” | “633 ms against 26 ms on this box, single run” |
| “minimal accuracy loss” | “-3.1 points, and the two Wilson intervals overlap” |
These words never appear in tutorial prose, because each of them states a preference or a guarantee that no cell on the page measured: best, fastest, always, never, recommended, rule of thumb, key finding, tip, guaranteed, optimal, when to use, for free, free speedup, no drop in accuracy, without any drop, and the verdict emoji. Code is not prose: warnings.simplefilter('always') is fine, and so is a file named best.pt.
Every number comes from the page
The rule is mechanical: a number stated in prose must be a number a cell on the same page prints, exactly or as a rounding of it. A percentage may be printed as a proportion (0.926928 backs 92.69%), a parameter count may be printed in full (134309962 backs 134 million). What is not allowed is a number nobody computed: a ratio, a delta or a speed-up that only exists in the sentence. If a page wants to say “3.9x smaller”, a cell prints the ratio.
Confidence bounds are the one exception, and only because they are checked harder: an interval written next to a k/n is recomputed from k and n and has to match.
Measurement rules
- Accuracy carries its n. A sentence stating an accuracy carries
n = N, or ak/n, or names the evaluation set size (“the 1478 validation images”). - Percentages that come from counts are written with the counts, and the two must agree:
92.69% (1370/1478). - Intervals are Wilson 95% intervals and are recomputed from
k/n— on whichever scale the page prints, percentages or proportions. - A latency carries a scope line: “single run”, “one run”, “this run” or “Measured on …”. A number with a
ms,µsorFPSunit and no scope is a claim about a machine the reader does not have. - A sentinel is never a result.
0.00 MB,0 parameters,nan ms,accuracy: -1are failed measurements; they may be discussed, never shown as an outcome.
Required elements
Front matter with title, description and skip_exec: true; a ## Summary section; a ## See Also section; every link resolving to a page or an image that exists. tutorials/quantize/deployable_export.ipynb is the reference for the shape of a page.
The rules the checks enforce
| Rule | What it asserts | Waivable |
|---|---|---|
| R1 | No cell output is an error or contains a traceback | no |
| R2 | A visible cell that produces something shows it, and no output is a bare placeholder | yes |
| R3 | No sentinel value (0.00 MB, 0 parameters, nan, -1) is shown as a result |
no |
| R4 | Every number in prose is printed by a cell on the same page | yes |
| R4b | A page reporting a latency carries a scope line | yes |
| R5 | The prose uses none of the forbidden words | yes |
| R6 | Names shown in prose exist: blocks parse, keyword arguments and vocabularies are real | yes |
| R7a | Front matter, ## Summary and ## See Also are present |
yes |
| R7b | Every internal link resolves | no |
| R8 | The sidebar and the tutorials folder agree, both directions | no |
| R9 | Accuracy sentences carry n; k/n and intervals are recomputed |
yes |
| R10 | No cell output is a stderr stream, hidden cells included | yes |
“Waivable” means the rule can hold an entry in the quarantine described below. The four that cannot be waived are the ones whose failure means the page is broken rather than imperfect: a failure shown as a result, and a link or sidebar entry that goes nowhere.
Running the checks
nbdev_test --path nbs/tutorial_contract.ipynb # seconds; this is what CI runs
And, on a machine with the GPU, the datasets and the optional dependencies, the execution gate — it re-runs every tutorial in a copy of its folder and reports what the code no longer reproduces:
python -c "from nbdev.test import nbdev_test; nbdev_test(path='nbs/tutorial_contract.ipynb', flags='tutorials')"
It takes about an hour. FASTERAI_TUTORIALS='tutorials/sparse/*' narrows it. Nothing is written under nbs/, and no output is committed by it: when a page drifts, the remedy is to re-run that page in a Jupyter kernel and commit the new outputs together with the prose they support.
The quarantine, and how it empties
Pages written before this contract carry known violations. Rather than block them, the gate holds a QUARANTINE dict — a per-page list of the rules that page is still allowed to fail — and enforces three things about it:
- It can only shrink. A frozen copy,
_LANDED, was taken when this page landed. A page or a rule that is not in_LANDEDcannot enterQUARANTINE, so a new violation can never be waived — it must be fixed. - It cannot hold an unwaivable rule.
- Entries expire the moment they are unused. If a quarantined page stops violating its rule, the gate fails with “now passes R4: delete the entry”. Rewriting a page and deleting its entry are one commit.
_LANDED is edited by review only; nothing in the machinery writes to it.
To let a single sentence through R5 — an honest caveat that happens to contain a listed word — add it verbatim to LEXICON_ALLOW[page]. The match is the whole sentence, so the diff shows exactly what was allowed.
What these checks cannot do
They read structure, not meaning. They cannot tell whether a sentence’s conclusion follows from the number beside it, whether a comparison is controlled, whether a baseline is degenerate, or whether a python block would actually run. Those stay with the reviewer of every tutorial change. Two known blind spots are worth naming: Pruner and PruneCallback accept **kwargs, so no signature can refute a made-up keyword on them (a denylist covers the ones already seen), and a cell whose last statement is a call is not required to have output, because a call may legitimately return None.
See Also
- Deployable INT8 Export - The page these rules were written from
- Quick Start - The shortest tour of the library
- Overview - What each module does