@nurix/etna 0.20.40 → 0.20.42

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 (36) hide show
  1. package/data/harness-index.json +1 -1
  2. package/data/harnesses/code/agents/doc-reviewer.md +31 -0
  3. package/data/harnesses/code/codex/agents/doc-reviewer.toml +28 -0
  4. package/data/harnesses/code/harness.json +2 -2
  5. package/data/harnesses/code/skills/documentation/SKILL.md +14 -11
  6. package/data/harnesses/code/skills/documentation/references/document-sets.md +95 -0
  7. package/data/harnesses/code/skills/documentation/references/style-guide.md +111 -23
  8. package/data/harnesses/code/skills/documentation/scripts/doc-lint.mjs +172 -1
  9. package/data/harnesses/code/skills/documentation/templates/Readme.md +1 -1
  10. package/data/harnesses/code/skills/documentation/templates/doctrine.md +39 -33
  11. package/data/harnesses/code/skills/documentation/templates/feature.md +2 -2
  12. package/data/harnesses/code/skills/documentation/templates/package.md +1 -1
  13. package/data/harnesses/code/skills/documentation/templates/system.md +2 -2
  14. package/data/harnesses/delivery/harness.json +2 -2
  15. package/data/harnesses/delivery/skills/documentation/SKILL.md +14 -11
  16. package/data/harnesses/delivery/skills/documentation/references/document-sets.md +95 -0
  17. package/data/harnesses/delivery/skills/documentation/references/style-guide.md +111 -23
  18. package/data/harnesses/delivery/skills/documentation/scripts/doc-lint.mjs +172 -1
  19. package/data/harnesses/delivery/skills/documentation/templates/Readme.md +1 -1
  20. package/data/harnesses/delivery/skills/documentation/templates/doctrine.md +39 -33
  21. package/data/harnesses/delivery/skills/documentation/templates/feature.md +2 -2
  22. package/data/harnesses/delivery/skills/documentation/templates/package.md +1 -1
  23. package/data/harnesses/delivery/skills/documentation/templates/system.md +2 -2
  24. package/data/harnesses/etna/agents/doc-reviewer.md +31 -0
  25. package/data/harnesses/etna/codex/agents/doc-reviewer.toml +28 -0
  26. package/data/harnesses/etna/harness.json +2 -2
  27. package/data/harnesses/etna/skills/documentation/SKILL.md +14 -11
  28. package/data/harnesses/etna/skills/documentation/references/document-sets.md +95 -0
  29. package/data/harnesses/etna/skills/documentation/references/style-guide.md +111 -23
  30. package/data/harnesses/etna/skills/documentation/scripts/doc-lint.mjs +172 -1
  31. package/data/harnesses/etna/skills/documentation/templates/Readme.md +1 -1
  32. package/data/harnesses/etna/skills/documentation/templates/doctrine.md +39 -33
  33. package/data/harnesses/etna/skills/documentation/templates/feature.md +2 -2
  34. package/data/harnesses/etna/skills/documentation/templates/package.md +1 -1
  35. package/data/harnesses/etna/skills/documentation/templates/system.md +2 -2
  36. package/package.json +2 -2
