Skip to content
Version: Current

The documentation engine

Documentation rots in a predictable order: the reference drifts first, then the examples, then the pages that were only ever true on the day they were written. This engine attacks the three in that order, and it refuses to do more than one page per cycle.

detect ──► rank ──► plan (one card) ──► write ──► check ──► record
▲ │
└──────────────────── next cycle ───────────────────────┘

detect reads the surfaces declared in tools/docs-engine/sources.json (the OpenAPI contract, the protobuf services, the CLI dispatcher, the flags, the error taxonomy), indexes every published page, runs the examples a page opts into, and reports the difference as gaps with citations. rank orders them by exposure weight, then by observed traffic. plan writes exactly one decision card. write produces the page. check runs the gate. record appends to docs/ITERATION.md and to the SQLite cycle store.

Terminal window
node --version
Terminal window
git log -1 --format=%h

The engine is plain Node with no dependencies, so it runs wherever the site builds:

Terminal window
node tools/docs-engine/detect.mjs --no-examples
node tools/docs-engine/generate.mjs --check
node tools/docs-engine/cycle.mjs --plan

Generated and gate-checked: the API reference, commands, configuration, error codes and RPCs. If the source changes and the page does not, the gate fails.

Generated but not gate-checked: the changelog, which is a feed, and the docs health snapshot, which is a measurement.

Hand-written, always: tutorials, how-to pages, runbooks and explanations. The engine can point at the gap and cite the evidence; it cannot decide what a reader needs to be told. That is why prose needs a reviewer and a reference regeneration does not.

  1. One page per cycle. A cycle that writes three pages leaves three pages half-checked and a card that cannot say what it approved.
  2. Every gap cites a source. A finding with no path:line or dated URL is a bug in the detector, not a task.
  3. Examples opt in. Only a block tagged exec runs; everything else is quoted for a reader. The runner allows a fixed set of verbs, refuses shell operators rather than reinterpreting them, and keeps network access on loopback unless the caller opts in.
  4. Authoritative checks are explicit. A checkout without required source repositories may run local checks, but they report NOT AUTHORITATIVE and must not be read as a green drift claim. Scheduled/authoritative runs pass --require-sources and set DOCS_ENGINE_REPO_* checkout overrides so an absent required source fails loudly.

sources.json declares each repo and source file, with required/set metadata for required and optional source sets. Use DOCS_ENGINE_REPO_ACUMEN and DOCS_ENGINE_REPO_CLI (or the matching DOCS_ENGINE_REPO_<NAME> variable) to point at the checkout present in an environment.

Authoritative check:

Terminal window
DOCS_ENGINE_REPO_ACUMEN=/srv/acumen-vnext \
DOCS_ENGINE_REPO_CLI=/srv/cli \
node tools/docs-engine/generate.mjs --check --require-sources

Refresh/regenerate:

Terminal window
DOCS_ENGINE_REPO_ACUMEN=/srv/acumen-vnext \
DOCS_ENGINE_REPO_CLI=/srv/cli \
node tools/docs-engine/generate.mjs --write
DOCS_ENGINE_REPO_ACUMEN=/srv/acumen-vnext \
DOCS_ENGINE_REPO_CLI=/srv/cli \
node tools/docs-engine/generate.mjs --check --require-sources

tools/ci.sh --skip-deploy keeps the local default: it runs the drift check without external source repos and labels missing required sources as non-authoritative REQUIRED-SKIPs, not a green drift claim.

  • docs/ITERATION.md: one entry per cycle: the gap, its citation, the page, the commit, the checks. Reviewed like any other page.
  • var/docs-engine/cycles.db: the same cycles plus every gap snapshot, for the panel and for the next cycle’s “do not re-plan this” check. Not committed: a binary file in git is unreviewable.

It does not read support tickets, search queries or analytics by itself. Those signals arrive as a JSON file (--signals); with no file, those detectors report nothing rather than inventing a finding. It also does not merge prose: a card is a proposal, and a human approves it.