@nurix/etna 0.20.25 → 0.20.26

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (72) hide show
  1. package/data/harness-index.json +1 -1
  2. package/data/harnesses/code/CLAUDE.md +4 -4
  3. package/data/harnesses/code/agents/bookkeeper.md +1 -1
  4. package/data/harnesses/code/agents/change-review.md +1 -1
  5. package/data/harnesses/code/agents/lld-mode.md +1 -1
  6. package/data/harnesses/code/agents/maintenance.md +7 -9
  7. package/data/harnesses/code/docs/structure.md +133 -71
  8. package/data/harnesses/code/harness.json +4 -4
  9. package/data/harnesses/code/hooks/awareness.mjs +0 -10
  10. package/data/harnesses/code/hooks/lib/ownership.mjs +4 -2
  11. package/data/harnesses/code/hooks/lib/sweep.mjs +4 -8
  12. package/data/harnesses/code/skills/documentation/SKILL.md +19 -8
  13. package/data/harnesses/code/skills/documentation/references/frontmatter.md +3 -3
  14. package/data/harnesses/code/skills/documentation/references/style-guide.md +70 -27
  15. package/data/harnesses/code/skills/documentation/references/untemplated.md +2 -1
  16. package/data/harnesses/code/skills/documentation/scripts/doc-lint.mjs +87 -1
  17. package/data/harnesses/code/skills/documentation/templates/Readme.md +4 -3
  18. package/data/harnesses/code/skills/documentation/templates/bookkeeping.md +1 -1
  19. package/data/harnesses/code/skills/documentation/templates/docs-readme.md +15 -36
  20. package/data/harnesses/code/skills/documentation/templates/doctrine.md +82 -0
  21. package/data/harnesses/code/skills/documentation/templates/feature.md +31 -123
  22. package/data/harnesses/code/skills/documentation/templates/handover.md +174 -0
  23. package/data/harnesses/code/skills/documentation/templates/operations-procedure.md +1 -1
  24. package/data/harnesses/code/skills/documentation/templates/package.md +28 -94
  25. package/data/harnesses/code/skills/documentation/templates/root-readme.md +103 -65
  26. package/data/harnesses/code/skills/documentation/templates/setup.md +138 -0
  27. package/data/harnesses/code/skills/documentation/templates/system.md +25 -109
  28. package/data/harnesses/delivery/agents/lld-mode.md +1 -1
  29. package/data/harnesses/delivery/agents/maintenance.md +7 -9
  30. package/data/harnesses/delivery/harness.json +2 -2
  31. package/data/harnesses/delivery/skills/documentation/SKILL.md +19 -8
  32. package/data/harnesses/delivery/skills/documentation/references/frontmatter.md +3 -3
  33. package/data/harnesses/delivery/skills/documentation/references/style-guide.md +70 -27
  34. package/data/harnesses/delivery/skills/documentation/references/untemplated.md +2 -1
  35. package/data/harnesses/delivery/skills/documentation/scripts/doc-lint.mjs +87 -1
  36. package/data/harnesses/delivery/skills/documentation/templates/Readme.md +4 -3
  37. package/data/harnesses/delivery/skills/documentation/templates/bookkeeping.md +1 -1
  38. package/data/harnesses/delivery/skills/documentation/templates/docs-readme.md +15 -36
  39. package/data/harnesses/delivery/skills/documentation/templates/doctrine.md +82 -0
  40. package/data/harnesses/delivery/skills/documentation/templates/feature.md +31 -123
  41. package/data/harnesses/delivery/skills/documentation/templates/handover.md +174 -0
  42. package/data/harnesses/delivery/skills/documentation/templates/operations-procedure.md +1 -1
  43. package/data/harnesses/delivery/skills/documentation/templates/package.md +28 -94
  44. package/data/harnesses/delivery/skills/documentation/templates/root-readme.md +103 -65
  45. package/data/harnesses/delivery/skills/documentation/templates/setup.md +138 -0
  46. package/data/harnesses/delivery/skills/documentation/templates/system.md +25 -109
  47. package/data/harnesses/etna/agents/change-review.md +1 -1
  48. package/data/harnesses/etna/agents/lld-mode.md +1 -1
  49. package/data/harnesses/etna/agents/maintenance.md +7 -9
  50. package/data/harnesses/etna/harness.json +2 -2
  51. package/data/harnesses/etna/skills/documentation/SKILL.md +19 -8
  52. package/data/harnesses/etna/skills/documentation/references/frontmatter.md +3 -3
  53. package/data/harnesses/etna/skills/documentation/references/style-guide.md +70 -27
  54. package/data/harnesses/etna/skills/documentation/references/untemplated.md +2 -1
  55. package/data/harnesses/etna/skills/documentation/scripts/doc-lint.mjs +87 -1
  56. package/data/harnesses/etna/skills/documentation/templates/Readme.md +4 -3
  57. package/data/harnesses/etna/skills/documentation/templates/bookkeeping.md +1 -1
  58. package/data/harnesses/etna/skills/documentation/templates/docs-readme.md +15 -36
  59. package/data/harnesses/etna/skills/documentation/templates/doctrine.md +82 -0
  60. package/data/harnesses/etna/skills/documentation/templates/feature.md +31 -123
  61. package/data/harnesses/etna/skills/documentation/templates/handover.md +174 -0
  62. package/data/harnesses/etna/skills/documentation/templates/operations-procedure.md +1 -1
  63. package/data/harnesses/etna/skills/documentation/templates/package.md +28 -94
  64. package/data/harnesses/etna/skills/documentation/templates/root-readme.md +103 -65
  65. package/data/harnesses/etna/skills/documentation/templates/setup.md +138 -0
  66. package/data/harnesses/etna/skills/documentation/templates/system.md +25 -109
  67. package/lib/install/materialize.mjs +4 -12
  68. package/lib/install/plan.mjs +4 -11
  69. package/package.json +3 -2
  70. package/data/harnesses/code/skills/documentation/templates/structure.md +0 -71
  71. package/data/harnesses/delivery/skills/documentation/templates/structure.md +0 -71
  72. package/data/harnesses/etna/skills/documentation/templates/structure.md +0 -71
@@ -7,7 +7,7 @@ description: "Use when creating or substantively editing ANY markdown doc — in
7
7
 
8
8
  **This skill is a template & generator library, not an orchestrator.** It supplies the templates, the frontmatter-derivation generator, and the co-authoring workflow that _agents_ call to produce individual docs. It does **not** baseline, audit, or reconcile a repo's doc tree — that is the **`maintenance` agent (baseline mode)**, which calls this skill for each template it scaffolds. Reach here to generate _one_ doc from a template; reach for the `maintenance` agent (baseline mode) to bring a whole repo into shape.
9
9
 
10
- Document contracts and architecture, not implementation details. Show function signatures and API shapes — never paste full implementations (they rot fast). Use ASCII diagrams over prose for flows. Only document state at persistence boundaries (Redux persistence, DB schemas, API shapes), not component-level or transient state. Mark deprecated fields with `// UNUSED:` comments stating why the field is dead now — never where it went or when it dies. Breaking changes belong in changelogs only, not module docs.
10
+ Document contracts and architecture, not implementation details. Signatures and API shapes belong in a reference document (an API reference, an environment registry); every other genre states design and promises and leaves mechanism to the code — never paste full implementations (they rot fast). Use ASCII diagrams over prose for flows. Only document state at persistence boundaries (Redux persistence, DB schemas, API shapes), not component-level or transient state. Mark deprecated fields with `// UNUSED:` comments stating why the field is dead now — never where it went or when it dies. Breaking changes belong in changelogs only, not module docs.
11
11
 
12
12
  ---
13
13
 
@@ -70,9 +70,14 @@ The two guarantees are complementary and both break on mixing: a reader holding
70
70
 
