Skip to content

Keeping the docs true

Documentation rots when it repeats something the code already knows. This guide is built to reduce how much of it can rot, and to fail the build when the rest does.

Four mechanisms, in order of how much they cover.

1. Derive rather than describe

Anything the source already knows is generated from the source, not typed twice. Today that is the repository layout, the CI gate list, the platform settings table, the dashboard menu, and every connector's tool inventory.

The connector tool tables are the clearest case. The generator calls each connector's real factory and reads back the tools it registers, so a tool that is added, renamed, or removed changes the published table with no page edit. bun run docs:gen --check is a CI gate: a committed block that no longer matches its source fails the build.

What cannot be derived is judgement. What a workspace is for, what a gate is protecting, what a setting means in practice: that lives in a notes file keyed by the identity the generator discovers. The pairing is deliberate, and it fails in both directions. A new workspace with no note fails, and a note for a workspace that no longer exists fails too, so the table can never be half written.

2. Screenshots are generated, never taken by hand

Every image in this guide is produced by one command. It boots its own throwaway PostgreSQL and Valkey on random ports, applies the real migrations, seeds a demo tenant through the real code paths, builds and serves the real dashboard, and drives it with a browser.

That matters for staleness because there is no manual step to skip. Nobody has to remember which screens changed, or crop anything, or keep a private copy of the demo data.

It also cannot touch your development database. The harness passes its own connection details to every child process and refuses to start if they match an inherited one.

A failed run leaves the published images alone. Capture writes to a staging directory and swaps it in only after every shot has succeeded, so a broken run can never leave the guide referencing images that no longer exist.

The wizard walk checks itself against the product

The setup pages are the most drift-prone in the guide, because they describe a sequence of screens step by step. So the capture walks every wizard for real, the Slack connection and each connector alike: it fills each form, presses the button that advances, and photographs every step.

Before it starts, it reads the wizard's own progress bar and compares it to the step list the guide claims. Rename a step, add one, or remove one, and the capture stops with both lists printed. It cannot silently publish a guide that describes screens the product no longer has.

Because each image is named after its step, a renamed step also renames its file, and the strict build below then fails on the page that still points at the old name. The two checks catch the same drift from opposite ends.

3. The strict build refuses broken references

mkdocs build --strict fails on a broken internal link, a missing image, or a page absent from the navigation. Any of those is an error, not a warning.

4. Prose rules are enforced, not requested

bun run docs:lint fails on em dashes, tracker and decision-record references, and source paths. The source-path rule exists because a reader of the user guide has no checkout. Pages under Build are exempt from that one rule, because their subject is the code, and every other rule still applies to them.

What is still maintained by hand

Being honest about the remaining gap is more useful than claiming full coverage.

Still by hand What protects it
Every explanatory sentence Nothing automatic. Prose is the part worth writing by hand
Which screenshot a page embeds The strict build, which fails if the file is missing
Step-by-step explanations of each wizard screen The step-name assertion, which fails if the sequence changes
Counts stated in prose, such as how many connectors exist Nothing automatic

The last row is a real gap. A count in a sentence is exactly the kind of fact that should be derived, and it is a good candidate for the next thing to generate.

Working on the docs

bun run docs:install    # once
bun run docs:serve      # live preview
bun run docs:gen        # regenerate derived blocks after a source change
bun run docs:build      # what CI runs

The site declares a canonical URL with a project subdirectory, so the local preview is mounted there too. Open http://127.0.0.1:8000/sre-platform/, not the bare root, the root just redirects there with a 302.

Screenshots are regenerated with bun scripts/docs/screenshots/capture.ts. It needs a Docker daemon and a browser from bunx playwright install chromium. Run it directly rather than through the package script, which buffers output and hides progress.