Skip to content

Writing the documentation

This page is the standard every page in this site is written to. It exists because an audit found the old pages explained the library in its own vocabulary ("family 229", "supercritical", "channels B and C") before telling the reader what problem they were solving. Follow it when you add or change a page, and point reviewers here.

Start from the reader

Before writing, answer three questions at the top of your draft (then delete them):

  1. Who is reading? Pick from the readers below. Most pages serve one or two.
  2. What do they already know when they arrive? Assume only what the pages before this one in the nav have taught.
  3. What can they do when they leave? A concrete ability: "wire the decide call into a FastAPI handler", "explain to a fraud lead why a card was held", "choose p_threshold from last quarter's data".
Reader Arrives knowing Wants
Evaluator Python, their own product "What is this? Is it for me?"
Integrator Their service, HTTP, databases "How do I wire it in and run it?"
Domain owner Fraud, clinical, ops, moderation "What will it decide, and why?"
Data scientist Models, scores, graphs, statistics "How do my data and scores map in?"
Theory reader Probability, graphs, algorithms "Which result, stated how, with what limits?"
Contributor This repository "How is it built and how do I change it?"

Kinds of page

Every page is one of four kinds. Don't mix them; link between them.

Kind Section Reader is… Shape
Tutorial Get started learning by doing numbered steps, each with a command and its real output
How-to How-to guides doing a specific task goal → prerequisites → steps → result → what can go wrong
Explanation Concepts, Theory trying to understand question → intuition → example → precise statement → limits
Reference Reference looking something up complete, consistent tables and definitions; little prose

Openings

The first three sentences of every page say, in plain words, what problem this page is about and why the reader should care. No term the reader hasn't met yet, no family number, no formula.

Bad: "Family 229 is the kernel's refusal to emit a seed label when the broadcast is too weak."

Good: "Sometimes the cases related to this one tell you a lot about it; sometimes they're too few or too mixed to tell you anything. This page explains how the library tells those apart, and why it holds a decision when the related cases are too weak to support it."

Then say what the page covers and what it assumes.

Concrete before abstract

Order every explanation as:

  1. The situation, in a domain the reader recognises (a card, a patient, a pager alert).
  2. The intuition, in plain words or a picture.
  3. A worked example with real numbers, copied from running the code (uv run grounded-decision examples <id>), not computed by hand.
  4. The precise statement (formula, rule, type signature).
  5. What it does not do: limits, failure modes, honest caveats.
  6. What to do about it in practice: the setting to change, the page to read next.

A formula never appears before the reader knows what question it answers.

Words

  • Define every term on first use on each page, or link it to the glossary. Readers arrive from search; don't assume they read the previous page.
  • Use the reader's words first, then ours: "how strongly linked cases agree (we call this neighbour agreement, λ)".
  • One name per thing. Use the canonical terms below. Never "channel B", "the cursor" and "state" for different things on the same page.
  • No aphorisms in place of explanations. "Silence is not coverage" is a conclusion; show the reader the empty calibration set and what happens.
  • No history. "The old regex tokenizer skipped characters" belongs in the changelog, not on a reader page.
  • Plain sentences. Full sentences, active voice, one idea each. Cut rhetorical repetition and intensifiers.

Canonical terms

Say Not Meaning
policy grammar, run-book (alone) The short text or chart listing which events lead to which proposed actions.
event letter Something that happened, named the way the policy names it (suspicious).
state cursor, vertex Where an entity currently is in its policy. Saved after each decision, restored before the next.
proposed action proposal, marking (alone) What the policy would do next if nothing else were checked. Always recorded.
check channel (alone), channel A/B/C One of six independent yes/no tests. Any "no" means the decision is held. "Channel" is the field name in records.
act / abstain / degrade fire / hold (as verdicts) The three verdicts. "Hold" is fine in prose for abstain-and-route-to-a-person.
evidence snapshot (alone) The numbers describing the related cases around this decision (EvidenceSnapshot).
related cases / corroboration graph broadcast tree, seed graph Your related cases as dots, with lines between cases that share something.
neighbour agreement (λ) lambda_hat (in prose), channel correlation How much more often linked cases share a label than chance. 0 = no better than chance.
evidence strength (dλ²) KS score, supercriticality Average links per case × agreement². Above about 1, the related cases genuinely inform.
decision line / knife-edge window flicker band, p*, p_* The range of link density near your cut-off where a little noise flips the answer.
unusualness score, calibration set nonconformity bag How unusual this case is compared with recent cases where the answer was right.
trust level: proven / published / practical lean / paper / operational (alone) How much of a mathematical result a check relies on. Field values stay lean, paper, operational.
math catalog, result number family (alone), pin The companion collection of math results; each has a number. Give the plain name first: "Kesten–Stigum reconstruction (catalog result 229)".

Numbers and examples

  • Every number on a page comes from running the code, and the page says which command produces it. If the code changes, the golden-output tests in tests/snapshots/ change too; update the page in the same commit.
  • Prefer one worked example carried through the page over several half-examples.
  • Show units and meaning next to every number: "dλ² = 1.51 (above the 1.05 line, so the related cases are informative)".

Honesty

  • Describe what the code does, not what we wish it did. If a check is weaker than its name suggests, say so on the page where readers rely on it.
  • Separate "proven" (with the exact statement used), "published but not machine-checked", and "practical stand-in".
  • Every page that recommends acting on a verdict says what the verdict does not establish.

Math

  • Inline math is \( ... \), display math is \[ ... \] (MathJax). Don't escape underscores or asterisks inside formulas; tests/test_docs_math.py fails if a formatter has.
  • Code identifiers inside a formula: \texttt{label\_score}.
  • Never let Prettier or another Markdown formatter rewrite these files (.prettierignore excludes them).
  • Every symbol is defined in words on the page where it appears.

Mechanics

  • New pages go in mkdocs.yml nav and are linked from at least one existing page. make docs (strict) fails on broken links.
  • Commands in fenced shell blocks must be real make targets or real example ids; tests/test_docs_commands.py checks.
  • Diagrams use Mermaid fences (```mermaid).
  • Admonitions (!!! note, !!! warning) for caveats a reader must not miss; don't use them for decoration.
  • Run make docs-serve and read your page in the browser before you finish.