71
71
  - **Truth documents never narrate history** — the § Present tense, always rule above, applied to this nature. When the system changes, the change-story goes to `docs/history/` (a changelog entry) and the truth document simply becomes correct in present tense. When you find historical narration in a truth document, rewrite it to the present-tense fact and let the record carry the story.
72
72
  - **Records are never edited to match the present.** A completed plan stays wrong-in-hindsight; a changelog entry describes close-time state; a scope change gets a *new* dated record that links back, never an edit to a frozen one.
73
- - **Two sanctioned bridges — head is truth, tail is provenance.** An **Architecture Decision (AD)** ends with a **Decision Changelog** (for a decision, the journey — what each revision reversed and what triggered it — is part of the reasoning), and `docs/structure.md` ends with the maintenance agent's **Health Log** (tooling-stamped audit rows, the structural cousin of `last-reviewed:`). In both, the body stays current-truth-only; the tail carries the dates. No other truth document carries dated history.
73
+ - **Two sanctioned bridges — head is truth, tail is provenance.** An **Architecture Decision (AD)** ends with a **Decision Changelog** (for a decision, the journey — what each revision reversed and what triggered it — is part of the reasoning), and the `maintenance` agent's **Health Log** lives in `docs/history/health-log.md`, an append-only record. The AD body stays current-truth-only; the tail carries the dates. No other truth document carries dated history. `docs/structure.md` is harness-owned — written whole by the installer, never edited by hand or by a skill; only its `harness-version` frontmatter is stamped, by the `maintenance` agent.
74
+ - **Indexes describe directories, never files.** `docs/README.md` — the top-level index of the documentation folder — is a description of its directories: one entry per folder saying what the folder holds, who reads it and how its files are named. It carries no file list and no file tree: not a per-file row, not a `├──` tree of files, not a tree at all — `docs/structure.md` is the one place the tree lives, as the authority on placement. The same holds for a `README.md` / `Readme.md` at any level of `docs/`. `ls` is the roster, and the ownership index is how a document is found for a path. A per-file row has to be edited on every add, rename and retirement, so the index's history records roster churn instead of what the index said, and a reader cannot tell when the index itself changed. The only files an index may link are the mandated scaffolds (`structure.md`, `operations/setup.md`, `history/CHANGELOG.md`, `history/backlog.md`, `memory/main.md`) and a sibling folder's own `Readme.md`. `scripts/doc-lint.mjs` blocks the rest as `index-lists-files`, and blocks a tree drawn in a folder index as `index-file-tree`. An inverse (which checklists verify a feature, which docs a folder holds) is generated, never written.
74
75
  - **Truth documents cite records for the _why_, never the _when_.** `Provenance: AD-002` is good; "decided in AD-002 and shipped 2026-06-13" is not. Routing/index docs point only to truth documents as a topic's authority — never a plan or changelog entry as the "read first" source. (An index _of the records themselves_ — a History section listing `plans/`, `changelog/` — is sanctioned.)
75
76
 
77
+ **A document is intent and promises; facts are the graph's.** An owning document (feature, package, system) answers why the product is shaped this way and what it promises, and names the objects it designs in `objects:`. Every computable fact — a table's columns and vocabularies, a foreign key and its delete rule, which function writes which column, which route sits behind which guard, which code a refusal answers, which file holds what — is the code graph's to compute (`docs/architecture/systems/knowledge-layer.md`), and a hand-typed copy of it is the defect this rule removes: it reads as authoritative and is wrong the day the code moves. Mechanism stays in the code, reasons stay in the document, and the document points by object and symbol name, never by line number. `doc-lint` blocks the retired mechanism sections in an owning document (`mechanism-section`) and an owning document without `objects:`. `keywords:` is not a key: an object's name is its discovery term. **The body is read by people** — plain English a newcomer reads top to bottom, with code named only at a cross-cutting seam the graph would not lead a reader to from the feature's own files (a middleware, a gate, a hook, a shared store) and every other identifier in the closing **For the agent** footer; the owning genres read Why it exists · How it works · What was decided · What it promises · Known gaps · For the agent (`references/style-guide.md` § Documents are read by people; `doc-lint` warns `body-identifier`, `list-not-prose`, `formula-run`).
78
+
79
+ **Every document that explains is written from the outside in, and every sentence passes the stability test.** Open on the question and its boundary, then the model with its numbered principles, then the parts and how they relate, then each part's decisions — and stop at the genre's deepest layer: decisions for doctrine, cross-package behaviour for a system, the public contract for a package, the full user-facing behaviour for a feature. A sentence that would have to change when a function is renamed, a file moves, or a route, column or error code changes is the code's, not the document's. The code is the authority on *what*; the document is the authority on *why*, and a disagreement on *why* is a defect to raise. The layers, the test and the per-genre depth table are [`references/style-guide.md`](references/style-guide.md) § Shape — the model first, the detail after.
80
+
76
81
  **No empty stubs.** Never leave a template section as an empty placeholder — omit any section with nothing real to say (each template declares its required core; everything else is optional). Write an explicit "None" only where the absence itself is information (e.g., a plan's Cross-Module Contracts Affected, an LLD's Ownership Conflicts). An empty table stub reads as "not yet researched"; an omitted section reads as "doesn't apply" — keep those meanings distinct.
77
82
 
78
83
  **No redirect docs.** When moving a doc to a new location, delete the old file entirely. Update all references (cross-doc links, memory files) to point to the new path. Never leave a stub file that says "Moved to X" — redirect docs rot, clutter the repo, and create false search hits.
@@ -87,6 +92,7 @@ The two guarantees are complementary and both break on mixing: a reader holding
87
92
  | Document feature/module (LLD) | [`templates/feature.md`](templates/feature.md) |
88
93
  | Document data flow / state / Redux | [`templates/feature.md`](templates/feature.md) — they are sections of the feature doc |
89
94
  | Document a workspace package (`docs/architecture/packages/{package}.md`) | [`templates/package.md`](templates/package.md) — the **residual** owner of `packages/{name}/**`: its manifest, build, entry, layout and every behavior no system or feature doc claims at higher specificity |
95
+ | Document one concern the platform handles everywhere (`docs/architecture/common/{concern}.md`) — authentication, storage, the API protocol | [`templates/doctrine.md`](templates/doctrine.md) — the design and its principles, no mechanism; owns no code, and surfaces bind to it through `applies:` |
90
96
  | Document one system spanning packages (`docs/architecture/systems/{system}.md`) | [`templates/system.md`](templates/system.md) — one machine end to end; its `owns:` names the machine's subtrees, narrower than the package glob, so it wins by specificity. Not a screen — a system doc written as a giant feature doc is the mistake it prevents |
91
97
  | Create/update changelog entry | [`templates/changelog-entry.md`](templates/changelog-entry.md) (record — one per unit of work; carries the refinement fields, frozen inside its commit, distilled by the `retro` agent) |
92
98
  | Create/update plan | [`templates/plan.md`](templates/plan.md) (record) |
@@ -102,14 +108,16 @@ The two guarantees are complementary and both break on mixing: a reader holding
102
108
  | What a person sees and can do on a surface (UX behavior) | [`templates/ux-behavior.md`](templates/ux-behavior.md) — decides observable behavior BEFORE the code; per-surface in `docs/features/{surface}-ux.md` owning the component globs, cross-cutting in `docs/architecture/`. Not the checklist, which only verifies it |
103
109
  | Behavioral checklist for one feature (`docs/tests/{feature}.md`) | [`templates/behavioral-checklist.md`](templates/behavioral-checklist.md) — the verification gate's driving script, and the source its suite tests are drawn from |
104
110
  | Acceptance criteria for one capability (`docs/acceptance/{capability}.md`) | [`templates/acceptance-criteria.md`](templates/acceptance-criteria.md) — the promises the built product must keep, as stable `AC-n` keyed assert lines verification surfaces parse as claims |