@@ -1,5 +1,5 @@
1
1
  {
2
- "fingerprint": "d4d71fdc192e",
2
+ "fingerprint": "bd1f2b63adef",
3
3
  "harnesses": {
4
4
  "code": {
5
5
  "plugin": "code",
@@ -0,0 +1,31 @@
1
+ ---
2
+ name: doc-reviewer
3
+ description: The documentation skill's one cold read — reviews a document, a folder of sibling documents, or a set's rule ledger against the skill's rubric and returns BLOCKING findings and NITs, each with its fix. Dispatched by the documentation skill after a doctrine document or a document set is written or its ledger drafted; read-only.
4
+ tools: Read, Grep, Glob, Bash
5
+ model: opus
6
+ effort: medium
7
+ maxTurns: 40
8
+ ---
9
+
10
+ # Doc reviewer
11
+
12
+ You are the cold reader of a document set. You have seen none of the conversation that produced it, and that is the point: a term the documents never define is a term you do not know.
13
+
14
+ **Input:** a mode (`ledger` or `docs`) and paths: the ledger and term table in ledger mode; the documents, or their folder, in docs mode.
15
+
16
+ 1. **Load the rubric:** `references/document-sets.md` § Rubric in the `documentation` skill (`.claude/skills/documentation/` in a consumer repo, `skills/documentation/` in the forge). Its classes are the only BLOCKING classes. Read `references/style-guide.md` § Sentences and § Vocabulary with it: Filler and Fused reason are judged against them.
17
+ 2. **Read everything once, in full,** before judging anything. A contradiction or a double home is visible only across files.
18
+ 3. **In docs mode, run the lint** from the repo root on the folder: `node <skill>/scripts/doc-lint.mjs <folder>`. Its findings are evidence, not your report: judge each `sibling-duplicate` (a restatement is BLOCKING only when the two statements can drift apart in meaning), and check that each citation says what the citing sentence claims, which the lint cannot.
19
+ 4. **Judge** against the rubric. Each finding: the file and line, the quoted text, its class, and the fix as a replacement or a cut. A finding with no fix is not a finding.
20
+
21
+ **Hold the line on severity.** A finding is BLOCKING only when it is one of the rubric's classes; taste, order and wording are NITs, and a NIT inflated to BLOCKING costs the author a full revision round. Equally, never pass a contradiction or a double home because each sentence reads well alone.
22
+
23
+ READ-ONLY: you edit nothing and write no file. Return, at most 900 words:
24
+
25
+ ```
26
+ BLOCKING
27
+ - path:line · class · "quote" → fix
28
+ NIT
29
+ - path:line · "quote" → fix
30
+ Verdict: PASS | FIX (n blocking)
31
+ ```
@@ -0,0 +1,28 @@
1
+ # dropped Claude tools: Read, Grep, Glob, Bash
2
+ name = "doc-reviewer"
3
+ description = "The documentation skill's one cold read — reviews a document, a folder of sibling documents, or a set's rule ledger against the skill's rubric and returns BLOCKING findings and NITs, each with its fix. Dispatched by the documentation skill after a doctrine document or a document set is written or its ledger drafted; read-only."
4
+ developer_instructions = '''
5
+
6
+ # Doc reviewer
7
+
8
+ You are the cold reader of a document set. You have seen none of the conversation that produced it, and that is the point: a term the documents never define is a term you do not know.
9
+
10
+ **Input:** a mode (`ledger` or `docs`) and paths: the ledger and term table in ledger mode; the documents, or their folder, in docs mode.
11
+
12
+ 1. **Load the rubric:** `references/document-sets.md` § Rubric in the `documentation` skill (`.claude/skills/documentation/` in a consumer repo, `skills/documentation/` in the forge). Its classes are the only BLOCKING classes. Read `references/style-guide.md` § Sentences and § Vocabulary with it: Filler and Fused reason are judged against them.
13
+ 2. **Read everything once, in full,** before judging anything. A contradiction or a double home is visible only across files.
14
+ 3. **In docs mode, run the lint** from the repo root on the folder: `node <skill>/scripts/doc-lint.mjs <folder>`. Its findings are evidence, not your report: judge each `sibling-duplicate` (a restatement is BLOCKING only when the two statements can drift apart in meaning), and check that each citation says what the citing sentence claims, which the lint cannot.
15
+ 4. **Judge** against the rubric. Each finding: the file and line, the quoted text, its class, and the fix as a replacement or a cut. A finding with no fix is not a finding.
16
+
17
+ **Hold the line on severity.** A finding is BLOCKING only when it is one of the rubric's classes; taste, order and wording are NITs, and a NIT inflated to BLOCKING costs the author a full revision round. Equally, never pass a contradiction or a double home because each sentence reads well alone.
18
+
19
+ READ-ONLY: you edit nothing and write no file. Return, at most 900 words:
20
+
21
+ ```
22
+ BLOCKING
23
+ - path:line · class · "quote" → fix
24
+ NIT
25
+ - path:line · "quote" → fix
26
+ Verdict: PASS | FIX (n blocking)
27
+ ```
28
+ '''
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "harness": "code",
3
3
  "name": "code",
4
- "version": "3.20.10",
4
+ "version": "3.20.12",
5
5
  "files": [
6
6
  ".prettierignore",
7
7
  ".prettierrc.json",
@@ -29,5 +29,5 @@
29
29
  "origin": "https://cdn.nustack.io",
30
30
  "track": "latest"
31
31
  },
32
- "digest": "77a37a1846a0"
32
+ "digest": "16ebb3336e2e"
33
33
  }
@@ -11,9 +11,9 @@ This skill writes one document at a time: the genre registry says what kind of d
11
11
 
12
12
  1. This file.
13
13
  2. Your genre's row in [`templates/Readme.md`](templates/Readme.md) § Registry, then the template that row names.
14
- 3. [`references/style-guide.md`](references/style-guide.md) § The model and § Labels before writing prose; the rest of it only for the section you are writing.
14
+ 3. [`references/style-guide.md`](references/style-guide.md) § The model, § Labels, § Sentences and § Vocabulary before writing prose; the rest of it only for the section you are writing.
15
15
  4. [`references/frontmatter.md`](references/frontmatter.md) when you write or change frontmatter keys beyond `type:` and `description:`.
16
- 5. Only for their own tasks: [`references/untemplated.md`](references/untemplated.md) (no registry row fits), [`references/instruction-style.md`](references/instruction-style.md) (instruction files), [`references/source-comments.md`](references/source-comments.md) (source-file comments), [`references/examples.md`](references/examples.md) (worked good and bad examples).
16
+ 5. Only for their own tasks: [`references/document-sets.md`](references/document-sets.md) (more than one sibling document, or a doctrine document), [`references/untemplated.md`](references/untemplated.md) (no registry row fits), [`references/instruction-style.md`](references/instruction-style.md) (instruction files), [`references/source-comments.md`](references/source-comments.md) (source-file comments), [`references/examples.md`](references/examples.md) (worked good and bad examples).
17
17
 
18
18
  ---
19
19
 
@@ -21,11 +21,12 @@ This skill writes one document at a time: the genre registry says what kind of d
21
21
 
22
22
  1. **Find the genre.** Match the request against § Routing, then read that genre's registry row: nature, `type:`, location, required keys, required sections. No row fits ⇒ `references/untemplated.md`.
23
23
  2. **Find the existing document.** If a document on the topic already exists, extend it; a second document on one topic is drift. If the file is a frozen record (a plan at `Complete` or `Abandoned`, a committed changelog entry, an executed runbook), never edit it: write a new dated record that links back.
24
- 3. **Place and name it** at the registry's location. `docs/structure.md` is the placement authority for anything the registry leaves open.
25
- 4. **Write it from the template.** Keep the template's section names exactly; omit optional sections with nothing real to say. Write the body from the outside in (style guide § Shape), every heading and bold label a noun phrase, every sentence after a label third person. In a truth document, every sentence is present tense (§ The three natures).
26
- 5. **Write the frontmatter.** `type:` from the registry, `description:` in at most 300 characters saying what the document settles and where its boundary sits, then the genre's required keys (`references/frontmatter.md` for each key's rules).
27
- 6. **Run the lint** from the repo root on the repo-relative path: `node <skill>/scripts/doc-lint.mjs docs/features/sign-in.md` (or `--changed`). Fix every `[block]` finding; read every `[warn]` and fix it unless the judgment it flags is genuinely yours. A disable takes bare rule ids, `<!-- doc-lint-disable: id -->`, alone on its own line for the whole file with the reason in a second comment on the next line, or at the end of one line for that line only.
28
- 7. **Edit, don't append, on a substantive change to an existing truth document.** Keep its section shape, shed any history narration, progress marker or stale tripwire in the sections you touch, bump `last-reviewed:`, update `objects:` if what it designs changed, and remove any retired key on the way through.
24
+ 3. **Earn it, and route a set.** A new truth document that states rules (doctrine, a system, an architecture decision) first lists the decisions only it would own, each checked against the documents that exist; under about six, its rules go to their homes and the document is not written. More than one sibling document, or any doctrine document, follows `references/document-sets.md` from here: a term table and a rule ledger before prose, rendered from the ledger, one cold read.
25
+ 4. **Place and name it** at the registry's location. `docs/structure.md` is the placement authority for anything the registry leaves open.
26
+ 5. **Write it from the template.** Keep the template's section names exactly; omit optional sections with nothing real to say. Write the body from the outside in (style guide § Shape), every heading and bold label a noun phrase, every sentence after a label third person, one rule per sentence in the term engineers use (style guide § Sentences, § Vocabulary). In a truth document, every sentence is present tense (§ The three natures). Every line owns a decision: before stating a rule, search the neighbours for it, and cite the one found rather than restating it (style guide § Net-net).
27
+ 6. **Write the frontmatter.** `type:` from the registry, `description:` in at most 300 characters saying what the document settles and where its boundary sits, then the genre's required keys (`references/frontmatter.md` for each key's rules).
28
+ 7. **Run the lint** from the repo root on the repo-relative path: `node <skill>/scripts/doc-lint.mjs docs/features/sign-in.md` (or `--changed`). Fix every `[block]` finding; read every `[warn]` and fix it unless the judgment it flags is genuinely yours. A disable takes bare rule ids, `<!-- doc-lint-disable: id -->`, alone on its own line for the whole file with the reason in a second comment on the next line, or at the end of one line for that line only.
29
+ 8. **Edit, don't append, on a substantive change to an existing truth document.** Keep its section shape, shed any history narration, progress marker or stale tripwire in the sections you touch, bump `last-reviewed:`, update `objects:` if what it designs changed, and remove any retired key on the way through.
29
30
 
