


Maintain a Docs Book Whose Code Examples Are Tested Like Real Code
Use when editing a docs book whose code examples are compiled and tested. Covers the build and test commands, the two ways examples are stored, moving an example out instead of raising shared library versions, and the pre-review checklist.
To use this AI rule
## Treat every code block in the book as tested code, not just text
The book is a collection of practical examples written as markdown files with embedded code blocks. A doc-test harness walks the source tree, extracts every code block, compiles it, and runs it, so a broken example fails the build exactly like broken application code.
### What that implies for every edit
An example that does not compile is not documentation. Prose can be reworded freely, but any change inside a code block is a change to tested source and has to be run through the test command before it is proposed.
### Keep the rendered book and the test surface in sync
The same markdown feeds the rendered book and the test harness, so formatting choices carry semantics. Annotations on a code block decide how the harness treats it, and lines hidden from readers are still compiled. Never strip an annotation or a hidden line just to make the rendered page look cleaner.
## Build, test, and preview the book with the documented commands
Route every routine action through the documented commands rather than inventing ad hoc invocations, so local runs match continuous integration.
### The commands that matter
- Build the book from the markdown sources.
- Run the full suite, which is the doc tests plus the spellcheck pass.
- Run only the doc-test target when you changed a code block and want the fast loop.
- Serve the book locally with live reload while editing prose.
- Build and test together as the pre-review default.
- Run the link checker, which validates internal and external links against a checked-in configuration file.
- Run the spellcheck script interactively and add legitimate new words to the repository dictionary file, so the addition is reviewed with the change.
### Pin the toolchain
The book generator and the link checker are installed at exact pinned versions from a single documented install command. Do not upgrade a tool locally to work around a failure, because a version drift turns a reproducible failure into one only you can see.
## Know the two ways examples are stored, and never raise shared library versions
Examples are tested in one of two ways, and knowing which pattern a file uses determines where its code and its dependencies live.
### Pattern one: inline blocks tested in place
Code blocks live directly in the markdown under the source tree. A build script walks that tree for markdown files and generates one test per code block. Every dependency such an example needs must already exist in the root manifest. Blocks accept annotations for the language edition and for behavior such as compile-only, expected-panic, and skip; boilerplate that readers do not need is written as lines prefixed with a hash and a space, which the harness compiles but the rendered book hides. This is the legacy pattern, kept working but not extended.
### Pattern two: standalone packages included into the markdown
The code lives in its own package under a shared code directory with an independent manifest, and the markdown pulls it in through an include directive that points at the source file by relative path. Line-range includes let a page show only part of a file, which is how test scaffolding is kept out of the rendered example. The path is excluded from the doc-test harness in the build script so the code is not tested twice. This is the preferred pattern for new and migrated examples.
### The dependency rule
Do not change dependency versions in the root manifest. The root manifest is shared by every inline example, so a bump to satisfy one page can silently break dozens of others. When an example needs a newer dependency, migrate that example to a standalone package with its own pinned versions instead.
## Move an example that needs a newer library into its own package
When a dependency version has to change, convert the affected examples to standalone packages. Follow the steps in order, because each one leaves the repository in a state the next step depends on.
1. Create the package under the shared code directory, in a folder named for its category and then the example, with its own manifest. Inherit shared dependencies from the workspace where possible, or pin versions independently where the whole point is to diverge.
2. Move the code out of the markdown code block into the package source: one binary per runnable example, or a library module for library-style examples.
3. Register the package in the workspace member list in the root manifest.
4. Replace the inline code in the markdown with an include directive whose relative path runs from the markdown file's own location to the package source.
5. Exclude the migrated path from the doc-test harness in the build script. There are two exclusion lists: one that takes a directory prefix and removes everything under it, and one that takes a single markdown file. Use the narrower one that fits.
6. Test both sides: run the new package's own tests, and rerun the doc-test target to confirm that removing the block did not break the remaining inline examples.
A migration that stops before step five leaves the example compiled twice, and one that stops before step six can silently drop coverage.
## Read the files that decide what gets built and tested
A handful of files decide what is tested, what is rendered, and what commands exist. Read them before changing behavior, and change them deliberately.
- The root manifest holds the dependencies used by inline examples and the list of workspace members.
- The build script discovers markdown for the doc-test harness and carries the two exclusion lists that keep migrated examples from being tested twice.
- The book configuration file controls how the markdown is rendered into the book.
- The build tool configuration defines the task-runner alias that the documented commands rely on.
- The task-runner package implements build, test, and link-checking as subcommands, so the same logic serves both a contributor and continuous integration.
If a command behaves differently from its description here, treat the files above as the source of truth and fix the description rather than working around it.
## Write complete examples readers can copy and run
An example is judged by whether someone can copy it into their own project and have it work, not by how short it looks on the page.
### Content rules
- Examples are complete and compilable, not fragments.
- Propagate errors with the language's error-propagation operator rather than panicking on failure, and follow the project's documented error-handling pattern.
- Avoid glob imports, so a reader can see exactly which traits and items the example depends on.
- Mark examples that need an external service or network access as compile-only, so the suite stays runnable offline.
- Hide boilerplate with the hidden-line prefix rather than deleting it, so the example still compiles.
- Prefer creating a standalone package for a new example over adding another dependency to the root manifest.
### Adding a new top-level section
When you add a new top-level section page, also add an include for it to the book's table-of-contents page, in the correct alphabetical position. That page is the reader's entry point, and a section that is not included there is effectively invisible even though it builds successfully.
## Pass all tests and the checklist before asking for review
Verify all of the following before opening or updating a change for review, and again after any rewrite.
- The full test suite passes locally, using the documented all-tests command rather than a partial run.
- Commits are squashed into one and rebased onto the latest main branch.
- The description contains a correct issue-closing clause, or the clause is removed entirely when no issue exists. A wrong issue number is worse than none.
- Non-rendered lists are in sorted order: links, references, identifiers, and manifest entries. Sorted order is what keeps future diffs small.
- Documentation links to external API reference pages use the wildcard version segment instead of a pinned version, so the link does not rot at the next release.
- The example uses the project's standard error handling, with no panic-on-failure shortcut.
- Code identifiers in the description are written as backticked names that are hyperlinked to their reference pages through link definitions at the bottom of the file.
After submitting, watch the continuous integration run and fix any failure it reports rather than leaving a red change open for a reviewer to triage.
