@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.
- package/data/harness-index.json +1 -1
- package/data/harnesses/code/CLAUDE.md +4 -4
- package/data/harnesses/code/agents/bookkeeper.md +1 -1
- package/data/harnesses/code/agents/change-review.md +1 -1
- package/data/harnesses/code/agents/lld-mode.md +1 -1
- package/data/harnesses/code/agents/maintenance.md +7 -9
- package/data/harnesses/code/docs/structure.md +133 -71
- package/data/harnesses/code/harness.json +4 -4
- package/data/harnesses/code/hooks/awareness.mjs +0 -10
- package/data/harnesses/code/hooks/lib/ownership.mjs +4 -2
- package/data/harnesses/code/hooks/lib/sweep.mjs +4 -8
- package/data/harnesses/code/skills/documentation/SKILL.md +19 -8
- package/data/harnesses/code/skills/documentation/references/frontmatter.md +3 -3
- package/data/harnesses/code/skills/documentation/references/style-guide.md +70 -27
- package/data/harnesses/code/skills/documentation/references/untemplated.md +2 -1
- package/data/harnesses/code/skills/documentation/scripts/doc-lint.mjs +87 -1
- package/data/harnesses/code/skills/documentation/templates/Readme.md +4 -3
- package/data/harnesses/code/skills/documentation/templates/bookkeeping.md +1 -1
- package/data/harnesses/code/skills/documentation/templates/docs-readme.md +15 -36
- package/data/harnesses/code/skills/documentation/templates/doctrine.md +82 -0
- package/data/harnesses/code/skills/documentation/templates/feature.md +31 -123
- package/data/harnesses/code/skills/documentation/templates/handover.md +174 -0
- package/data/harnesses/code/skills/documentation/templates/operations-procedure.md +1 -1
- package/data/harnesses/code/skills/documentation/templates/package.md +28 -94
- package/data/harnesses/code/skills/documentation/templates/root-readme.md +103 -65
- package/data/harnesses/code/skills/documentation/templates/setup.md +138 -0
- package/data/harnesses/code/skills/documentation/templates/system.md +25 -109
- package/data/harnesses/delivery/agents/lld-mode.md +1 -1
- package/data/harnesses/delivery/agents/maintenance.md +7 -9
- package/data/harnesses/delivery/harness.json +2 -2
- package/data/harnesses/delivery/skills/documentation/SKILL.md +19 -8
- package/data/harnesses/delivery/skills/documentation/references/frontmatter.md +3 -3
- package/data/harnesses/delivery/skills/documentation/references/style-guide.md +70 -27
- package/data/harnesses/delivery/skills/documentation/references/untemplated.md +2 -1
- package/data/harnesses/delivery/skills/documentation/scripts/doc-lint.mjs +87 -1
- package/data/harnesses/delivery/skills/documentation/templates/Readme.md +4 -3
- package/data/harnesses/delivery/skills/documentation/templates/bookkeeping.md +1 -1
- package/data/harnesses/delivery/skills/documentation/templates/docs-readme.md +15 -36
- package/data/harnesses/delivery/skills/documentation/templates/doctrine.md +82 -0
- package/data/harnesses/delivery/skills/documentation/templates/feature.md +31 -123
- package/data/harnesses/delivery/skills/documentation/templates/handover.md +174 -0
- package/data/harnesses/delivery/skills/documentation/templates/operations-procedure.md +1 -1
- package/data/harnesses/delivery/skills/documentation/templates/package.md +28 -94
- package/data/harnesses/delivery/skills/documentation/templates/root-readme.md +103 -65
- package/data/harnesses/delivery/skills/documentation/templates/setup.md +138 -0
- package/data/harnesses/delivery/skills/documentation/templates/system.md +25 -109
- package/data/harnesses/etna/agents/change-review.md +1 -1
- package/data/harnesses/etna/agents/lld-mode.md +1 -1
- package/data/harnesses/etna/agents/maintenance.md +7 -9
- package/data/harnesses/etna/harness.json +2 -2
- package/data/harnesses/etna/skills/documentation/SKILL.md +19 -8
- package/data/harnesses/etna/skills/documentation/references/frontmatter.md +3 -3
- package/data/harnesses/etna/skills/documentation/references/style-guide.md +70 -27
- package/data/harnesses/etna/skills/documentation/references/untemplated.md +2 -1
- package/data/harnesses/etna/skills/documentation/scripts/doc-lint.mjs +87 -1
- package/data/harnesses/etna/skills/documentation/templates/Readme.md +4 -3
- package/data/harnesses/etna/skills/documentation/templates/bookkeeping.md +1 -1
- package/data/harnesses/etna/skills/documentation/templates/docs-readme.md +15 -36
- package/data/harnesses/etna/skills/documentation/templates/doctrine.md +82 -0
- package/data/harnesses/etna/skills/documentation/templates/feature.md +31 -123
- package/data/harnesses/etna/skills/documentation/templates/handover.md +174 -0
- package/data/harnesses/etna/skills/documentation/templates/operations-procedure.md +1 -1
- package/data/harnesses/etna/skills/documentation/templates/package.md +28 -94
- package/data/harnesses/etna/skills/documentation/templates/root-readme.md +103 -65
- package/data/harnesses/etna/skills/documentation/templates/setup.md +138 -0
- package/data/harnesses/etna/skills/documentation/templates/system.md +25 -109
- package/lib/install/materialize.mjs +4 -12
- package/lib/install/plan.mjs +4 -11
- package/package.json +3 -2
- package/data/harnesses/code/skills/documentation/templates/structure.md +0 -71
- package/data/harnesses/delivery/skills/documentation/templates/structure.md +0 -71
- package/data/harnesses/etna/skills/documentation/templates/structure.md +0 -71
|
@@ -1,143 +1,59 @@
|
|
|
1
1
|
# System Documentation (docs/architecture/systems/{system}.md)
|
|
2
2
|
|
|
3
|
-
Truth document. Use for: **one machine that spans packages
|
|
3
|
+
Truth document. Use for: **one machine that spans packages**, which a person cannot point at — the walk, the egress, the ingest, the settlement, a gate, a sweep, a door an agent calls. One file per machine, named for the machine. A thing a person navigates to is a feature document, even when it owns tables; a unit of distribution is a package document.
|
|
4
4
|
|
|
5
|
-
**A
|
|
5
|
+
**A document is read by people, and its footer is for the agent** (`references/style-guide.md` § Documents are read by people). A system document explains a machine to a person: what it is for, why it is split where it is split, how it behaves from the outside, what it guarantees at the far end, what re-drives it when it stalls. Its stages, tables, routes, frames, bindings and files are the code graph's (`docs/architecture/systems/knowledge-layer.md`), not a hand-typed tour. The body names code only at a cross-cutting seam another machine or feature would not find from its own files.
|
|
6
6
|
|
|
7
|
-
**
|
|
7
|
+
**A system document's deepest layer is the machine's behaviour across packages** (`references/style-guide.md` § Shape — the model first, the detail after): the order it runs in, the sequence and state diagrams at role level, the invariant that holds at each place where parts meet, and what re-drives a stall. That layer is earned because no single file shows a cross-package flow. It stops before per-function steps, tables, columns and routes.
|
|
8
8
|
|
|
9
|
-
**
|
|
9
|
+
**A system document's globs win by specificity.** Its `owns:` names the subtrees and exact files the machine is made of, narrower than the package glob. Two documents never claim a path at equal specificity; every glob matches a file on disk at `status: active`.
|
|
10
10
|
|
|
11
|
-
**Required
|
|
12
|
-
|
|
13
|
-
System documents are long by nature, because the point is that the whole machine is in one place — roughly 300 to 1000 lines. Length is earned by stages, never by restating a neighbour: every paragraph that could have been a link to the document that owns it is the genre's characteristic waste.
|
|
11
|
+
**Required:** the frontmatter, the opening paragraph (the machine defined in its first sentence, what enters, what it leaves behind), the **boundary paragraph** (what this document does not decide, and which document does — subjects with owners, never bare links), **Why it exists**, **How it works**, **What it promises**, **For the agent**. **What was decided** once any choice was made the code cannot explain. **Known gaps** only when there is one. Nothing else — the lint rules of the feature template apply. Sixty to a hundred and sixty lines.
|
|
14
12
|
|
|
15
13
|
```yaml
|
|
16
14
|
---
|
|
17
|
-
|
|
15
|
+
type: system # required tooling key
|
|
16
|
+
status: active # required — draft = the machine as a whole does not run
|
|
17
|
+
objects: [run, run ledger, settlement] # required — the objects this machine owns or moves
|
|
18
|
+
owns: # required until the graph computes ownership — narrower than the package glob
|
|
18
19
|
- packages/{pkg}/src/{machine}/**
|
|
19
|
-
|
|
20
|
-
- packages/{other}/src/shared/{machine}Vocabulary.ts
|
|
21
|
-
keywords: [machine name, its nouns, its verbs] # required — discovery terms: the machine's own vocabulary, the table and route names
|
|
22
|
-
status: active # required — active | draft | deprecated
|
|
23
|
-
applies: # optional — the decisions and doctrine this machine is BOUND by (obligation, not a bibliography)
|
|
20
|
+
applies: # optional — decisions and doctrine this machine is BOUND by
|
|
24
21
|
- docs/architecture/decisions/AD-0NN-{slug}.md
|
|
25
|
-
- docs/architecture/common/{doctrine}.md
|
|
26
|
-
type: system # required tooling key — genre stamp; preserve on edits, never narrate
|
|
27
22
|
---
|
|
28
23
|
```
|
|
29
24
|
|
|
30
|
-
> A system document carries no `module:` — a machine that spans packages belongs to no single
|
|
31
|
-
> bounded context, and labelling it with one asserts a boundary it crosses by definition.
|
|
32
|
-
> `last-reviewed:` is optional tooling metadata: preserve it, never narrate it.
|
|
33
|
-
|
|
34
25
|
```
|
|
35
26
|
# {The machine}
|
|
36
27
|
|
|
37
|
-
{
|
|
38
|
-
then says what this document states, in the order the body states it. The enumeration is the
|
|
39
|
-
contract: a reader who wants one stage finds it by reading this sentence. Where the machine's
|
|
40
|
-
purpose is easier stated as an outcome, lead with `**Goal:**` and one sentence instead.}
|
|
41
|
-
|
|
42
|
-
{One paragraph: the boundary. What this document does **not** restate, and which document holds
|
|
43
|
-
each part — the neighbouring systems, the package documents whose residue this sits inside, the
|
|
44
|
-
feature documents that render from it, the common-plane doctrine it obeys, the decision records
|
|
45
|
-
behind its shape. Name each with a link and the subject it holds. This paragraph is what keeps the
|
|
46
|
-
document from growing into its neighbours.}
|
|
47
|
-
|
|
48
|
-
```text
|
|
49
|
-
{The machine diagram. One fenced block, drawn as the thing flows — entry at the top or left,
|
|
50
|
-
each stage a box or a labelled arrow, the durable writes named, the re-drive path shown returning.
|
|
51
|
-
Label the arrows with what crosses them, not with verbs. This is the picture a reader holds while
|
|
52
|
-
reading the rest, so it carries the machine's real names — routes, tables, classes, files — and
|
|
53
|
-
not generic boxes.}
|
|
54
|
-
```
|
|
55
|
-
|
|
56
|
-
{Optional, and worth its line whenever the body names paths: "Every path below is relative to
|
|
57
|
-
`packages/{pkg}/src/{dir}/` unless it names another package."}
|
|
28
|
+
{The machine defined in its first sentence — bold the term — then what it takes in, what it leaves behind, and what a reader sees at the far end. Plain words.}
|
|
58
29
|
|
|
59
|
-
{
|
|
60
|
-
§ Z is what re-drives it" — where the section list is not self-evidently a sequence.}
|
|
30
|
+
{The boundary paragraph: what this document does not decide and which document does.}
|
|
61
31
|
|
|
62
|
-
##
|
|
32
|
+
## Why it exists
|
|
63
33
|
|
|
64
|
-
{
|
|
65
|
-
name them in one table before the stages begin.}
|
|
34
|
+
{Why this is one machine and not two, what it deliberately is not, the constraint that shaped it.}
|
|
66
35
|
|
|
67
|
-
|
|
68
|
-
| --- | --- | --- |
|
|
69
|
-
| {Entry} | `routes/{x}.ts` | {thin, tenancy first} |
|
|
70
|
-
| {Ledger} | `{machine}/ledger.ts` | {the durable row} |
|
|
36
|
+
## How it works
|
|
71
37
|
|
|
72
|
-
|
|
38
|
+
{The machine's behaviour from the outside, in the order it runs, in plain words: what starts it, what it does at each step as a person would describe it, what it writes that outlives it, what re-drives it, what it refuses. Terms of art introduced on first use. Code named only at a seam.}
|
|
73
39
|
|
|
74
|
-
|
|
75
|
-
Entry, then each stage, then what is written durably, then what re-drives a stalled one, then what
|
|
76
|
-
reads the result. Name each section for its stage in the product's own vocabulary. Within a
|
|
77
|
-
section, state the mechanism and its reason: what the code does, what it refuses, and why it
|
|
78
|
-
refuses that rather than something else. Tables for rosters (routes, columns, frames, states,
|
|
79
|
-
bindings); prose for a rule and the defect it prevents. Never paste an implementation — a
|
|
80
|
-
signature, a state list, a wire shape, a table's columns.}
|
|
40
|
+
## What was decided
|
|
81
41
|
|
|
82
|
-
|
|
42
|
+
{Themed paragraphs; alternatives named only where a reader would reach for them.}
|
|
83
43
|
|
|
84
|
-
|
|
85
|
-
where the machine has a suite of its own; omit the heading where the coverage lives in the package
|
|
86
|
-
documents' suites.}
|
|
44
|
+
## What it promises
|
|
87
45
|
|
|
88
|
-
|
|
46
|
+
{Checkable guarantees and refusals, grouped; what holds at the far end; what a stalled run gets.}
|
|
89
47
|
|
|
90
|
-
|
|
91
|
-
| --- | --- |
|
|
92
|
-
| `packages/{pkg}/src/{machine}/{file}.ts` | {what it holds, by name — the exports a reader is looking for} |
|
|
48
|
+
## Known gaps
|
|
93
49
|
|
|
94
|
-
{One
|
|
95
|
-
the inverse: "Read here, owned elsewhere:" naming the paths the body describes but another document
|
|
96
|
-
claims, each with the document that claims it. That closing line is what stops a system document
|
|
97
|
-
from quietly annexing the code it reads.}
|
|
50
|
+
{One paragraph, only when needed.}
|
|
98
51
|
|
|
99
|
-
##
|
|
52
|
+
## For the agent
|
|
100
53
|
|
|
101
|
-
|
|
102
|
-
- [`{neighbour}.md`]({neighbour}.md) — {the machine on the other side of this seam}
|
|
103
|
-
- [`{feature}.md`](../../features/{feature}.md) — {what a person sees of this machine}
|
|
104
|
-
- [`{doctrine}.md`](../common/{doctrine}.md) — {the cross-cutting contract this machine answers to}
|
|
54
|
+
Objects: {…}. Code roots {…} — directories, one per package the machine spans. Seams {…} by name. Checklist `tests/{system}.md`. See also {neighbour} ({why}). No tables, routes or symbol rosters — those are the graph's.
|
|
105
55
|
```
|
|
106
56
|
|
|
107
|
-
### The boundary paragraph is the genre's load-bearing section
|
|
108
|
-
|
|
109
|
-
Systems overlap: they share tables, call each other, and render into the same surfaces. Without a
|
|
110
|
-
paragraph that names the seams, two system documents describe the same stage from two angles and
|
|
111
|
-
drift apart on the first change — and a reader has no way to tell which is authoritative. So the
|
|
112
|
-
boundary paragraph is not a courtesy list of related reading; it is the statement of what this
|
|
113
|
-
document is *not*, written specifically enough that a later editor can tell where to put a fact.
|
|
114
|
-
Write it as a list of subjects with their owners — "the coordinator's tables, alarm and drive claim
|
|
115
|
-
are `harness.md`; a run's ledger row and settlement are `generation-runs.md`" — never as bare
|
|
116
|
-
links.
|
|
117
|
-
|
|
118
57
|
### Marking what is decided and unbuilt
|
|
119
58
|
|
|
120
|
-
Where
|
|
121
|
-
acts, a column that is written and never read, a door with no caller — wrap the prose in a marker
|
|
122
|
-
so the gap is machine-findable and its evidence travels with it:
|
|
123
|
-
|
|
124
|
-
```
|
|
125
|
-
<!-- UNBUILT:START — {what is decided, where it is decided (an AD § or an owner ruling), and the
|
|
126
|
-
source evidence that it is not built: the function with no caller, the route that is not mounted,
|
|
127
|
-
the value written and never read} -->
|
|
128
|
-
{the prose describing the unbuilt stage, and what runs in its place}
|
|
129
|
-
<!-- UNBUILT:END -->
|
|
130
|
-
```
|
|
131
|
-
|
|
132
|
-
**State what runs instead.** A machine with a hole in it still works somehow, and the workaround is
|
|
133
|
-
the fact a reader needs. **A design decided *against* carries no marker** — a marker means the work
|
|
134
|
-
is owed and absent, so using one for a rejected design turns the register of debt into a register
|
|
135
|
-
of opinions.
|
|
136
|
-
|
|
137
|
-
### `status: draft` on a system
|
|
138
|
-
|
|
139
|
-
A system document is `draft` when the **machine as a whole** does not run — the code is on disk and
|
|
140
|
-
nothing reaches it. Say so in the first section, in plain words, with the evidence: which halves
|
|
141
|
-
exist, which do not, and what a reader who invokes it actually observes. A scoped gap in a working
|
|
142
|
-
machine is not a draft: the document stays `active` and takes an UNBUILT marker at the stage that
|
|
143
|
-
has the hole.
|
|
59
|
+
Where a stage is decided and not built, wrap its prose in `<!-- UNBUILT:START — {what, where decided, the evidence it is not built} -->` … `<!-- UNBUILT:END -->` and say in What it promises what runs instead. A design decided *against* carries no marker.
|
|
@@ -33,7 +33,7 @@ Parse these from the user's prompt; use the default when unstated.
|
|
|
33
33
|
|
|
34
34
|
1. If `./docs/memory/change-review.md` exists, read it for historical velocity snapshots, prior risk-zone flags, known concentration risks, and the project's **Module Taxonomy** / **Feature Taxonomy**.
|
|
35
35
|
2. If a CSV from a prior run already exists at the project root (`change-review-YYYY-MM-DD.csv`), prefer it as input and **skip Phase 1** — re-classify only when the requested window changed.
|
|
36
|
-
3. Build the ownership map from feature `owns:` frontmatter — consult the injected ownership index (`glob → doc · module ·
|
|
36
|
+
3. Build the ownership map from feature `owns:` frontmatter — consult the injected ownership index (`glob → doc · module · objects · status`), or glob `docs/features/**/*.md` and read each doc's `owns:` globs — to map churn to owning feature docs and their `module:` labels.
|
|
37
37
|
|
|
38
38
|
---
|
|
39
39
|
|
|
@@ -21,7 +21,7 @@ Map the documentation landscape — what exists, what is adjacent, how detailed
|
|
|
21
21
|
2. Locate the repo's feature-doc layer from `structure.md` — the standard shape is `./docs/features/`, but a repo may document components under their own subject folders. Read that layer's index if it has one; otherwise glob for docs carrying `owns:` frontmatter
|
|
22
22
|
3. If `./docs/memory/lld-mode.md` exists (or the legacy `./docs/memory/spec-mode.md`), read it for feature doc inventory, ownership conflict zones, and lessons from previous research
|
|
23
23
|
4. Read 1-2 existing feature LLDs from that layer to calibrate format and depth
|
|
24
|
-
5. Consult the **injected ownership index** (the generated `glob → doc · module ·
|
|
24
|
+
5. Consult the **injected ownership index** (the generated `glob → doc · module · objects · status` map — the union of every feature doc's `owns:` frontmatter) to build the ownership map. It is the source of truth for what code paths are already owned. If the index isn't present in context, glob the docs tree (excluding `docs/history/`) and read the `owns:` frontmatter of every doc that declares it.
|
|
25
25
|
|
|
26
26
|
## What You Research
|
|
27
27
|
|
|
@@ -95,8 +95,6 @@ Run `git log --since="2 weeks ago" --name-only --pretty=format:"%h %s"` to find
|
|
|
95
95
|
|
|
96
96
|
**Unowned paths.** Compare the repo's actual top-level source directories (derive them — the top-level dirs that contain code, or the roots named across the `owns:` globs; do not assume `src/`) against the `owns:` map. Report directories no `owns:` glob covers.
|
|
97
97
|
|
|
98
|
-
**Stale greenfield self-label.** If `structure.md` asserts the repo is greenfield — _"No source code or feature docs exist yet"_ or similar — **but a real source tree exists** (the derived source roots above are non-empty, e.g. a populated `packages/` of real workspaces), the self-label has gone stale. Raise it as a question (e.g. `structure.md says "No source code exists yet" but packages/ holds 5 workspaces — confirm the greenfield label should be retired`).
|
|
99
|
-
|
|
100
98
|
**Architecture drift.** Grep `docs/architecture/` for file-path references. Verify referenced paths still exist. Remove or update stale references.
|
|
101
99
|
|
|
102
100
|
**Backlog health.** Read `docs/history/backlog.md`. Report items older than 30 days. Count pending by priority.
|
|
@@ -117,7 +115,7 @@ For an unowned code **region**, append: `- **[P2]** No feature doc owns \`{dir}/
|
|
|
117
115
|
|
|
118
116
|
### Step 6: Report & update tracking
|
|
119
117
|
|
|
120
|
-
1.
|
|
118
|
+
1. Append today's row to `docs/history/health-log.md` — **append to the end**, never date-sorted into the middle. Rows are positional: one may say "the row above is…", and an inserted row silently breaks that reference. A Health Log entry is a **generated row, not a narrative essay**: one line — date · counts (stale docs fixed, dead globs, unowned paths, backlog items created) · links to anything that needs a human.
|
|
121
119
|
2. Update `docs/memory/maintenance.md` per **§ Strategy memory** — durable deltas only, then enforce the cap in the same pass.
|
|
122
120
|
3. Report findings: stale docs, broken ownership, unowned code, architecture drift, backlog health.
|
|
123
121
|
|
|
@@ -132,7 +130,7 @@ Baseline mode converges the repo's `docs/` to the **installed** harness shape, t
|
|
|
132
130
|
```
|
|
133
131
|
docs/
|
|
134
132
|
├── README.md ✱ # Documentation root — quick links, section index
|
|
135
|
-
├── structure.md
|
|
133
|
+
├── structure.md # Harness-owned authority map — the installer writes it on every refresh; you stamp only `harness-version`
|
|
136
134
|
├── architecture/ # Cross-module design + steering layer
|
|
137
135
|
│ │ # domain-model, glossary, non-goals, references, open-questions
|
|
138
136
|
│ └── decisions/ # Architecture Decisions (ADs — one per subject, updated in place; journey in each AD's Decision Changelog)
|
|
@@ -156,7 +154,7 @@ docs/
|
|
|
156
154
|
└── tests/ # Behavioral test checklists ({feature}.md, step → **Assert**), derived at plan Completion via the `documentation` skill; author-maintained
|
|
157
155
|
```
|
|
158
156
|
|
|
159
|
-
**✱ marks the
|
|
157
|
+
**✱ marks the scaffolded files — the only paths a baseline creates, and the only shape signals.** `docs/structure.md` is not one of them: the installer owns it and rewrites it on every install or refresh, so a missing or hand-edited `structure.md` means the harness needs refreshing (`npx @nurix/etna`), never a scaffold from a template — and its body is never converged, only its `harness-version` field stamped. Every **folder** in this tree is created on first use and is simply absent until it holds a file; git cannot track an empty directory, so a missing folder is never evidence of drift and is never scaffolded to satisfy the shape. Its role is already in `docs/structure.md`; a repo's own notes about legacy folders go in `docs/README.md` § Notes for this repository.
|
|
160
158
|
|
|
161
159
|
There is **no `docs/routing.md`**, **no `docs/modules/{m}/`**, **no `docs/pillars/`**, **no `docs/boundaries/`**. Code ownership lives in feature `owns:` frontmatter; a module is a `module:` label, not a folder; boundaries are diagnosed from source; brainstorm records live in `docs/research/` (active) and `docs/history/brainstorms/` (harvested).
|
|
162
160
|
|
|
@@ -192,7 +190,7 @@ B2 folds artifacts whose **shape dissolved** — a file in the wrong place or th
|
|
|
192
190
|
|
|
193
191
|
| Nature | Genres | Treatment |
|
|
194
192
|
| --- | --- | --- |
|
|
195
|
-
| **Truth document** | features, ux, architecture, operations, `docs/tests/` checklists, `structure.md`,
|
|
193
|
+
| **Truth document** | features, ux, architecture, operations, `docs/tests/` checklists, READMEs (never `structure.md`, which the installer owns) | **Converge in place.** These state what is true now, so rewriting them to the current schema is not revision, it is the genre working as designed. Add missing frontmatter keys, add missing required sections, rename keys the template renamed |
|
|
196
194
|
| **Record** | plans, changelog entries, migration runbooks, brainstorm records | **Never rewritten.** A completed plan and a committed entry are frozen — immutability begins at commit, and a record edited to match a newer schema stops being evidence of what happened. Report non-conformance; repair only the **living index** that points at the record (an absent `docs/history/CHANGELOG.md` row is an index defect, not a record defect, and is backfilled with a note saying so) |
|
|
197
195
|
|
|
198
196
|
**Never invent content to satisfy a field.** A frozen changelog entry missing `Skills:` is missing the *judgement* that field carries, and no later session holds it — writing one is fabrication wearing a schema's clothes. Report it, backlog the pattern if it recurs, and leave the entry alone. The same restraint applies to a truth document: a genre's new section that needs knowledge the repo does not contain is raised as a question, not filled with plausible prose.
|
|
@@ -203,9 +201,9 @@ B2 folds artifacts whose **shape dissolved** — a file in the wrong place or th
|
|
|
203
201
|
|
|
204
202
|
Table: `| File | Action | From | To | Reason |` (actions: `Move`, `Merge into {target}`, `Delete`, `Keep`, `Create`, `Fold`). For a fresh baseline this is mostly `Create`; for an upgrade it is mostly `Fold`/`Move`. Ask once: **"Approve this reconcile?"** — you own this interaction (the `documentation` skill is a library and has none).
|
|
205
203
|
|
|
206
|
-
On approval, execute: create the folder structure; move/fold/merge/delete per the plan; apply B2b's schema convergences to the truth documents (records are reported, never rewritten); add `Status:` to plan files; for each feature doc, derive and write its `owns:` globs (+ `module:` label + `
|
|
204
|
+
On approval, execute: create the folder structure; move/fold/merge/delete per the plan; apply B2b's schema convergences to the truth documents (records are reported, never rewritten); add `Status:` to plan files; for each feature doc, derive and write its `owns:` globs (+ `module:` label + `objects:`) from the source it describes, and each checklist's `verifies:` edge, by calling the `documentation` skill's **frontmatter derivation**; merge scattered backlogs into `docs/history/backlog.md`; fix links broken by moves.
|
|
207
205
|
|
|
208
|
-
Scaffold missing mandated files **by calling the `documentation` skill for each template** — you orchestrate, the skill supplies templates: `docs/
|
|
206
|
+
Scaffold missing mandated files **by calling the `documentation` skill for each template** — you orchestrate, the skill supplies templates: `docs/history/CHANGELOG.md`, `docs/history/backlog.md`, `docs/memory/main.md`, `docs/operations/setup.md` (when the repo has a lockfile and a runnable root script; **never a second first-run doc** — propose a rename with a `note:` row if one exists under another name), and the repo-root `README.md` (an outward opening in a user's terms from the charter and vision documents, then orientation and routing filled from the manifests, the ownership index and the root scripts — **never overwrite an existing root README**).
|
|
209
207
|
|
|
210
208
|
### Step B4 — Stamp the version
|
|
211
209
|
|
|
@@ -237,7 +235,7 @@ Apply the **§ Strategy memory** retirement procedure to `docs/memory/maintenanc
|
|
|
237
235
|
- **Enforce the memory cap on every run** (§ Strategy memory) — you are its only writer, so no one else can do it.
|
|
238
236
|
- **A clean report is valid** — do not invent issues.
|
|
239
237
|
- **Declarative, idempotent.** Re-running baseline mode on a current repo reshapes nothing — a second pass is just the audit plus the module proposal. Converge to the current shape; never replay a version ladder; never reconstruct a past shape.
|
|
240
|
-
- **Brownfield extraction (operator-ruled 2026-08-19).** When baseline mode meets a repo with a real source tree and few or no feature docs, the module *proposal* is not enough — run the extraction pass: produce feature docs for the recognized modules (docs/features/, full frontmatter: `
|
|
238
|
+
- **Brownfield extraction (operator-ruled 2026-08-19).** When baseline mode meets a repo with a real source tree and few or no feature docs, the module *proposal* is not enough — run the extraction pass: produce feature docs for the recognized modules (docs/features/, full frontmatter: `objects:` · `owns:` · `module:` · `status:` · `last-reviewed:` · `type: feature` · `derivation: "extracted (baseline YYYY-MM-DD, nustack graph + source read)"`), plus the architecture, tests, and operations layers. Use the `nustack-graph` skill where installed — localize through the index before reading; the docs record intent, the index answers facts. **Every extracted feature doc carries a `## History & Ownership` section** — top contributors with recency, churn posture, and bus-factor notes, dated "as of YYYY-MM-DD" (operator ruling: this section is mandatory in extraction output even though doc-lint flags dated narrative in truth docs; the findings are accepted for now, and a future harness version may retire the section in favor of live index pointers). `status:` is evidence-graded: `deprecated` only when history shows the area dead, never by guess. Scale by fan-out (one extraction lane per module, a completeness critic over the result) rather than one long cold read.
|
|
241
239
|
- **Diagrams ride the baseline (operator-ruled 2026-08-24).** Whenever baseline mode produces or converges the architecture layer, draw two ASCII diagrams from the real source, each in its own fenced code block: (1) an **architecture diagram** in the system-design/architecture doc — the actual processes, entry points, and wire surfaces as boxes, the calls/queues/files between them as labelled arrows; (2) a **DB ER diagram** wherever the repo declares a relational schema (DDL, migrations, an ORM schema) — one box per table listing its key columns, FK edges drawn to the table they reference, cardinality on the edge; it lands in the domain-model doc, or `docs/architecture/data-model.md` when none exists. Box-drawing characters (`┌─┐│└┘├┤`), width ≤ 100 columns. Derived only from what the code declares — a diagram never invents a component the source does not show, and a repo with no relational schema gets **no** ER diagram rather than an imagined one. Diagrams are truth-document sections: later baselines and audits converge them in place like any other section.
|
|
242
240
|
- **Tool tiers.** The SessionStart context names each manifest-declared tool with its tier; calibrate the run to it, never stall on it. **Present-fresh** (`Tool: nustack 0.9.0`): use it — localize every question through `nustack graph` before reading source, and never run an index step first: the family re-indexes a stale store before it answers, so the only freshness decision left is the deliberate `--no-refresh`. **Present-stale** (below the catalog minimum): still use it, but note the version gap and the upgrade command in the run report — a stale contract may lack answer shapes the skill assumes. **Absent** (`Tool: nustack MISSING`): fall back to the cold method (Glob/Grep/read), state in the run report that the tool was absent and give the install command — degraded output is acceptable, silent degradation is not.
|
|
243
241
|
- **One sentinel.** `docs/structure.md` `harness-version` is the only baseline/version marker.
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"harness": "etna",
|
|
3
3
|
"name": "etna",
|
|
4
|
-
"version": "1.5.
|
|
4
|
+
"version": "1.5.27",
|
|
5
5
|
"files": [
|
|
6
6
|
".prettierignore",
|
|
7
7
|
".prettierrc.json",
|
|
@@ -10,5 +10,5 @@
|
|
|
10
10
|
"seeds": [],
|
|
11
11
|
"tools": [],
|
|
12
12
|
"docsRoot": "docs",
|
|
13
|
-
"digest": "
|
|
13
|
+
"digest": "bbde0394df6d"
|
|
14
14
|
}
|
|
@@ -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.
|
|
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
|
|
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
|
-
|
|
|
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,
|
|
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 — `
|
|
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
|
|
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 `
|
|
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
|
|
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. `
|
|
62
|
+
**3. `objects:` & `status:`**
|
|
63
63
|
|
|
64
|
-
`
|
|
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
|
-
##
|
|
343
|
-
|
|
344
|
-
[Diagram + explanation]
|
|
345
|
-
|
|
346
|
-
## Key Functions
|
|
347
|
-
|
|
348
|
-
[Signatures and contracts]
|
|
349
|
-
|
|
350
|
-
## State
|
|
405
|
+
## [Contract or procedure sections]
|
|
351
406
|
|
|
352
|
-
[
|
|
353
|
-
|
|
354
|
-
## Files
|
|
355
|
-
|
|
356
|
-
[Source file list]
|
|
407
|
+
[Signatures, shapes, steps — the content the reader came for]
|
|
357
408
|
```
|
|
358
409
|
|
|
359
|
-
|
|
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 |
|
|
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 |
|
|
384
|
-
|
|
|
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
|
-
- **
|
|
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
|
|