105
- | Recurring procedure/setup | [`templates/operations-procedure.md`](templates/operations-procedure.md) |
111
+ | Machine setup / first run / stack (one per repo, `docs/operations/setup.md`) | [`templates/setup.md`](templates/setup.md) |
112
+ | Recurring procedure (develop, deploy, rotate, diagnose) | [`templates/operations-procedure.md`](templates/operations-procedure.md) |
106
113
  | Cold-start build order (implementation map) | [`templates/implementation-map.md`](templates/implementation-map.md) — authored by the executing session at build start, updated in place as waves complete |
107
114
  | Capture mid-execution knowledge (`docs/history/journal.md`) | [`templates/journal.md`](templates/journal.md) (record — append-only; a row resolves by landing in its owning doc) |
108
115
  | Bookkeeping work queue (`docs/operations/bookkeeping.md`) | [`templates/bookkeeping.md`](templates/bookkeeping.md) — machine-read row grammar; appended by hooks and sessions, drained by the `bookkeeper` agent, walled at Stop and commit |
109
116
  | One-shot migration/upgrade | [`templates/migration-runbook.md`](templates/migration-runbook.md) (record) |
117
+ | Hand-over at the end of an unattended or multi-session build (`docs/history/handovers/YYYY-MM-DD-{slug}.md`) | [`templates/handover.md`](templates/handover.md) (record) — a decision queue, an undo manual and a resume file: a verdict token and scoreboard, the acts only the owner can take today, everything that left the repository with its exact undo, a ten-minute path to seeing it work, every ruling taken on the owner's behalf with its authority and how to overturn it; then the successor half — proof, state re-provable by command, open loops, discoveries |
110
118
  | Add to protected files | [`templates/protected-files.md`](templates/protected-files.md) |