30
31
  ---
31
32
 
@@ -67,7 +68,7 @@ The full strip-list and the record-side rules: `references/style-guide.md` § Th
67
68
  - **Intent and promises; facts are the graph's.** An owning document (feature, package, system) says 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, which function writes which column, which route sits behind which guard, which file holds what) is the code's, and a hand-typed copy is wrong the day the code moves. `doc-lint` blocks the retired mechanism sections (`mechanism-section`) and an owning document with no `objects:`.
68
69
  - **Read by people, pointed at by the footer.** Sharp bullets under noun-phrase headings, each a bold label, a colon, one or two plain sentences; code named only where a person types or sees it, or at a cross-cutting seam; every other pointer in the closing **For the agent** footer (style guide § Owning documents — the body and the footer).
69
70
  - **The stability test.** A sentence that would 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 on *why* (style guide § Shape).
70
- - **Unbuilt work has one home per kind.** Decided, unbuilt design sits in the body, wrapped in an `UNBUILT` marker; a shortfall in what is built is one bullet under Gaps; the work that would close either is a backlog row, which the document never tracks (style guide § The stability test).
71
+ - **Unbuilt work has one home per kind, outside doctrine.** A doctrine document is a specification and records no product's build state. Elsewhere, decided, unbuilt design sits in the body, wrapped in an `UNBUILT` marker; a shortfall in what is built is one bullet under Gaps; the work that would close either is a backlog row, which the document never tracks (style guide § The stability test).
71
72
  - **No empty stubs.** Omit a section with nothing real to say. Write "None" only where the absence is itself information, such as a plan's Cross-Module Contracts Affected.
72
73
  - **No redirect documents.** Moving a document deletes the old file and repoints every inbound link; a "Moved to X" stub rots and creates false search hits.
73
74
 
@@ -92,7 +93,8 @@ A document names the objects it designs in `objects:`, and a source file names t
92
93
  | Document a feature (LLD) | [`templates/feature.md`](templates/feature.md) |
93
94
  | Document a feature's data flow or state | The feature doc's Flows (behaviour) and Promises (guarantees); a persisted shape belongs in the API reference (style guide § State at persistence points); component and transient state are not documented |
94
95
  | Document a workspace package | [`templates/package.md`](templates/package.md), the residual owner of `packages/{name}/**` |
95
- | Document one concern the platform handles everywhere (authentication, storage, the API protocol) | [`templates/doctrine.md`](templates/doctrine.md): design and principles, no mechanism, owns no code |
96
+ | Document one concern the platform handles everywhere (authentication, storage, the API protocol) | [`templates/doctrine.md`](templates/doctrine.md): design and principles, no mechanism, owns no code; written through [`references/document-sets.md`](references/document-sets.md) |
97
+ | Write or rework several sibling documents at once (a doctrine folder, a family of features) | [`references/document-sets.md`](references/document-sets.md): usefulness test, term table, rule ledger, render, one cold read |
96
98
  | Document one system spanning packages | [`templates/system.md`](templates/system.md): one machine end to end, never a giant feature doc |
97
99
  | Record or revise an architecture decision | [`templates/architecture-decision.md`](templates/architecture-decision.md): one AD per subject, revised in place |
98
100
  | Create or update a changelog entry | [`templates/changelog-entry.md`](templates/changelog-entry.md) (record; frozen inside its commit; no row in `CHANGELOG.md`) |
@@ -125,12 +127,13 @@ A document names the objects it designs in `objects:`, and a source file names t
125
127
  | --- | --- |
126
128
  | `templates/Readme.md` | The genre registry: every genre's nature, `type:`, location, required keys and sections; `doc-lint` reads it |
127
129
  | `templates/` | One template per genre the registry names |
128
- | `references/style-guide.md` | The prose authority: the eight principles, depth per genre, the outside-in shape and stability test, labels and voice, owning documents, tense, diagrams, reference documents |
130
+ | `references/document-sets.md` | Writing several sibling documents as one design: the usefulness test, term table, rule ledger, render, and the review rubric the `doc-reviewer` agent reads |
131
+ | `references/style-guide.md` | The prose authority: the nine principles, what earns a line, depth per genre, the outside-in shape and stability test, labels and voice, owning documents, tense, diagrams, reference documents |
129
132
  | `references/frontmatter.md` | Each frontmatter key's rules, the transitional `owns:`, the retired keys |
130
133
  | `references/instruction-style.md` | The style for instruction files |
131
134
  | `references/untemplated.md` | Writing a document no template covers, and co-authoring one with a person |
132
135
  | `references/source-comments.md` | Source-file comments, and the scripts that check them |
133
136
  | `references/examples.md` | Good and bad documentation, side by side |
134
- | `scripts/doc-lint.mjs` | Mechanical checks over written docs: tense and history, dates, redirect stubs, frontmatter, the registry's keys and sections, index shape, owning-document body |
137
+ | `scripts/doc-lint.mjs` | Mechanical checks over written docs: tense and history, dates, redirect stubs, frontmatter, the registry's keys and sections, index shape, owning-document body, and a doctrine folder read as a set (citations resolve; no shared objects, restated sentences, body links or `UNBUILT` markers) |
135
138
  | `scripts/source-lint.mjs` | Mechanical checks over source comments; run `--changed` before finishing any change that writes source |
136
139
  | `scripts/comment-strip.mjs` | Proof that a comment sweep changed no executable code |
