# Documentation is code

> This method treats documentation as code, and every run] shows what a document passes through.

Page: Methodology · Verify
Canonical: https://banes-lab.com/disciplined-methodology/verify#documentation-is-code

This section is stop 47 of 102 in the learning route. Previous: [32 - Counting copies](https://banes-lab.com/disciplined-methodology/verify/counting-copies.md). Next: [34 - Moves and renames](https://banes-lab.com/disciplined-methodology/verify/moves-and-renames.md). It builds on [22 - One home](https://banes-lab.com/disciplined-methodology/build/one-home.md), [18 - The gate holds the line](https://banes-lab.com/disciplined-methodology/build/the-gate-holds-the-line.md).

This method treats documentation as code, and [H1·a every run](https://banes-lab.com/disciplined-methodology/verify#documentation-is-code-panel-a) shows what a document passes through. A document is typed, and it is placed by the same grammar described in [placement is a grammar](https://banes-lab.com/disciplined-methodology/build/placement-is-a-grammar.md). A check resolves its references, as shown in [H1·b a resolved reference](https://banes-lab.com/disciplined-methodology/verify#documentation-is-code-panel-b), so [traceability](https://banes-lab.com/records/arch/traceability.md) runs in both directions. A count in a document is derived rather than typed, and a document that drifts fails the same gate as the code. A module's overview is generated from the manifest the module owns and never written by hand, which is [manifest-based design](https://banes-lab.com/records/arch/manifest-based-design.md) taken literally; the manifest is typed in [H1·c a manifest](https://banes-lab.com/disciplined-methodology/verify#documentation-is-code-panel-c), and [H1·d compiled from four](https://banes-lab.com/disciplined-methodology/verify#documentation-is-code-panel-d) shows how the overview is assembled. Prose that cannot be parsed cannot be governed, so documentation is written in a form that can be.

### Typed, placed, parsed

Hand-written documentation is right on the day of writing and drifts every day after. The readme names a script that was renamed a month ago, and a new contributor runs it, gets nothing, and assumes the tooling is broken. Prose about code has no compiler, so nothing tells you when it stops being true.

For this reason documentation goes through the same typing, placement, parsing, validation and repair as any other code. The parseable form is written and the prose generated from it, rather than the prose written in the hope that it stays true. In practice, every document has a type, and the type selects its schema, its rules and its one computed location. Every reference points at an identifier and a path with a declared verb, and a check resolves both halves and fails on an undeclared verb rather than skipping it. Each module's overview is generated from a manifest the module owns, together with its derived public surface. No count is stated in prose. A scaling guide sits beside every system that has seams, and it is updated in the same change that adds a seam.

To check this, rename one file that the documents mention. The document gate should fail before anything else does, and a rename the documents survived is a rename they never mentioned. A generated document is exempt from the content scan and checked for drift instead, because the governed surface is the manifest it was generated from. The one way a generated document differs from generated source is its marker: generated source carries its marker in its name, while a generated document opens with a banner that the gate looks for.

### A path computed from three axes

A document's path is computed from three axes and never chosen. Its form says what it is, such as a guide, a reference, a contract, a template or a taxonomy. Its owner says which part of the tree it belongs to. Its name states the subject, prefixed by the activity verb where the form is directive. Because a document's location is a function of its declared type and its owner, one search finds every document of a type and every document an owner holds. A document is created through a tool that computes that location, and a filename that does not break down into these parts fails.

Every document has one audience, one purpose and one [abstraction](https://banes-lab.com/records/arch/abstraction.md) level, as with a behaviour policy, a codebase contract, a guide to extending one system, a reference to what is enforced, or a taxonomy that holds a standard and its vocabulary. Content that belongs to a different level moves to that level and is never duplicated. The test is to strip out the words that belong to the wrong level and ask whether the entry still says something at this one. A document that reads at two levels is two documents.

### References are constructs

A document points at code with a construct rather than a phrase: a declared verb, an identifier and a path. The gate resolves both halves, so the path has to exist, and the identifier has to be exported from, declared in or referenced in that file. An undeclared verb fails rather than being skipped, which is what stops a typo from making a reference invisible. Every claim a document makes about what it validates is backed by a real construct. Documents also form a [dependency graph](https://banes-lab.com/records/arch/dependency-graph.md): a document's name is its export, its edge fields are imports resolved through a registry, a superseded edge sets the target's status, and a duplicate name or a dead edge is a finding.

### The manifest is the editorial surface

A module's overview is generated, and the manifest is its whole editorial surface. Everything that can be derived is computed: the public surface from the declarations, the dependencies from the descriptor, the governing principles resolved by identity against the canon, and the diagrams from the module's own graph. A thin manifest is a bug. The content rules run on each field as rendered into its fragment and report against that field, and the generated document is checked for drift in both directions, so a hand edit is reverted on the next run.

The manifest is a typed record, and its type is what separates a stub from a document. The documentation block has a required core and expands itself: any further key renders as its own section without a change to the generator, so the type admits arbitrary lowercase keys beside the required ones. A quick start is runnable code with its intent and its language, never a sketch, and a validator holds every required field to its shape before anything is generated.

H1·a every run

```mermaid
flowchart TB
typed["Typed · the form selects the schema, the rules and the legal place"]
placed["Placed · one computed location from form, owner and name"]
parsed["Parsed · references are constructs with a verb, an identifier and a path"]
validated["Validated · every reference resolves, no count, no past tense"]
repaired["Repaired · bare paths healed, generated documents regenerated"]
typed --> placed --> parsed --> validated --> repaired
repaired -. on every run .-> typed
```

H1·b a resolved reference

```markdown
The placement check parses every path, see: `parsePath` "engine/matchers/path.matcher.ts"

The validator resolves both halves:
the path must exist
the identifier must be declared in that file

A verb it does not know fails the document rather than being skipped,
so a typo cannot make a reference invisible.
```

H1·c a manifest

```typescript
export interface Manifest {
readonly label: string;
readonly summary: string;
readonly maturity: "experimental" | "stable";
readonly domains: readonly { readonly meta: Domain; readonly sub: SubDomain }[];
readonly governedBy: readonly ConceptId[];
readonly entries: readonly string[];
readonly docs: {
readonly overview: string;
readonly whenToUse: readonly string[];
readonly whenNotToUse: readonly string[];
readonly quickStart: readonly { readonly intent: string; readonly lang: string; readonly code: string }[];
readonly configuration: string;
readonly disposal: readonly string[];
readonly aiContext: readonly string[];
readonly apiNotes?: readonly { readonly name: string; readonly note: string }[];
readonly [section: string]: unknown;
};
}
```

H1·d compiled from four

```mermaid
flowchart TB
manifest["The manifest · the authored surface"]
surface["The public surface · derived from the code"]
deps["The dependencies · derived from the descriptor"]
principles["The principles · resolved by identity against the canon"]
readme["The module document · generated, drift-checked, never edited"]
manifest --> readme
surface --> readme
deps --> readme
principles --> readme
readme -. a hand edit is reverted on the next run .-> manifest
```

## Links to

- [Placement is a grammar](https://banes-lab.com/disciplined-methodology/build/placement-is-a-grammar.md)
- [Traceability](https://banes-lab.com/records/arch/traceability.md)
- [Manifest-Based Design](https://banes-lab.com/records/arch/manifest-based-design.md)
- [Abstraction](https://banes-lab.com/records/arch/abstraction.md)
- [Dependency Graph](https://banes-lab.com/records/arch/dependency-graph.md)

## Linked from

- [The behaviour document](https://banes-lab.com/disciplined-methodology/start/the-behaviour-document.md)
- [Derived state](https://banes-lab.com/disciplined-methodology/verify/derived-state.md)

## Evidence in the code

- [markDocumentReferences](https://banes-lab.com/source/tree/presentation/components/source.component.ts.md)
- [documentBlocks](https://banes-lab.com/source/tree/domain/converters/document.converter.ts.md)