111
- | Create/update root README | [`templates/root-readme.md`](templates/root-readme.md) |
112
- | Scaffold a standard doc (docs index, `structure.md`, CHANGELOG, backlog, memory) | [`templates/Readme.md`](templates/Readme.md) — the index names each scaffold file |
119
+ | Create/update root README (outward opening in a user's terms, then orientation and routing for the team and agents — no install, stack, tree or chrome) | [`templates/root-readme.md`](templates/root-readme.md) |
120
+ | Scaffold a standard doc (docs index, CHANGELOG, backlog, memory) | [`templates/Readme.md`](templates/Readme.md) — the index names each scaffold file; `structure.md` is the installer's, never scaffolded |
113
121
  | Derive/update an owning doc's `owns:` (feature, package, system) | [`references/frontmatter.md`](references/frontmatter.md) |
114
122
  | Update existing doc | § Editing an existing doc (below) |
115
123
  | Instruction file (`CLAUDE.md`, a rule, an agent, skill prose) | [`references/instruction-style.md`](references/instruction-style.md) — not these templates; every-load prose stays lean, and the present-tense rule still applies |
@@ -135,6 +143,7 @@ The two guarantees are complementary and both break on mixing: a reader holding
135
143
  | Feature (LLD) | Truth | `kebab-case.md` | Living; `status:` `draft` → `active` → `deprecated` |
136
144
  | Package | Truth | `{package-folder}.md` | Living; `status:` as the feature doc |
137
145
  | System | Truth | `{machine}.md` | Living; `status:` as the feature doc |
146
+ | Doctrine | Truth | `{concern}.md` | Living; `status:` `draft` → `active` |
138
147
  | Architecture Decision | Truth | `AD-NNN-kebab-case.md` | Living; `Proposed` → `Accepted` → `Deprecated`; revisions rewrite the body + append to its Decision Changelog |
139
148
  | Steering docs (overview, domain model, glossary, non-goals, security, testing strategy) | Truth | fixed names | Living |
140
149
  | API reference / environment registry | Truth | fixed names | Living |
@@ -153,11 +162,13 @@ The two guarantees are complementary and both break on mixing: a reader holding
153
162
  **Frontmatter is compulsory on every document this skill authors** — `type:` (the genre) on every
154
163
  doc, plus the genre's own keys beside it; a document without its frontmatter fails the skill's
155
164
  contract and is not done. **There is no frontmatter-less genre.** A feature or UX doc carries the
156
- full set — `owns:` (required), `module:` (optional), `keywords:` (required), `status:` (required),
165
+ full set — `objects:` (required — the product objects the document designs), `owns:` (required until the graph computes ownership), `module:` (optional), `status:` (required),
157
166
  `applies:` (the architecture docs it obeys; omitted when none), optional `last-reviewed:`. A
158
167
  **package** doc (`docs/architecture/packages/`) and a **system** doc (`docs/architecture/systems/`)
159
168
  carry the same set minus `module:` — a package is already a bounded unit and a machine spanning
160
- packages belongs to no single context. A behavioral checklist (`docs/tests/`) carries
169
+ packages belongs to no single context. A **doctrine** doc (`docs/architecture/common/`)
170
+ carries `type: doctrine`, `status:` and `objects:` — no `owns:`, because doctrine governs code
171
+ without claiming it. A behavioral checklist (`docs/tests/`) carries
161
172
  `type: checklist` and `verifies:` — the doc whose promises it proves. An acceptance-criteria doc
162
173
  (`docs/acceptance/`) carries `type:` and `status:`.
163
174
 
@@ -177,7 +188,7 @@ update, and the `maintenance` agent's baseline pass, route there.
177
188
  | `templates/` | One file per template, indexed by [`Readme.md`](templates/Readme.md) — feature (LLD), changelog, plan, AD, steering docs, API reference, environment registry, operations procedure, migration runbook, protected files, READMEs, and the baseline scaffolds |
178
189
  | `references/style-guide.md` | Writing rules, formatting conventions, the two-natures tense rules |
179
190
  | `references/instruction-style.md` | The style for instruction files (`CLAUDE.md`, rules, agents, skill prose) — the every-line test, armor vs. narration, voice, negative space |
180
- | `references/frontmatter.md` | Deriving a feature doc's `owns:` / `module:` / `keywords:` / `status:` from code |
191
+ | `references/frontmatter.md` | Deriving a feature doc's `objects:` / `owns:` / `module:` / `status:` from code |
181
192
  | `references/untemplated.md` | How to write a document no template covers (nature, placement, shape) + the co-authoring workflow |
182
193
  | `references/examples.md` | Good vs bad documentation examples |
183
194
  | `scripts/doc-lint.mjs` | Mechanical checks over written docs (tense narration, dates, stubs, redirects) — run over changed docs before finishing |
@@ -32,7 +32,7 @@ Every other genre owns no code and carries no `owns:`. That includes the cross-c
32
32
 
33
33
  ## How to derive the frontmatter
34
34
 
35
- An owning doc's ownership frontmatter is `owns:` (required), `module:` (optional — feature docs only; a package is already a bounded unit and a system spans contexts by definition), `keywords:` (required), and `status:` (required). An optional `last-reviewed:` date (stamped whenever the doc is substantively reviewed or updated) gives the `maintenance` agent a staleness signal to rank its audits by — it is tooling metadata, never narrated in the body. `type:` (required — the genre, enum = the template names) and `rev:` (generator-written generation stamp) are the same class: external tooling reads them, sessions **preserve them on edits** and never narrate or inject them. The `maintenance` agent stamps `type:` on docs that predate the key. `slug:` completes the set on generated docs: the identity key, minted once at creation and never re-derived from a display name — in the repo the filename is the slug, and the `maintenance` agent re-aligns the two when they diverge.
35
+ An owning doc's frontmatter is `objects:` (required — the product objects it designs, by their graph names; its discovery terms and its traced edge into the knowledge graph), `owns:` (required until the graph computes ownership from traces), `module:` (optional — feature docs only; a package is already a bounded unit and a system spans contexts by definition), and `status:` (required). An optional `last-reviewed:` date (stamped whenever the doc is substantively reviewed or updated) gives the `maintenance` agent a staleness signal to rank its audits by — it is tooling metadata, never narrated in the body. `type:` (required — the genre, enum = the template names) and `rev:` (generator-written generation stamp) are the same class: external tooling reads them, sessions **preserve them on edits** and never narrate or inject them. The `maintenance` agent stamps `type:` on docs that predate the key. `slug:` completes the set on generated docs: the identity key, minted once at creation and never re-derived from a display name — in the repo the filename is the slug, and the `maintenance` agent re-aligns the two when they diverge.
36
36
 
37
37
  **1. `owns:`** (the path scope)
38
38
 
@@ -59,9 +59,9 @@ Glob each pattern against the codebase. At `status: active`, drop any that match
59
59
 
60
60
  The single bounded-context label this feature belongs to, or omit it for a cross-cutting feature that belongs to no single context. A module is a label, not a folder — features sharing a `module:` value are what ties that module to code (a filter over the generated ownership index). Package and system docs omit it entirely.
61
61
 
62
- **3. `keywords:` & `status:`**
62
+ **3. `objects:` & `status:`**
63
63
 
64
- `keywords:` are the discovery terms topic→doc lookup rides. `status:` is `active`, `draft`, or `deprecated` — it steers the model toward live docs and away from draft/deprecated ones.
64
+ `objects:` names the product objects the document designs — the discovery terms topic→doc lookup rides, and the edge the knowledge graph renders each object's documents from. There is no `keywords:` key: an object's name is its discovery term. `status:` is `active`, `draft`, or `deprecated` — it steers the model toward live docs and away from draft/deprecated ones.
65
65
 
66
66
  ## The doc → doc edges
67
67
 
@@ -271,6 +271,67 @@ Two verbosity regimes, split by who pays for the words. **Instruction files** (`
271
271
  - **Inline links are the minimum that action requires.** Link mid-prose only where the reader must go there to act on this page. Every other sister document — everything the topic touches — belongs in one **Related** (or **References**) section at the document's end.
272
272
  - **The Related tail is the document's entire link surface.** Deep relative paths (`../../../../…`) are fragile — a folder move breaks every one — so they are confined to that one block, where a path change touches one place; body mentions use the plain name (`the boundary skill`, `structure.md`) instead of a link.
273
273
 
274
+ ## Shape — the model first, the detail after
275
+
276
+ Every truth document a person reads to understand something — doctrine, system, package, feature — is written **from the outside in**. It opens on the model and adds detail in layers, so a reader who stops at any layer holds a picture that is coarse but true, never a teaser that only the next section makes sense of. The failure this prevents is a document written at one density from its first word: an inventory table before the reader knows what is being inventoried, and the principles that summarize it arriving last, where nobody reads them.
277
+
278
+ **The layers, in order:**
279
+
280
+ 1. **The question and its boundary.** The first paragraph says what question this document answers, and which neighbouring documents answer the questions next to it. No addresses, file paths or configuration in it.
281
+ 2. **The model.** What the thing is in a page: the parties or parts, the one or two axes that organize them, and the invariants that hold everywhere — numbered, each with its reason, so later sections can cite them ("principle 3").
282
+ 3. **The parts.** One table or diagram that places every part in the model, then how the parts relate: what they share, where they meet, and what keeps them apart.
283
+ 4. **Each part in turn.** For each part, the decisions it rests on and why. Each section opens with why the part exists, not with how it is built.
284
+ 5. **The genre's deepest layer**, from the table below, and nothing deeper.
285
+
286
+ **The stability test decides what a sentence may say.** Ask whether the sentence would have to change if a function were renamed, a file moved, a route, column, cookie attribute or error code changed, or a constant was retuned without the design changing. If it would, it fails. The fact belongs to the code, and the code graph computes it on demand (`docs/architecture/systems/knowledge-layer.md`). A copy typed here is at best a duplicate of the code and at worst a stale one, which misleads the next agent more than no document would. It also has to be found and re-edited on every change to the code beneath it.
287
+
288
+ These survive the test:
289
+
290
+ - **Reasons.** Why the design is this way, and what would break otherwise.
291
+ - **Invariants.** What must hold everywhere.
292
+ - **Decisions and the alternatives a reader would reach for.**
293
+ - **Promises a person or a test can check.**
294
+ - **Contracts that span components no single file shows.** For example, two clients that must classify the same answer identically.
295
+ - **Decided-but-unbuilt intent.** The code cannot reveal what it does not yet do.
296
+
297
+ **The code is the authority on *what*; the document is the authority on *why*.** A document that disagrees with the code about what happens is simply stale, and the code wins. A disagreement about why, or about an invariant, is a defect to raise with the owner, because one of the two is wrong on purpose. State this in the opening of any document whose readers include agents.
298
+
299
+ **Each genre has its own deepest layer.** The shape above is common to every genre; how far down a genre may go differs:
300
+
301
+ | Genre | Deepest layer | Stops before |
302
+ | --- | --- | --- |
303
+ | Doctrine (`architecture/common/`) | The decisions behind each part, and the reasons for them | Any mechanism. A doctrine document describes no code |
304
+ | System (`architecture/systems/`) | How the machine behaves across packages: sequence and state diagrams, the invariants at each place where parts meet, what re-drives a stall. No single file shows a cross-package flow, so this layer earns its place | Per-function steps; tables and columns; routes |
305
+ | Package (`architecture/packages/`) | The public contract a consumer touches: commands and their flags, exports, what is installed and where. For a CLI the flags *are* the promise | Internal layout; the build's steps; which file holds what |
306
+ | Feature (`features/`) | The behaviour a person meets, in full: each state the surface can be in, each edge case, what a refusal tells them, wording where the wording is promised. **This genre runs deepest toward its end**, because a promise is checked by a person or a test, not computed from code | Columns, routes, guards, functions, files |
307
+ | Reference (API reference, environment registry) | The contract itself: signatures, shapes, variables | Nothing. The detail is the point |
308
+ | Operations procedure, runbook | The exact commands, in order | Nothing. The detail is the point |
309
+
310
+ **A diagram belongs to a layer.** At the model and parts layers it names roles ("the browser", "the auth service"), never a URL, a header or a file. A diagram drawn from the code's names belongs to the code graph.
311
+
312
+ **Length is a signal, not a target.** A document whose reference tail is longer than its body is an inventory with an introduction. A doctrine document past about three hundred lines has usually let mechanism in.
313
+
314
+ ## Documents are read by people; the footer is for the agent
315
+
316
+ A document that explains something — a doctrine, an owning document (feature, package, system) — is prose a person reads top to bottom. It takes the shape above (§ Shape — the model first, the detail after). The rules:
317
+
318
+ - **The body is plain English.** It says what the thing is, why it is shaped that way, how a person meets it, and what it promises. Bullets and tables are for enumerable facts only — never for an argument, a decision or a promise. No sentence shape repeats down a list; a section whose entries share one shape is rewritten as paragraphs.
319
+ - **Name code only where the graph would not lead a reader there.** The code graph answers what a feature's own files call, so those names add nothing. What it cannot answer from the feature's files is the seam that runs the other way: a middleware, a gate, a hook, a scheduler tick, a shared store holding part of the feature's logic because that logic is global. Write that reference by name, once, where the narrative leaves the feature. Everything else is a plain name — "the device registry", "the sign-off page", "the mirror".
320
+ - **A term of art is introduced in plain words the first time it appears.**
321
+ - **Bold marks a defined term's first appearance at most** — never a noun mid-sentence. An em-dash is a budget, one per paragraph, not a joint between clauses.
322
+ - **A gap the code does not close is one Known gaps paragraph, or a backlog row.** Never a ledger row inside the body, never a temporal hedge.
323
+ - **The first line under the title is the goal.** No plan link, no routing line above it.
324
+ - **The footer, "For the agent", is a set of pointers, not an inventory.** It holds four things:
325
+ 1. The objects, with a one-line definition each.
326
+ 2. The code roots, as directories, where the graph should start.
327
+ 3. The cross-cutting seams, by name.
328
+ 4. The checklist, and the neighbouring documents with a purpose for each.
329
+
330
+ A feature adds its pages, because an address is what a person points at. A package adds its commands, because those are its public contract. Tables, routes, symbol rosters and file lists do not belong in the footer any more than in the body. The footer obeys the stability test (§ Shape) like every other line, and a footer that grows with every function is the inventory moved down the page.
331
+ - **"How it works" is narrative, not mechanism.** It says that a forgotten machine comes back on its next call, not which function re-mints the row. Behaviour in plain words is intent made legible; columns, routes, guards and signatures are the graph's.
332
+
333
+ The Mechanics rules below ("inline-code every identifier", "bold assertion — explanation") bind instruction files and operations procedures, not doctrine or the owning genres.
334
+
274
335
  ---
275
336
 
276
337
  ## The Two Natures — Tense & History
@@ -334,38 +395,19 @@ Worked example of the strip-and-relocate move: [`examples.md`](examples.md) Exam
334
395
 
335
396
  ### Standard Layout
336
397
 
398
+ An owning document (feature, system, package) takes its shape from its template — Goal · Why it exists · How it works · What was decided · What it promises · Known gaps · For the agent — and a doctrine document from `templates/doctrine.md` — the question · The model · The parts · one section per part · For the agent. Neither is ever a code tour: no Architecture, Key Functions, State or Files section (§ Shape — the model first, the detail after; § Documents are read by people). The layout below is for a **reference document** that is not an owning genre — an API reference, an environment registry, a procedure's appendix — where a signature or a file list is the content itself:
399
+
337
400
  ```markdown
338
401
  # [Title]
339
402
 
340
403
  **Goal:** One-line purpose
341
404
 
342
- ## Architecture
343
-
344
- [Diagram + explanation]
345
-
346
- ## Key Functions
347
-
348
- [Signatures and contracts]
349
-
350
- ## State
405
+ ## [Contract or procedure sections]
351
406
 
352
- [Persistence shapes]
353
-
354
- ## Files
355
-
356
- [Source file list]
407
+ [Signatures, shapes, steps — the content the reader came for]
357
408
  ```
358
409
 
359
- ### File References
360
-
361
- Always end with:
362
-
363
- ```markdown
364
- ## Files
365
-
366
- - `src/path/main.js` - Core logic
367
- - `src/path/hooks.js` - React hooks
368
- ```
410
+ A file roster belongs in no document: the ownership index and the code graph answer "which file" for every genre.
369
411
 
370
412
  ---
371
413
 
@@ -373,12 +415,13 @@ Always end with:
373
415
 
374
416
  | Aspect | Rule |
375
417
  | ---------- | ------------------------------- |
376
- | Functions | Always include signatures |
418
+ | Functions | Signatures in reference docs only — an owning document names a symbol in its footer |
377
419
  | Parameters | Type + purpose |
378
420
  | Returns | Type + shape |
379
421
  | State | Persistence points only |
380
422
  | Diagrams | ASCII for structure at rest, mermaid for behaviour over time — docs only, never instruction files |
381
423
  | Code | Under 15 lines, contracts only |
382
424
  | Voice | Imperative/active |
383
- | Mechanics | Inline-code identifiers; bold-assertion bullets |
384
- | Length | Concise, one line when possible |
425
+ | Mechanics | Instruction files and procedures: inline-code identifiers, bold-assertion bullets. Doctrine and owning documents: plain prose, pointers in the footer |
426
+ | Shape | The model first, the detail after; every sentence passes the stability test; each genre stops at its deepest layer (§ Shape) |
427
+ | Length | Concise; a paragraph is one line — never hard-wrap prose (`.prettierrc.json` keeps `proseWrap: never`) |
@@ -25,7 +25,8 @@ When a draft wants to be both — the current state *and* the story of getting t
25
25
  - **Headings are retrieval keys.** Sections get pulled out of context by search and agents; qualify generic headings with the topic (`## Merge rules — data sync`, not `## Rules`) so each stands alone.
26
26
  - **Tables for enumerable facts, prose for judgment.** One row per item; anything needing a *because* lives in prose around the table, never inside a cell.
27
27
  - **Every section earns its place.** No empty stubs — omit what has nothing real to say; write an explicit "None" only where the absence itself is information.
28
- - **Cite sources and link neighbours.** If the document mentions a concept another document owns, link it; if it draws on code, name the files.
28
+ - **Build from the outside in.** The question and its boundary, then the model, then the parts, then the detail — and nothing that fails the stability test (`references/style-guide.md` § Shape — the model first, the detail after). An explanation of a concern the whole platform handles is not untemplated: it is `templates/doctrine.md`.
29
+ - **Cite sources and link neighbours.** If the document mentions a concept another document owns, link it; if it draws on code, name the directory it lives in — the code graph finds the files, and a file list goes stale.
29
30
 
30
31
  ## 4. Write it in the house style
31
32
 
@@ -119,11 +119,97 @@ function lintFile(path, findings) {
119
119
 
120
120
  // A folder index (Readme.md/README.md) is a browse page, not a feature doc — it owns no code.
121
121
  const isFolderIndex = /(^|\/)(readme)\.md$/i.test(path);
122
+
123
+ // An index names folders, never files (SKILL.md § The Two Natures). A link from a folder index or
124
+ // the authority map to an individual document is a row that must be edited on every add, rename
125
+ // and retirement; the only files an index may link are the mandated scaffolds and a sibling
126
+ // folder's own Readme.
127
+ const isAuthorityMap = /(^|\/)docs\/structure\.md$/.test(path);
128
+ const isRootReadme = /^(\.\/)?README\.md$/i.test(path.replace(process.cwd() + '/', ''));
129
+ if (scope === 'truth' && (isFolderIndex || isAuthorityMap) && !disabled.has('index-lists-files')) {
130
+ const SCAFFOLD = /(^|\/)(readme|structure|changelog|backlog|main|health-log|journal|claude|agents)\.md$|(^|\/)operations\/setup\.md$/i;
131
+ for (const { n, line } of lines) {
132
+ if (line.includes('doc-lint-disable: index-lists-files')) continue;
133
+ for (const m of line.matchAll(/\]\(([^)\s#]+\.md)(#[^)]*)?\)/g)) {
134
+ const target = m[1];
135
+ if (/^[a-z]+:\/\//.test(target) || SCAFFOLD.test(target)) continue;
136
+ // The repo-root README routes by intent (templates/root-readme.md): its Map names owning package and system
137
+ // docs, its Where-to-go rows name procedures and rules. Individual feature docs stay off it — the ownership index finds them.
138
+ if (isRootReadme && /(^|\/)docs\/(architecture\/(packages|systems|common)\/|operations\/)[^/]+\.md$|(^|\/)\.claude\/rules\/[^/]+\.md$/.test(target)) continue;
139
+ if (isRootReadme && /(^|\/)docs\/features\/[^/]+\.md$/.test(target)) { findings.push({ path, n, severity: 'warn', id: 'root-readme-feature-link', message: `root README links an individual feature doc (\`${target}\`) — point at docs/features/ and let the ownership index find it`, excerpt: line.trim().slice(0, 90) }); continue; }
140
+ findings.push({ path, n, severity: 'block', id: 'index-lists-files', message: `index links an individual document (\`${target}\`) — name the folder and how its files are named; \`ls\` is the roster`, excerpt: line.trim().slice(0, 90) });
141
+ }
142
+ }
143
+ }
144
+ // A folder index describes directories; a drawn tree is a file roster in another costume
145
+ // (SKILL.md § Indexes describe directories, never files). structure.md is the authority map and keeps its tree.
146
+ if (scope === 'truth' && isFolderIndex && (isRootReadme || /(^|\/)docs\//.test(path)) && !disabled.has('index-file-tree')) {
147
+ // Raw lines, not proseLines: a tree is drawn inside a code fence, which proseLines drops. The repo-root README routes by a Map table; its tree is docs/structure.md's too (templates/root-readme.md).
148
+ const rawLines = text.split('\n').map((line, i) => ({ n: i + 1, line }));
149
+ const tree = rawLines.find(({ line }) => /^\s*[│├└]/.test(line));
150
+ if (tree) findings.push({ path, n: tree.n, severity: 'block', id: 'index-file-tree', message: 'a tree drawn in a folder index — describe each directory in a sentence; the tree is docs/structure.md\'s', excerpt: tree.line.trim().slice(0, 90) });
151
+ }
152
+ // The repo-root README is an orientation page with a budget (templates/root-readme.md): up to about 140 non-blank lines, plain Markdown, no chrome.
153
+ if (scope === 'truth' && isRootReadme) {
154
+ const raw = text.split('\n');
155
+ const nonBlank = raw.filter((l) => l.trim()).length;
156
+ if (!disabled.has('root-readme-budget') && nonBlank > 140) findings.push({ path, n: 1, severity: 'warn', id: 'root-readme-budget', message: `${nonBlank} non-blank lines — the root README orients and routes; a section that needs a paragraph needs a doc (templates/root-readme.md)` });
157
+ const chrome = raw.findIndex((l) => /shields\.io|<img\b|<div\b|<p align|^!\[/.test(l));
158
+ if (!disabled.has('root-readme-chrome') && chrome !== -1) findings.push({ path, n: chrome + 1, severity: 'block', id: 'root-readme-chrome', message: 'badge, image or HTML layout in the root README — agents cannot read it and the team does not need it', excerpt: raw[chrome].trim().slice(0, 90) });
159
+ }
122
160
  if (scope === 'truth' && !isFolderIndex && /(^|\/)docs\/features\/[^/]+\.md$/.test(path)) {
123
161
  const fm = text.startsWith('---') ? text.slice(0, text.indexOf('\n---', 3)) : '';
124
- for (const key of ['owns:', 'keywords:', 'status:', 'type:'])
162
+ for (const key of ['owns:', 'status:', 'type:'])
125
163
  if (!fm.includes(key)) findings.push({ path, n: 1, severity: 'block', id: 'feature-frontmatter', message: `feature doc missing \`${key}\` frontmatter` });
126
164
  }
165
+
166
+ // An owning document (feature, package, system) is intent and promises; the sections that narrate
167
+ // mechanism — a file roster, a walk through the code, a schema or route table — are the graph's
168
+ // to compute and are retired from the genre (SKILL.md § A document is intent and promises).
169
+ const isOwningDoc = scope === 'truth' && !isFolderIndex && /(^|\/)docs\/(features|architecture\/(packages|systems))\/[^/]+\.md$/.test(path);
170
+ if (isOwningDoc && !disabled.has('mechanism-section')) {
171
+ const RETIRED = /^#{2,4}\s+(Files|Current Behavior|Key Functions|Data|API|Refusals?|Architecture|State|Redux|Affected Modules|Conventions to Follow|Ownership Conflicts|Tests|The shape|Layout|Build and test|Commands|Routes|Schema|Wire)\b/i;
172
+ for (const { n, line } of lines) {
173
+ if (!RETIRED.test(line) || line.includes('doc-lint-disable: mechanism-section')) continue;
174
+ findings.push({ path, n, severity: 'block', id: 'mechanism-section', message: 'mechanism section in an owning document — columns, routes, guards, functions and files are the graph\'s to compute; keep the decision or the promise, point by name, cut the rest', excerpt: line.trim().slice(0, 90) });
175
+ }
176
+ const fm = text.startsWith('---') ? text.slice(0, text.indexOf('\n---', 3)) : '';
177
+ if (!/^objects:/m.test(fm)) findings.push({ path, n: 1, severity: 'block', id: 'objects-missing', message: 'owning document names no `objects:` — the product objects it designs are its edge into the graph and its discovery terms' });
178
+ }
179
+
180
+ // The body of an owning document is read by people; its "For the agent" footer is the reference
181
+ // surface (style-guide § Documents are read by people). These three warn, never block: a seam
182
+ // reference is allowed in the body, and the judgment of which identifier is a seam is the author's.
183
+ if (isOwningDoc) {
184
+ const OLD_SHAPE = /^##\s+(Background|Decisions|Promises|Objects|Related)\s*$/;
185
+ const footerAt = lines.findIndex(({ line }) => /^##\s+For the agent\b/.test(line));
186
+ const body = footerAt === -1 ? lines : lines.slice(0, footerAt);
187
+ let section = null; // proseLines already dropped the frontmatter and the fences
188
+ const sections = [];
189
+ for (const { n, line } of body) {
190
+ if (/^##\s+/.test(line)) {
191
+ if (!disabled.has('old-shape-section') && OLD_SHAPE.test(line)) findings.push({ path, n, severity: 'warn', id: 'old-shape-section', message: 'second-shape heading — the owning genres now read Why it exists · How it works · What was decided · What it promises · Known gaps · For the agent', excerpt: line.trim() });
192
+ section = { n, title: line.replace(/^##\s+/, '').trim(), bullets: 0, lines: 0, ids: 0, boldRun: 0, maxRun: 0 };
193
+ sections.push(section);
194
+ continue;
195
+ }
196
+ if (!section || !line.trim()) { if (section) section.boldRun = 0; continue; }
197
+ section.lines++;
198
+ const isBullet = /^\s*[-*]\s+/.test(line);
199
+ if (isBullet) section.bullets++;
200
+ if (/^\s*[-*]\s+\*\*/.test(line)) { section.boldRun++; section.maxRun = Math.max(section.maxRun, section.boldRun); } else section.boldRun = 0;
201
+ for (const m of line.matchAll(/`([^`]+)`/g)) {
202
+ const t = m[1];
203
+ if (/[\/]|\.(ts|tsx|mjs|js|md|json|sql)$|_|\(|^[a-z]+[A-Z]|^[A-Z][a-z]+[A-Z]|^(GET|POST|PUT|PATCH|DELETE) /.test(t)) section.ids++;
204
+ }
205
+ }
206
+ for (const s of sections) {
207
+ if (/^(Ownership|Known gaps)$/.test(s.title)) continue;
208
+ if (!disabled.has('body-identifier') && s.ids > 3) findings.push({ path, n: s.n, severity: 'warn', id: 'body-identifier', message: `${s.ids} code identifiers in a body section — the body names code only at a cross-cutting seam (a middleware, gate, hook, store); the rest is plain names in prose, with identifiers in "For the agent"`, excerpt: s.title });
209
+ if (!disabled.has('list-not-prose') && s.bullets >= 4 && s.bullets / s.lines > 0.6) findings.push({ path, n: s.n, severity: 'warn', id: 'list-not-prose', message: 'a body section that is a list — a decision, a promise or an explanation is prose; a list is for genuinely parallel one-liners', excerpt: s.title });
210
+ if (!disabled.has('formula-run') && s.maxRun >= 3) findings.push({ path, n: s.n, severity: 'warn', id: 'formula-run', message: 'three or more bold-led bullets in a row — the "**X** — over Y, because Z" formula reads as a ledger; write the decisions as themed paragraphs', excerpt: s.title });
211
+ }
212
+ }
127
213
  }
128
214
 
129
215
  // A changed plan whose committed version is already frozen must not be edited.
@@ -6,6 +6,7 @@ One file per template. Every template is either a **truth document** (states cur
6
6
  | --- | --- | --- |
7
7
  | Feature (LLD) | [feature.md](feature.md) | Truth |
8
8
  | Package (one workspace package) | [package.md](package.md) | Truth |
9
+ | Doctrine (one concern the platform handles everywhere) | [doctrine.md](doctrine.md) | Truth |
9
10
  | System (one machine spanning packages) | [system.md](system.md) | Truth |
10
11
  | Architecture Decision (AD) | [architecture-decision.md](architecture-decision.md) | Truth (Decision Changelog tail sanctioned) |
11
12
  | System overview | [system-overview.md](system-overview.md) | Truth |
@@ -18,13 +19,13 @@ One file per template. Every template is either a **truth document** (states cur
18
19
  | Testing strategy | [testing-strategy.md](testing-strategy.md) | Truth |
19
20
  | Behavioral checklist | [behavioral-checklist.md](behavioral-checklist.md) | Truth |
20
21
  | UX behavior | [ux-behavior.md](ux-behavior.md) | Truth |
22
+ | Setup (first run, one per repo) | [setup.md](setup.md) | Truth |
21
23
  | Operations procedure | [operations-procedure.md](operations-procedure.md) | Truth |
22
24
  | Implementation map | [implementation-map.md](implementation-map.md) | Truth |
23
25
  | Bookkeeping ledger | [bookkeeping.md](bookkeeping.md) | Truth (work queue) |
24
26
  | Protected files | [protected-files.md](protected-files.md) | Truth |
25
- | Project root README | [root-readme.md](root-readme.md) | Truth |
27
+ | Project root README (outward opening, then orientation and routing) | [root-readme.md](root-readme.md) | Truth |
26
28
  | docs/README.md (doc index) | [docs-readme.md](docs-readme.md) | Truth |
27
- | docs/structure.md (authority map) | [structure.md](structure.md) | Truth (Health Log tail sanctioned) |
28
29
  | Plan | [plan.md](plan.md) | Record |
29
30
  | Changelog entry | [changelog-entry.md](changelog-entry.md) | Record |
30
31
  | Migration runbook | [migration-runbook.md](migration-runbook.md) | Record |
@@ -35,6 +36,6 @@ One file per template. Every template is either a **truth document** (states cur
35
36
 
36
37
  **The `type:` enum lives here.** A doc's `type:` frontmatter takes its value from this table — one genre per template (`feature`, `architecture-decision`, `non-goals`, …). External generators consume this list rather than defining their own; a type this table does not name defaults to `docs/architecture/` placement and is never added to the protected-files list.
37
38
 
38
- **Baseline scaffolds** — files that must exist after every baseline; the `maintenance` agent (baseline mode) creates any that are missing: [docs-readme.md](docs-readme.md), [structure.md](structure.md), [changelog-index.md](changelog-index.md), [backlog.md](backlog.md), [memory-main.md](memory-main.md), and [root-readme.md](root-readme.md) (never overwriting an existing root README).
39
+ **Baseline scaffolds** — files that must exist after every baseline (`docs/structure.md` is not among them: it is harness-owned, shipped whole by the installer and overwritten on every refresh, and has no template); the `maintenance` agent (baseline mode) creates any that are missing: [docs-readme.md](docs-readme.md), [changelog-index.md](changelog-index.md), [backlog.md](backlog.md), [memory-main.md](memory-main.md), [setup.md](setup.md) (when the repo has a lockfile and a runnable root script; never overwriting an existing first-run procedure), and [root-readme.md](root-readme.md) (never overwriting an existing root README).
39
40
 
40
41
  **Ownership.** Three genres carry code — **feature**, **package**, **system** — and each is the canonical reference for the code paths in its **`owns:` frontmatter**, the only ownership key. To find what a doc owns, read its `owns:` globs; to find the doc for a path, match the path against the injected ownership index (the union of every owning doc's globs), narrower glob wins. That is what layers them: a package doc claims `packages/{name}/**` and is the tree's **residual** owner, while a system doc claims the narrower subtrees of one machine and a feature doc claims one surface — both win those paths by specificity, and the package doc keeps everything neither claims. Two docs may never claim a path at **equal** specificity. Every other genre here owns no code, including the cross-cutting doctrine in `docs/architecture/common/`. See [`../references/frontmatter.md`](../references/frontmatter.md) for turning code into `owns:` globs.
@@ -21,4 +21,4 @@ The shared work queue keeping documentation and code in sync — a queue, never
21
21
 
22
22
  **A waiver covers a finding only when it names the finding's kind and its subject in backticks** — the matcher (`waiverCovers`) tests the backticked subject exactly, so a waiver written without them silences nothing and the wall stands. A `waived:` row's `expires=` date is enforced: CI honors the waiver until the date, then fails. `dead-glob` waivers double as the dead-glob allowlist; `ownership-overlap` waivers cover the CI ownership check the same way.
23
23
 
24
- Finding kinds for `auto:`: `dead-glob` · `doc-implicated` · `doc-lint` · `header-missing` · `index-row-missing` · `package-rejected` · `frozen-record-edited` · `source-lint`. The CI ownership check additionally accepts `waived:` rows of kind `ownership-overlap`.
24
+ Finding kinds for `auto:`: `dead-glob` · `doc-implicated` · `doc-lint` · `header-missing` · `package-rejected` · `frozen-record-edited` · `source-lint`. The CI ownership check additionally accepts `waived:` rows of kind `ownership-overlap`.
@@ -2,67 +2,46 @@
2
2
 
3
3
  Truth document. Use for: the entry point for all documentation in a repo. Created during baseline audit.
4
4
 
5
+ **This file describes directories, never files.** Each section names one folder under `docs/` and says what the folder holds, who reads it and how its files are named — a description of the directory, not of its contents. No per-file rows, no file tree, no `├──` block: the tree is `structure.md`'s, as the authority on placement, and `ls` is the roster. A row per file forces an index edit on every file added, renamed or retired, and the index's own history then records roster churn instead of what the index said — a repo carried 103 commits on `docs/README.md` before this rule, most of them row edits. Each section below names a folder and says what the folder holds and how its files are named; the only files an index may name are the mandated scaffolds (`structure.md`, `operations/setup.md`, `history/CHANGELOG.md`, `history/backlog.md`) and the root `CLAUDE.md`. The repo-root `README.md` routes the team and agents in by intent; this file describes the folders of the docs tree — each links the other once and neither restates the other. `doc-lint` blocks a folder index that links an individual document (`index-lists-files`) or draws a tree (`index-file-tree`).
6
+
5
7
  **Link only what exists.** Every row below is a placeholder — drop any whose target the repo does not have. Most `history/` and `architecture/` folders are created on first use, so linking them unconditionally ships a docs index with dead links on day one. An index is a browse page: a link that resolves to nothing is worse than an absent row.
6
8
 
7
9
  ```
8
10
  # {Project Name} Documentation
9
11
 
10
- Technical documentation for {project description}.
12
+ Technical documentation for {project description}. {Two or three sentences: what the product is, its planes or packages, who the docs are for.}
11
13
 
12
14
  > For documentation organization, authority map, and folder rules, see **[structure.md](structure.md)**.
13
15
 
14
16
  ---
15
17
 
16
- ## Quick Links
17
-
18
- | Document | Description |
19
- | --------------------------------- | ------------------------------------ |
20
- | [Structure](structure.md) | Documentation entry point and rules |
21
- | [Setup](operations/setup.md) | Installation and configuration guide |
22
-
23
- ---
24
-
25
18
  ## Architecture
26
19
 
27
- System design, steering docs, and standing decisions — the truth layer.
28
-
29
- - [system-design.md](architecture/system-design.md) - System overview: subsystems and key flows
30
- - [domain-model.md](architecture/domain-model.md) - Entities, relationships, state ownership
31
- - [glossary.md](architecture/glossary.md) - Project vocabulary
32
- - [non-goals.md](architecture/non-goals.md) - What this system deliberately does not do
33
- - [decisions/](architecture/decisions/Readme.md) - Architecture Decisions (ADs)
34
- {list other architecture docs — api.md, security.md — when present}
35
-
36
- ---
20
+ The design layer — [architecture/](architecture/): {what the folder holds — the system overview, steering docs, cross-cutting doctrine, the per-package and per-system documents, and `decisions/` (one Architecture Decision per subject, `AD-NNN-{slug}.md`, status in each file's frontmatter)}.
37
21
 
38
22
  ## Features
39
23
 
40
- Living reference docs for implemented features (how things currently work).
24
+ [features/](features/) — one living reference per feature (how it works today), flat, named `{feature}.md`; each carries `owns:` for the code it speaks for. Find a feature by its name or by the ownership index, never by a row here.
41
25
 
42
- - [feature-name.md](features/feature-name.md) - Feature description
43
- {list all feature docs}
26
+ ## Tests
44
27
 
45
- ---
28
+ [tests/](tests/) — one behavioral checklist per documented surface, `{feature}.md`, `verifies:` naming the document whose promises it proves.
46
29
 
47
30
  ## Operations
48
31
 
49
- How to run, develop, and deploy.
32
+ [operations/](operations/) — how to set up, run, develop, deploy and recover. Start at [`setup.md`](operations/setup.md) on a new machine; every other procedure is named for its task.
33
+
34
+ ## History
50
35
 
51
- - [setup.md](operations/setup.md) - Installation and configuration guide
52
- {list all operations docs — environment.md when present}
36
+ [history/](history/) — the records: `plans/` (one dated plan per unit of work, frozen at completion), `changelog/` (one entry per unit of work, indexed by [CHANGELOG.md](history/CHANGELOG.md)), `migrations/` (one-shot runbooks), `brainstorms/`, `research/`, and [backlog.md](history/backlog.md).
53
37
 
54
- ---
38
+ ## Research and memory
55
39
 
56
- ## History
40
+ [research/](research/) — in-progress brainstorm sessions and standing research. [memory/](memory/) — project memory, one file per agent.
57
41
 
58
- The records — everything dated, frozen, or append-only.
42
+ ## Notes for this repository
59
43
 
60
- - [CHANGELOG.md](history/CHANGELOG.md) - Master changelog index
61
- - [changelog/](history/changelog/) - Individual changelog entries
62
- - [plans/](history/plans/) - Implementation plans (frozen at completion)
63
- - [migrations/](history/migrations/) - One-shot migration runbooks (frozen once executed)
64
- - [research/](history/research/) - Deep-research artifacts (one folder per topic)
65
- - [backlog.md](history/backlog.md) - Tracked work items and technical debt
44
+ {The one place project-specific placement facts live, because `structure.md` is the harness's and is overwritten on every refresh: legacy folders kept as frozen provenance, a retired genre whose residue is still on disk, a local exception to a folder rule. One bullet each; delete the section when there are none.}
66
45
 
67
46
  ---
68
47
 
@@ -0,0 +1,82 @@
1
+ # Doctrine Documentation (docs/architecture/common/{concern}.md)
2
+
3
+ Truth document. Use for **one concern the platform handles everywhere**: authentication, authorization, storage, the API protocol, credentials, telemetry. One file per concern, named for the concern. A doctrine document owns no code and carries no `owns:`. A surface declares that it is bound by one through its own `applies:`.
4
+
5
+ **A doctrine document states the design and nothing beneath it** (`references/style-guide.md` § Shape — the model first, the detail after). It is the most stable document in the tree, because it says why the platform is shaped the way it is, and that changes far less often than the code. It explains no mechanism: no function, file, column, cookie attribute, header value or per-route error code, since each of those fails the stability test. The code graph answers what the code does. This document answers why, and which principles any new code in the concern must keep.
6
+
7
+ **Required:**
8
+
9
+ - the frontmatter
10
+ - the opening (the question, the boundary, and the authority sentence)
11
+ - **The model**, ending in numbered principles, each with its reason
12
+ - **The parts**: one table or diagram placing every part in the model, then how the parts relate
13
+ - **one section per part**
14
+ - **For the agent**
15
+
16
+ **Optional:**
17
+
18
+ - an `UNBUILT` block for decided-but-unbuilt intent
19
+ - **Related**
20
+
21
+ Nothing else. Expect one hundred and fifty to three hundred lines; past that, mechanism has usually crept in.
22
+
23
+ ```yaml
24
+ ---
25
+ type: doctrine # required tooling key
26
+ status: active # required — active | draft
27
+ objects: [principal, credential, device grant] # recommended — the concepts this doctrine governs, by their graph names
28
+ ---
29
+ ```
30
+
31
+ ```
32
+ # {Concern}
33
+
34
+ {The question this concern answers for every request, row or run, in one sentence, bolded — then what it does not answer and which document does. One paragraph.}
35
+
36
+ {The authority sentence: this document states the design, not the code; for what does what, read the code roots in the footer or ask the code graph; where this document and the code disagree on *what*, the code is right; on *why* or a principle, the disagreement is a defect to raise.}
37
+
38
+ ## The model
39
+
40
+ ### {What the platform owns here, and what it delegates}
41
+
42
+ {The one framing fact a reader needs before anything else — e.g. "NuStack checks identity; it does not own it". Plain words, no addresses.}
43
+
44
+ ### {The parties or parts}
45
+
46
+ {Who or what participates, in a short list of one-liners — each named in plain words first, its term of art in parentheses.}
47
+
48
+ ### {The axis that organizes them}
49
+
50
+ {The one or two dimensions every part is placed on — e.g. "who issued the proof decides how it is checked". A small table is right here.}
51
+
52
+ ### The principles
53
+
54
+ {Numbered invariants that hold across every part. Each one sentence of rule plus its reason. Later sections cite them by number.}
55
+
56
+ ## {The parts} — e.g. "The credential families"
57
+
58
+ {One table: each part placed on the model's axes. Then "How the parts relate": what they share, where they meet, what keeps them apart, and the order in which they are tried — each as a bold-led paragraph with its reason. A role-level diagram (mermaid) where the relationships are a flow.}
59
+
60
+ ## {Each part, one section per part} — e.g. "How each family works"
61
+
62
+ ### {A part, named for who meets it} — e.g. "A person in a browser"
63
+
64
+ {Why the part exists, then the decisions it rests on, each with its reason, citing principles by number. A sequence diagram at role level where the part is a flow. Detail that a person or test can check is welcome; detail that only restates the code is not.}
65
+
66
+ ## For the agent
67
+
68
+ {Pointers, not an inventory: the objects with one line each; the code roots as directories; any cross-cutting seam by name; the neighbouring doctrine with a purpose each.}
69
+ ```
70
+
71
+ ### Marking what is decided and unbuilt
72
+
73
+ Code cannot reveal what it does not yet do, so decided-but-unbuilt intent is one of the few places a doctrine document records something the code does not. Wrap it in `<!-- UNBUILT:START — {what, and the evidence it is not built} -->` … `<!-- UNBUILT:END -->`, in plain words. A design decided *against* carries no marker.
74
+
75
+ ### What a doctrine document is not
76
+
77
+ | It is not | That is |
78
+ | --- | --- |
79
+ | A tour of the code that implements the concern | The code graph |
80
+ | The catalog of routes, error codes or variables | An API reference or environment registry |
81
+ | The one feature that happens to use the concern most | That feature's own document, which `applies:` this one |
82
+ | The story of how the concern got this way | A decision record (`decisions/`) for the why, and the changelog for the when |