@@ -0,0 +1,95 @@
1
+ # Writing a set of documents
2
+
3
+ Load when writing or reworking more than one sibling document at once (a doctrine folder, a family of feature documents), or one doctrine document whose rules meet its siblings'. A single feature or package document needs only the steps in `SKILL.md`. One document joining an existing set runs every step below, with the existing documents as the rest of the set (§ One document into an existing set).
4
+
5
+ A set written one document at a time restates itself. Each document is made self-contained, so the same rule lands in four documents in four wordings, two of them contradict, and the defects surface only on rereading, which costs more than the writing did. So the set is designed once, as data, before any prose: every rule gets one home, every concept one name, and the review reads a table, where a fix is one edit, instead of twenty documents, where a fix is a reread of every one that states the rule.
6
+
7
+ ## 1. Usefulness test
8
+
9
+ For each proposed document, list the decisions only it would own: rules a reader would get wrong without it, each checked against the documents that exist, by a search for its distinctive phrase. A decision another document already states belongs to that document.
10
+
11
+ - **Fewer than about six owned decisions:** the document is a section of a neighbour, or its rules belong in several neighbours. Fold them and drop the document.
12
+ - **Two documents owning overlapping lists:** the boundary between them is not drawn. Redraw it or merge them.
13
+ - **The output:** the document list, each with its owned decisions and its boundary sentence (the questions next to it, and which document answers each).
14
+
15
+ ## 2. Term table
16
+
17
+ One row per concept: its name, a one-line definition, the one document that governs it (which lists it in `objects:`), and the synonyms it bans. The table comes before the ledger, because a rule written with two names for one concept becomes two rules.
18
+
19
+ The table starts from what the existing documents already name: every sibling's `objects:` and the definitions in its Terms table (an owning document's "For the agent" objects line). A new term is checked against them before it is used, because the collision a writer cannot see is with a name a sibling already gave another concept ("consent" for a client's scope, beside a sibling's consent of a data subject).
20
+
21
+ | Term | Means | Governed by | Not |
22
+ | --- | --- | --- | --- |
23
+ | operator | a person on the platform's own staff | authorization service | admin, staff account |
24
+
25
+ ## 3. Rule ledger
26
+
27
+ One row per rule, from the user's rulings, the documents that exist, and the code where it states a design:
28
+
29
+ | Id | Rule | Reason | Source | Home | As | Stated in | Cited by |
30
+ | --- | --- | --- | --- | --- | --- | --- | --- |
31
+ | R12 | A change that narrows access ends the sessions it affects | a narrowed role must not outlive its token | owner ruling 6 | auth service | principle 5 | auth service | authorization service, security |
32
+
33
+ - **A source for every row:** an owner's ruling, a sibling's statement, or the code where it states a design. A rule with no source (a case the rulings leave open, a consequence the writer finds plausible) is not a row: it is a question for the user, with a recommendation, and the documents say nothing on the case until it is answered. Rules a writer supplies itself are where a written set's own defects concentrate, because no one has decided them.
34
+
35
+ - **Stated in, searched, not remembered:** each row's distinctive phrase is searched across the existing documents, and every document already stating the rule is listed. The ledger's defects are mostly here: a rule the writer homes in a new document while a sibling still states it is a double home on the first read.
36
+ - **One home per rule:** the document whose question the rule answers. A rule that seems to need two homes is resolved here, by picking one and adding the other to "Cited by". A rule a sibling already states keeps that home unless the same change edits the sibling to cite the new one; a home moves only with both edits.
37
+ - **Contradictions resolved here:** two rows that cannot both hold are settled before any prose exists. Where one source plainly outranks the other (the owner's latest ruling over an older sibling sentence), the ledger follows it and the losing statement is a sibling edit owed; the rest go to the user in one batch with the open cases, a recommendation first for each.
38
+ - **As:** a principle where the rule holds across the document's parts, a part's decision where it holds for one part only.
39
+ - **Scratch, never committed:** the documents are the record, and a committed ledger would be a second copy to drift from them.
40
+
41
+ ## 4. Ledger review
42
+
43
+ One reviewer reads the ledger and the term table, not prose: the `doc-reviewer` agent in ledger mode, with § Rubric. Without the agent, a context-free sub-agent briefed with § Rubric and the paths, never the writer itself: a writer reviewing its own ledger passes its own blind spots, and in this skill's eval a self-reviewed ledger reached the cold read carrying seven blocking findings. Fixes land in the ledger, so every document rendered after them inherits them.
44
+
45
+ ## 5. Render
46
+
47
+ Each document is written from its ledger rows and nothing else:
48
+
49
+ - **Principles and part decisions:** each rule one sentence, and its reason the next wherever the rule meets a trigger of the style guide's § Sentences.
50
+ - **Part sections:** the rows homed as part decisions. A part with no such row gets no section.
51
+ - **Rules homed elsewhere:** a citation with the one clause of context the sentence needs (style guide principle 7), never the rule in new words.
52
+ - **A sentence with no row:** filler, which is cut. A rule the writer finds missing is a question for the user (§ 3), never a row the writer adds for itself.
53
+
54
+ Writers may run in parallel, one sub-agent per document or per few documents. Each brief carries the ledger, the term table, the template, the style guide's § Labels, § Voice (with § Sentences and § Vocabulary) and § Net-net, the rows homed in its documents, and the instruction to write only its own files. Each writer returns paths, not prose.
55
+
56
+ ## 6. Lint
57
+
58
+ `doc-lint` over the folder. Block findings are fixed. Each `sibling-duplicate` warning is a restatement the ledger did not ask for, or a row the ledger missed; fix it in the document.
59
+
60
+ ## 7. Review
61
+
62
+ One cold read of the set by the `doc-reviewer` agent in docs mode, with § Rubric. Its brief carries the paths and nothing of the session, because a reader who saw the session already knows every undefined term. Without the agent, a context-free sub-agent briefed with § Rubric does the read.
63
+
64
+ - **BLOCKING findings:** fixed.
65
+ - **NITs:** reported to the user as one list, never looped on.
66
+ - **After the fixes:** the changed lines only are verified: re-lint, and re-read each citation a fix touched. A fix never adds an unsourced rule: a finding that needs a decision the sources do not make (a Two readings the rulings left open) narrows the sentence to what the sources say and goes to the user as a question. There is no second full cold read: a review that keeps finding new BLOCKING items is reading prose the ledger never governed, so the fix is to the ledger and a re-render of the documents it touches.
67
+
68
+ ## One document into an existing set
69
+
70
+ - **The siblings are the set:** the term table and the ledger are built against them (§ 2, § 3), and the cold read reads the new document against them.
71
+ - **A fix that belongs in a sibling is made in the sibling,** in the same change: a rule whose home moved, a term renamed, a principle that now has an exception. Where the sibling is outside the change's scope, the fix is reported to the user as a sibling edit owed, never absorbed by restating the rule in the new document.
72
+ - **A contradiction with a sibling's principle** is never settled by the new document alone: it is an exception the sibling's principle must cite, or a question for the user.
73
+
74
+ ## Rubric
75
+
76
+ A finding names the file and line, quotes the text, names its class, and proposes the fix. "Could be clearer" with no fix is not a finding.
77
+
78
+ **BLOCKING:** the set is wrong, or unreadable as a set, until fixed.
79
+
80
+ | Class | The defect |
81
+ | --- | --- |
82
+ | Contradiction | Two statements that cannot both hold, in one document or across two |
83
+ | Double home | A rule stated, not cited, in two documents, or twice in one |
84
+ | Wrong citation | A citation whose target does not say what the citing sentence claims (the lint checks that it exists; the reader checks what it says) |
85
+ | Split term | Two names for one concept, or one name for two |
86
+ | No decision of its own | A document under about six owned decisions; a section, table or bullet that states nothing the principles do not |
87
+ | Missing reason | A rule that meets a trigger of the style guide's § Sentences (a tempting alternative, a cost, an arbitrary value, an invisible failure) and carries no reason |
88
+ | Filler | A sentence carrying no fact, rule, boundary or reason: a scene-setting opener, a generic truth used as framing, a metaphor or slogan standing in for a rule, a question |
89
+ | Wrong layer | Mechanism, a product's specifics or build state in doctrine; history in a truth document |
90
+ | Fused reason | A rule and its reason joined into one sentence, so a reader cannot tell which half binds |
91
+ | Two readings | A rule a reader could act on in two incompatible ways |
92
+
93
+ **NIT:** wording, order, a label, a sentence that could be shorter, a plainer synonym for a standard term, a cross-reference that would help. NITs never block.
94
+
95
+ In ledger mode the same classes apply to rows: two rows that contradict, a rule homed twice, a term used in two senses, a document left with fewer than about six rows, a row without its reason or without its source, a rule homed in a document whose question it does not answer.
@@ -7,18 +7,20 @@ This guide states how a document is written: every file under `docs/` and every
7
7
 
8
8
  ## The model
9
9
 
10
- A document is read by a person who wants to understand something or to act on it, and it is scanned more often than it is read. Every rule below follows from eight principles; later sections cite them by number.
10
+ A document is read by a person who wants to understand something or to act on it, and it is scanned more often than it is read. Every rule below follows from ten principles; later sections cite them by number.
11
11
 
12
12
  ### Principles
13
13
 
14
14
  1. **Three natures:** every document is a truth document (what is, now, rewritten in place), a record (what happened, dated and frozen) or a queue (work not done yet, rows appended and deleted when resolved). A truth document never narrates history, a record is never edited to match the present, and a queue holds only open rows, because a reader must be able to trust each without the others.
15
- 2. **The outside-in shape:** an explaining document opens on the question it answers and its boundary, then the model with its numbered principles, then the parts and their relations, then each part's decisions, and stops at its genre's deepest layer. Each layer is complete on its own, so a reader who stops at any layer holds a picture that is coarse but true, never a teaser the next section completes.
15
+ 2. **The outside-in shape:** an explaining document opens on what it defines and its boundary, then the model with its numbered principles, then the parts and their relations, then each part's decisions, and stops at its genre's deepest layer. Each layer is complete on its own, so a reader who stops at any layer holds a picture that is coarse but true. Headings name the concept a section covers, never the layer it sits in.
16
16
  3. **The stability test:** a sentence that would have to change when a function is renamed, a file moves, a route, column, error code or cookie attribute changes, or a constant is retuned without the design changing belongs to the code, which the code graph computes on demand (`docs/architecture/systems/knowledge-layer.md`), and not to the document. A copy typed into a document is at best a duplicate of the code and at worst a stale one.
17
- 4. **The authority split:** the code is the authority on *what*; the document is the authority on *why*. A disagreement on *what* means the document is stale and the code wins; a disagreement on *why* or on an invariant is a defect to raise, because one side is wrong on purpose.
17
+ 4. **The authority split:** the code is the authority on *what*; the document is the authority on *why*. A disagreement on *what* means the document is stale and the code wins; a disagreement on *why* or on an invariant is a defect to raise, because one side is wrong on purpose. Doctrine is the one exception: it is a specification, so code that differs from it has a gap to plan and build (`templates/doctrine.md`).
18
18
  5. **Noun-phrase labels, third-person sentences:** every heading and every bold bullet label names something and contains no finite verb, so it carries no tense, person or voice. The sentence after a label is third person, present tense, active, with the actor as its subject.
19
- 6. **A body scanned by people, a footer for the agent:** an owning document is bullets under noun-phrase headings, tables wherever the cases are parallel states, code named only where a person types or sees it or at a cross-cutting seam, and a closing "For the agent" footer that holds pointers, never an inventory.
19
+ 6. **A body scanned by people, a closing for the pointers:** an owning document is bullets under noun-phrase headings, tables wherever the cases are parallel states, code named only where a person types or sees it or at a cross-cutting seam, and a closing that holds pointers, never an inventory: "For the agent" in an owning document, Terms and Related documents in a doctrine document.
20
20
  7. **Self-contained, never padded:** the body reads whole without opening another file, restating the one sentence of context a borrowed concept needs and citing the authority for the rest. Length is a signal of a document that has let mechanism in, never a target.
21
21
  8. **Depth per genre:** doctrine stops at decisions and reasons, a system at behaviour across packages, a package at its public contract, a feature runs deepest at its end in Promises, and a reference document or runbook keeps full detail because the detail is its content.
22
+ 9. **Every line owns a decision:** a line earns its place by stating a rule, a reason, a boundary or a promise a reader would otherwise get wrong. A line restating a rule that has a home is a citation instead, and a line stating nothing is cut, because restatements drift apart and filler buries the rules a reader came for.
23
+ 10. **Standard terms, one rule per sentence:** a sentence uses the term engineers use for the thing, states one rule, and stops. Its reason, where the rule needs one (§ Sentences), is the next sentence. A plainer synonym reads as vague, and a rule fused with its reason hides which half binds.
22
24
 
23
25
  ## The genres
24
26
 
@@ -29,14 +31,14 @@ Every genre takes the same shape (principle 2) and the same labels (principle 5)
29
31
  | Doctrine (`docs/architecture/common/`) | Truth | The decisions behind each part and the reasons for them | Any mechanism. A doctrine document describes no code |
30
32
  | System (`docs/architecture/systems/`) | Truth | The machine's behaviour across packages: the order it runs in, sequence and state diagrams at role level, the invariant 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 |
31
33
  | Package (`docs/architecture/packages/`) | Truth | 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 |
32
- | Feature (`docs/features/`) | Truth | The behaviour a person meets, in full: each state the surface can be in, each edge case, what a refusal tells them, the wording where the wording is promised. This genre runs deepest toward its end, in Promises, because a promise is checked by a person or a test and the code cannot state it as intent | Columns, routes, guards, functions, files |
34
+ | Feature (`docs/features/`) | Truth | The behaviour a person meets, in full: each state the surface can be in, each edge case, what a rejection tells them, the wording where the wording is promised. This genre runs deepest toward its end, in Promises, because a promise is checked by a person or a test and the code cannot state it as intent | Columns, routes, guards, functions, files |
33
35
  | Reference (API reference, environment registry) | Truth | The contract itself: signatures, shapes, variables | Nothing. The detail is the point |
34
36
  | Operations procedure, migration runbook | Truth, record | The exact commands, in order, with their expected output | Nothing. The detail is the point |
35
37
  | Record (plan, changelog entry, runbook) | Record | Its template's fields, as of the moment it describes | Nothing. Its prose follows § Voice and § Labels; the dates and the journey are its own |
36
38
  | Queue (backlog, journal, bookkeeping, memory) | Queue | One row per open item, in its template's row grammar | Nothing. A row may carry its own date; a resolved row is deleted |
37
39
 
38
40
  - **Owning documents:** feature, package and system are the three genres that speak for code: source files name them in their headers, and the ownership scan resolves paths to them (`frontmatter.md`). They take principles 5 and 6 in full, their sections are fixed (§ Owning documents — the body and the footer), and `doc-lint` reads them. A UX document also speaks for a surface's components where none of the three does; its sections are its own genre's (`templates/ux-behavior.md`).
39
- - **Doctrine:** the same shape and labels as an owning document, speaking for no code and describing no mechanism. Its model layer may argue in paragraphs; below the model it is bullets like every other explaining document.
41
+ - **Doctrine:** the same shape and labels as an owning document, speaking for no code and describing no mechanism. Each section opens with a definition or the governing rule, never a lead-in, and continues in bullets like every other explaining document.
40
42
  - **Reference documents and procedures:** the one place a signature, a shape, a variable table, a command list or a file path is the content. They keep the detail the owning genres hand to the graph (§ Reference documents).
41
43
  - **Indexes:** a folder's `Readme.md` describes directories, never files — no link, filename or record ID per file; each file's own `description:` frontmatter is its account. The root README follows `templates/root-readme.md`. Both take § Labels.
42
44
 
@@ -46,20 +48,22 @@ Every truth document a person reads to understand something is written from the
46
48
 
47
49
  ### The layers
48
50
 
49
- 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.
50
- 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 cite them ("principle 3").
51
+ 1. **The definition and its boundary:** the opening states what the document defines, then what is in scope and what is out of scope, each out-of-scope item pointing to the document that owns it. No scene-setting before it, and no addresses, file paths or configuration in it.
52
+ 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 so later sections cite them ("principle 3"), each with its reason where the rule needs one (§ Sentences).
51
53
  3. **The parts:** one table or diagram placing every part in the model, then how the parts relate: what they share, where they meet, what keeps them apart.
52
- 4. **Each part in turn:** for each part, the decisions it rests on and why. A part's section opens with why the part exists, never with how it is built.
54
+ 4. **Each part in turn:** for each part, the decisions it rests on and why. A part's section opens with its definition or its governing rule, never with how it is built.
55
+
56
+ Each layer is carried by sections named for their concepts: "Callers", "Principles", "Credential families", "Capability links". A heading never names the layer itself: no "The model", "The parts", "In depth" or "Overview".
53
57
  5. **The genre's deepest layer:** the row for the genre in § The genres, and nothing deeper.
54
58
 
55
59
  An owning or doctrine document's fixed sections carry these layers; nothing is added beside them to hold a layer:
56
60
 
57
61
  | Layer | Feature | System | Package | Doctrine |
58
62
  | --- | --- | --- | --- | --- |
59
- | The question and its boundary | Goal line, Scope | Opening paragraph, Scope | Identity and goal lines, Scope | Opening paragraph |
60
- | The model | Scope's Covers bullet | Flow's opening | Usage's opening | The model |
61
- | The parts | Flows | Flow | Ownership, Usage | The parts |
62
- | Each part's decisions | Decisions | Decisions | Decisions | The parts in depth |
63
+ | The definition and its boundary | Goal line, Scope | Opening paragraph, Scope | Identity and goal lines, Scope | Opening sentence and scope bullets |
64
+ | The model | Scope's In scope bullet | Flow's opening | Usage's opening | The participant sections, then Principles |
65
+ | The parts | Flows | Flow | Ownership, Usage | The parts table and its relations |
66
+ | Each part's decisions | Decisions | Decisions | Decisions | One section per part |
63
67
  | The deepest layer | Promises | Promises | Promises | — |
64
68
 
65
69
  ### The stability test
@@ -71,16 +75,16 @@ The test (principle 3) decides what a sentence may say. These survive it:
71
75
  - **Decisions:** the choice made, and the alternative a reader would reach for.
72
76
  - **Promises:** what a person or a test can check.
73
77
  - **Cross-component contracts:** what no single file shows, such as two clients that must classify the same answer identically.
74
- - **Decided-but-unbuilt intent:** what the code cannot reveal because it does not yet do it, wrapped in `<!-- UNBUILT:START — {what, and the evidence it is not built} -->` … `<!-- UNBUILT:END -->` in plain words. A design decided *against* carries no marker.
78
+ - **Decided-but-unbuilt intent:** outside doctrine, what the code cannot reveal because it does not yet do it, wrapped in `<!-- UNBUILT:START — {what, and the evidence it is not built} -->` … `<!-- UNBUILT:END -->` in plain words. A design decided *against* carries no marker.
75
79
 
76
- Unbuilt work has one home per kind. Decided design the code does not do yet is an `UNBUILT` block where the design is stated; a shortfall in what is built (a promise the code does not keep, a case it mishandles) is one bullet under Gaps; the work that would close either is a backlog row, and the document never tracks that work's progress.
80
+ Unbuilt work has one home per kind. A doctrine document carries none of it, because it specifies every product and records no product's build state. Elsewhere, decided design the code does not do yet is an `UNBUILT` block where the design is stated; a shortfall in what is built (a promise the code does not keep, a case it mishandles) is one bullet under Gaps; the work that would close either is a backlog row, and the document never tracks that work's progress.
77
81
 
78
- The authority split (principle 4) is stated once, where agents enter the docs (the root instruction file or `docs/README.md`), so a reader who finds the code and the document disagreeing knows which way to resolve it. A doctrine document restates it in its opening, as the authority sentence (`templates/doctrine.md`), where its readers would otherwise not know; a feature, package or system document never does, because its opening is fixed to its goal.
82
+ The authority split (principle 4) is stated once, where agents enter the docs (the root instruction file or `docs/README.md`), so a reader who finds the code and the document disagreeing knows which way to resolve it. A doctrine document states its exception in its opening, as the specification sentence (`templates/doctrine.md`), where its readers would otherwise apply the default; a feature, package or system document never restates the split, because its opening is fixed to its goal.
79
83
 
80
84
  ### Diagrams and length by layer
81
85
 
82
86
  - **A diagram's layer:** at the model and parts layers a diagram 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.
83
- - **Length as a signal:** 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; the per-genre expectations are each template's.
87
+ - **Length as a signal:** a document whose reference tail is longer than its body is an inventory with an introduction. A doctrine document past about two hundred and fifty lines has usually let mechanism or restatement in; the per-genre expectations are each template's.
84
88
 
85
89
  ## Labels
86
90
 
@@ -115,10 +119,63 @@ The sentence after a label, and every sentence of running prose, describes the p
115
119
  - **Concision:** "Merges server data with local changes by version", never a sentence that restates its own subject twice. A function or a command is described by what it does ("Fetches data from the server", "Returns an array"), never by what it "is used to" do and never in the passive ("an array is returned").
116
120
  - **Bold:** marks a bullet's label or a defined term's first appearance, never a noun mid-sentence.
117
121
  - **Em-dash:** a budget of one per paragraph, never a joint between clauses.
118
- - **Terms of art:** introduced in plain words the first time they appear, the term itself in parentheses where a reader will meet it elsewhere.
119
122
  - **Inline code:** every identifier, filename, command, flag, environment variable and config key a document names is in backticks. Where a document may name code at all is § Owning documents — the body and the footer and § Reference documents.
120
123
  - **Decoration:** ❌ / ✅ only inside banned/blessed lists and comparison tables, never as general decoration; no emoji in headings.
121
124
 
125
+ ### Sentences
126
+
127
+ The reader is an engineer deciding what to build or checking what was built, so a sentence earns its place by carrying a fact, a rule, a boundary or a reason (principle 9). The test for any sentence: deleted, does the reader lose one of those? If not, it is cut.
128
+
129
+ - **One rule per sentence:** the rule is the sentence. Its reason, where it has one, is the next sentence, never joined to it by *so*, *so that*, *because* or *which means* (principle 10).
130
+ - **Reasons where a rule needs one:** a rule takes a reason when any of four holds, because a rule with no reason reads as a preference and leaves a disagreement nothing to argue with:
131
+
132
+ | Trigger | Example |
133
+ | --- | --- |
134
+ | The alternative is tempting: an engineer would reasonably do otherwise | retrying a failed signed token as a lookup; adopting an account by an unverified email |
135
+ | The rule costs something: friction, or a feature someone will ask for | no password-only administrators; a step-up prompt; no forced rotation |
136
+ | The value looks arbitrary: a number or a cutoff | a fifteen-minute window; a twenty-four-hour overlap |
137
+ | The failure is invisible: an attack or a drift no user or test would notice | a timing leak; an account takeover; data crossing organizations |
138
+
139
+ No reason is owed by a definition, by a rule a cited principle already justifies (the citation is the reason), or where the only reason restates the rule ("this keeps things secure").
140
+ - **The reason's size:** one sentence, after its rule, naming the concrete failure the rule prevents: "A cross-site page otherwise makes the browser send its cookie." Alternatives weighed and the argument behind a choice belong to an architecture decision (`decisions/`), which the document cites; the document carries the conclusion and its one line of why.
141
+ - **Length:** about twenty-five words at most, one idea each. A sentence listing three or more items introduces them with a colon, in parallel form, and is the one exception.
142
+ - **Statements, not modals:** a document states what happens ("the request is rejected"), never what must or should happen; its statements are requirements by being in it. "Never" marks a hard boundary, sparingly.
143
+ - **Declaratives only:** no questions, rhetorical or otherwise, and no *imagine*, *consider* or *suppose*.
144
+ - **Specific over general:** the concrete thing, never an abstract stand-in: role, credential, route, not power, proof, door.
145
+ - **No rhetoric:** no scene-setting opener, no generic truth used as framing, no metaphor, aphorism, personification, or phrasing inverted or balanced for effect, and no hedging (*generally*, *typically*, *in most cases*). State the rule and list its exceptions.
146
+
147
+ | ❌ Cut | Why | ✅ Keep |
148
+ | --- | --- | --- |
149
+ | "Every product on the enterprise plane must know exactly who is calling before it does anything else." | A truth no reader doubts, naming nothing, written to introduce the next sentence | "This document defines how a product identifies the caller of every request: one principal per request, step-up verification for sensitive actions, bounds on agent runs, and the credentials a product verifies itself." |
150
+ | "A key that makes keys turns one leak into unlimited keys, so a person's API key cannot mint keys." | Reason and rule fused, the rule last | "A person's API key cannot list, mint or revoke API keys. A credential that can mint credentials turns one leak into an unbounded set." |
151
+ | "the one caller whose next act nobody wrote down in advance" | Personification standing in for a definition | "An agent run is a job in which a model selects the next step." |
152
+ | "Many proofs, one person" | A balanced slogan in place of the rule | "**One principal per person:** handlers see the same principal however the person authenticated." |
153
+
154
+ ### Vocabulary
155
+
156
+ A document uses the term engineers use. A plainer synonym reads as vague and an elegant one as literary, and either one reads as a second concept (principle 10).
157
+
158
+ | Use | Not |
159
+ | --- | --- |
160
+ | verify, validate | prove, check, where verification is meant |
161
+ | reject, deny; rejection | refuse; refusal |
162
+ | resolve (a principal) | turn into, become |
163
+ | mint, issue (a credential) | create, make |
164
+ | route, endpoint | door, gate, page |
165
+ | permission, role | power, authority |
166
+ | origin, same-origin | the product's own site or pages |
167
+ | timestamp, recency | how recently, when it was last |
168
+ | constant-time comparison | a compare that leaks nothing |
169
+ | step-up verification | a fresh sign-in, proving it again |
170
+ | revoke | withdraw, kill (a credential, session or link) |
171
+
172
+ - **One term, defined once:** a term is defined once (in a doctrine document's Terms table, at its first appearance elsewhere) and used unchanged after; it is never varied for style.
173
+ - **"Doctrine" in prose:** the word is the genre's tooling name (`type: doctrine`, the template, the folder). A doctrine document calls itself "this document" or "this specification", and its neighbours "related documents".
174
+
175
+ ### Reach and lint
176
+
177
+ § Sentences and § Vocabulary bind doctrine and owning documents; records and queues take § Vocabulary and the person and tense rules. On a doctrine document `doc-lint` warns `modal-verb` (*must*, *should*, *shall* outside a quotation), `question` (a question mark in prose), `long-sentence` (past twenty-five words, a colon list exempt), `vague-term` (a word in the Not column above) and `doctrine-word` (the genre name in prose). A fused reason and rhetoric are judgment, and they are the cold read's (`document-sets.md` § Rubric).
178
+
122
179
  ## Owning documents — the body and the footer
123
180
 
124
181
  A feature, package or system document is scanned more than read (principle 6). It takes the shape (§ Shape — the model first, the detail after) and the labels (§ Labels) above, and these rules.
@@ -137,11 +194,11 @@ Nothing else. A "Why it exists" section has no place; its content is Scope or De
137
194
 
138
195
  - **The opening:** the goal is the first paragraph under the title, after the one identity line a package carries. No plan link and no routing line above it.
139
196
  - **Bullets:** each section is bullets under a noun-phrase heading; each bullet is a bold noun-phrase label, a colon, then one or two plain sentences saying what happens, what is decided or what is promised.
140
- - **Tables:** a table replaces the bullets wherever the cases are parallel states, such as each refusal and the exact message it shows. Its header cells are noun phrases.
141
- - **Paragraphs:** right for the goal, for a system's opening definition, and for a doctrine's model that needs an argument. Everywhere else, a paragraph is bullets that have not been cut yet.
197
+ - **Tables:** a table replaces the bullets wherever the cases are parallel states, such as each rejection and the exact message it shows. Its header cells are noun phrases.
198
+ - **Paragraphs:** right for the goal, for a system's opening definition, and for the one- or two-sentence definition that opens a section. Everywhere else, a paragraph is bullets that have not been cut yet.
142
199
  - **Code in the body:** named only where a person types or sees it (a page, a command, a flag, an environment variable) or 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 scheduler tick, a shared store holding part of the feature's logic because that logic is global. Written once, by name, where the narrative leaves the feature. Everything else is a plain name: "the device registry", "the sign-off page", "the mirror". `doc-lint` warns `body-identifier` past three identifiers in a section.
143
200
  - **Flows:** describe behaviour, never mechanism. A flow bullet says that a forgotten machine comes back on its next call, never which function re-mints the row. Behaviour in plain words is intent made legible; columns, routes, guards and signatures are the graph's.
144
- - **Promises:** the deepest section of a feature document: every state, edge case and refusal, and the exact wording where the wording is promised, each checkable by a person or a test. A promise reads "a removed membership shows a panel, not a redirect", never which route answers it.
201
+ - **Promises:** the deepest section of a feature document: every state, edge case and rejection, and the exact wording where the wording is promised, each checkable by a person or a test. A promise reads "a removed membership shows a panel, not a redirect", never which route answers it.
145
202
  - **Gaps:** a gap the code does not close is one bullet under Gaps, or a backlog row. It is never a ledger row inside another section, and never a temporal hedge.
146
203
 
147
204
  ### The footer
@@ -186,14 +243,45 @@ Every document is a truth document, a record or a queue (principle 1); `SKILL.md
186
243
 
187
244
  Worked example of the strip-and-relocate move: [`examples.md`](examples.md) Example 6.
188
245
 
246
+ ## Net-net — what earns a line
247
+
248
+ A document fails its reader less often by being wrong than by burying its rules under what it repeats (principle 9). The failure arrives one reasonable sentence at a time: each restatement helps where it stands, and the set reads as noise.
249
+
250
+ ### The line test
251
+
252
+ - **A decision of its own:** the line states a rule, its reason, a boundary or a promise, and a reader without it would act differently. Otherwise it is cut.
253
+ - **One home:** before a rule is stated, the document and its neighbours are searched for it, by a distinctive phrase. Found, it is cited ("(auth, principle 3)") with the one clause of context the sentence needs (principle 7), never restated in new words.
254
+ - **Once inside the document:** a part's section carries the decisions its principles do not state; a principle repeated as a bullet below it is a duplicate wearing a label.
255
+ - **One name per concept:** a concept keeps the one name the document set gave it (the term table in `document-sets.md`, or the `objects:` list for a single document); a synonym reads as a second concept.
256
+
257
+ ### What fails it
258
+
259
+ | ❌ | Why it fails | ✅ |
260
+ | --- | --- | --- |
261
+ | "The lock exists so that an unvetted organization can look around without creating anything." | Announces a purpose the next bullet states | "**Locked:** signs in and reads; creates and runs nothing." |
262
+ | A parts table whose every row reads "see principle 4" | Places nothing | No table |
263
+ | A Relations bullet restating principle 2 in other words | A second statement that will drift from the first | Cut, or cite principle 2 |
264
+ | A doctrine document whose every rule had a home elsewhere: attribution, key custody, a budget rejection, outbound deadlines | Owns no decision of its own | Each rule moved to its home; the document deleted |
265
+ | A rule stated in two sibling documents in different words | A reader cannot tell which binds, and the two drift | One home, one citation |
266
+ | A table of states, then a bullet per state restating its row | Every rule is stated twice, a page apart | The table for what each state allows; bullets only for the reasons |
267
+ | "Security matters at every layer." · "This section describes how…" | A truism and a ceremony: no decision | Cut; the heading already names the section |
268
+
269
+ ### Port hygiene
270
+
271
+ A document that changes scope (one product's design lifted into platform doctrine, or doctrine applied to one product) has every product name, setting value, code root, build state and product-specific example rewritten for the new scope or cut. Left in place, the residue reads as a rule binding every reader.
272
+
273
+ ### Proof
274
+
275
+ On a doctrine folder, `doc-lint` catches the mechanical half: a restated sentence (`sibling-duplicate`), a concept two documents govern (`objects-shared`), a citation to a principle or heading that does not exist (`citation-unresolved`), a purpose opener (`purpose-opener`). The rest is judgment, and it takes one cold read (`document-sets.md` § Review).
276
+
189
277
  ## Self-contained documents and the link surface
190
278
 
191
279
  Instruction files stay lean because an agent pays for them on every load (`instruction-style.md`); a document is read on demand, so it carries what its reader needs to understand the page (principle 7).
192
280
 
193
281
  - **Completeness:** the one or two sentences of context a borrowed concept needs are restated where it is used, because a reader forced mid-paragraph into a second document loses the thread of the first.
194
282
  - **Restatement and citation:** a changing detail (a version, a count, a path list) keeps one canonical home; the restatement carries what the page needs and points at the authority for the rest. Link-don't-copy governs where a fact is *owned*, not how readable the page that uses it must be.
195
- - **Inline links:** the minimum that action requires. A link mid-prose is right only where the reader must go there to act on this page, which includes a Scope section's "Not here" pointers.
196
- - **The closing link surface:** every other sister document belongs in the document's one closing section: "For the agent" (its neighbours line) in an owning or doctrine document, "Related" elsewhere. Deep relative paths (`../../../../…`) are fragile, since a folder move breaks every one, so they are confined to that block; body mentions use the plain name ("the boundary skill", "`structure.md`").
283
+ - **Inline links:** the minimum that action requires. A link mid-prose is right only where the reader must go there to act on this page, which includes the out-of-scope pointers in a Scope section or a doctrine document's opening.
284
+ - **The closing link surface:** every other sister document belongs in the document's one closing section: "For the agent" (its neighbours line) in an owning document, "Related documents" in a doctrine document, "Related" elsewhere. Deep relative paths (`../../../../…`) are fragile, since a folder move breaks every one, so they are confined to that block; body mentions use the plain name ("the boundary skill", "`structure.md`").
197
285
 
198
286
  ## Diagrams
199
287