@nurix/etna 0.20.26 → 0.20.28
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/README.md +15 -14
- package/bin/etna.js +61 -19
- package/data/harness-index.json +1 -1
- package/data/harnesses/code/codex/agents/bookkeeper.toml +1 -1
- package/data/harnesses/code/harness.json +6 -2
- package/data/harnesses/code/hooks/awareness.mjs +50 -2
- package/data/harnesses/code/hooks/hooks.json +1 -1
- package/data/harnesses/code/hooks/lib/backlog-detector.mjs +82 -0
- package/data/harnesses/code/hooks/lib/records-door.mjs +54 -0
- package/data/harnesses/code/hooks/mount.mjs +470 -0
- package/data/harnesses/code/skills/documentation/SKILL.md +6 -6
- package/data/harnesses/code/skills/documentation/references/examples.md +29 -25
- package/data/harnesses/code/skills/documentation/references/style-guide.md +211 -335
- package/data/harnesses/code/skills/documentation/references/untemplated.md +2 -1
- package/data/harnesses/code/skills/documentation/scripts/doc-lint.mjs +33 -17
- package/data/harnesses/code/skills/documentation/templates/doctrine.md +15 -16
- package/data/harnesses/code/skills/documentation/templates/feature.md +53 -17
- package/data/harnesses/code/skills/documentation/templates/handover.md +1 -1
- package/data/harnesses/code/skills/documentation/templates/package.md +38 -15
- package/data/harnesses/code/skills/documentation/templates/root-readme.md +16 -16
- package/data/harnesses/code/skills/documentation/templates/setup.md +1 -1
- package/data/harnesses/code/skills/documentation/templates/system.md +37 -15
- package/data/harnesses/delivery/harness.json +6 -2
- package/data/harnesses/delivery/skills/documentation/SKILL.md +6 -6
- package/data/harnesses/delivery/skills/documentation/references/examples.md +29 -25
- package/data/harnesses/delivery/skills/documentation/references/style-guide.md +211 -335
- package/data/harnesses/delivery/skills/documentation/references/untemplated.md +2 -1
- package/data/harnesses/delivery/skills/documentation/scripts/doc-lint.mjs +33 -17
- package/data/harnesses/delivery/skills/documentation/templates/doctrine.md +15 -16
- package/data/harnesses/delivery/skills/documentation/templates/feature.md +53 -17
- package/data/harnesses/delivery/skills/documentation/templates/handover.md +1 -1
- package/data/harnesses/delivery/skills/documentation/templates/package.md +38 -15
- package/data/harnesses/delivery/skills/documentation/templates/root-readme.md +16 -16
- package/data/harnesses/delivery/skills/documentation/templates/setup.md +1 -1
- package/data/harnesses/delivery/skills/documentation/templates/system.md +37 -15
- package/data/harnesses/discover/harness.json +4 -0
- package/data/harnesses/discussion/harness.json +4 -0
- package/data/harnesses/etna/harness.json +6 -2
- package/data/harnesses/etna/skills/documentation/SKILL.md +6 -6
- package/data/harnesses/etna/skills/documentation/references/examples.md +29 -25
- package/data/harnesses/etna/skills/documentation/references/style-guide.md +211 -335
- package/data/harnesses/etna/skills/documentation/references/untemplated.md +2 -1
- package/data/harnesses/etna/skills/documentation/scripts/doc-lint.mjs +33 -17
- package/data/harnesses/etna/skills/documentation/templates/doctrine.md +15 -16
- package/data/harnesses/etna/skills/documentation/templates/feature.md +53 -17
- package/data/harnesses/etna/skills/documentation/templates/handover.md +1 -1
- package/data/harnesses/etna/skills/documentation/templates/package.md +38 -15
- package/data/harnesses/etna/skills/documentation/templates/root-readme.md +16 -16
- package/data/harnesses/etna/skills/documentation/templates/setup.md +1 -1
- package/data/harnesses/etna/skills/documentation/templates/system.md +37 -15
- package/data/harnesses/hr/harness.json +4 -0
- package/data/harnesses/kb-agi/harness.json +4 -0
- package/lib/install/materialize.mjs +51 -23
- package/lib/install/mount.mjs +448 -0
- package/lib/install/plan.mjs +24 -29
- package/package.json +6 -3
|
@@ -22,6 +22,7 @@ When a draft wants to be both — the current state *and* the story of getting t
|
|
|
22
22
|
## 3. Shape it
|
|
23
23
|
|
|
24
24
|
- **Open with the goal.** The first line under the H1 states what the document is for and who reads it — a reader (or agent) landing here cold decides in one sentence whether to keep reading.
|
|
25
|
+
- **Headings are noun phrases** — no verb, no tense, no person (`references/style-guide.md` § Labels).
|
|
25
26
|
- **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
27
|
- **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
28
|
- **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.
|
|
@@ -30,7 +31,7 @@ When a draft wants to be both — the current state *and* the story of getting t
|
|
|
30
31
|
|
|
31
32
|
## 4. Write it in the house style
|
|
32
33
|
|
|
33
|
-
`references/style-guide.md` carries the rules: present tense with no history narration, progress markers, or stale-reference tripwires (§ The Two Natures);
|
|
34
|
+
`references/style-guide.md` carries the rules: present tense with no history narration, progress markers, or stale-reference tripwires (§ The Two Natures); third-person, present-tense, active sentences after noun-phrase labels (§ Voice, § Labels); diagrams in documents only, beside the prose and never in its place (§ Diagrams); signatures, state shapes and code examples under 15 lines in reference documents only (§ Reference documents).
|
|
34
35
|
|
|
35
36
|
## 5. With a human in the loop — the co-authoring workflow
|
|
36
37
|
|
|
@@ -17,7 +17,7 @@ const RULES = [
|
|
|
17
17
|
{ id: 'status-glyph', severity: 'warn', scope: 'truth', exempt: /(^|\/)docs\/(tests|operations)\//, pattern: /(^|\s)(✅|⏳|- \[[ x]\])/u, message: 'status glyph / checklist in a truth doc — tracking belongs in a record' },
|
|
18
18
|
// Truth docs are supposed to cite records, and record filenames are dated — so a date inside a link
|
|
19
19
|
// target or a code span is a path, not narration. Strip those before matching.
|
|
20
|
-
{ id: 'date-in-truth-doc', severity: 'block', scope: 'truth', strip: /\[[^\]]*\]\([^)]*\)|`[^`]*`|^(last-reviewed|last-updated|rev|harness-version):.*$/gm, pattern: /\b20\d{2}-\d{2}-\d{2}\b/, message: 'date in a truth doc — cite the record by name and link; the closed exceptions are the frontmatter tooling keys, an AD Decision Changelog tail and
|
|
20
|
+
{ id: 'date-in-truth-doc', severity: 'block', scope: 'truth', strip: /\[[^\]]*\]\([^)]*\)|`[^`]*`|^(last-reviewed|last-updated|rev|harness-version):.*$/gm, pattern: /\b20\d{2}-\d{2}-\d{2}\b/, message: 'date in a truth doc — cite the record by name and link; the closed exceptions are the frontmatter tooling keys, an AD Decision Changelog tail and a dated path inside a link or code span' },
|
|
21
21
|
];
|
|
22
22
|
|
|
23
23
|
// Sections inside a truth doc where dated history is sanctioned (the two bridges).
|
|
@@ -134,7 +134,7 @@ function lintFile(path, findings) {
|
|
|
134
134
|
const target = m[1];
|
|
135
135
|
if (/^[a-z]+:\/\//.test(target) || SCAFFOLD.test(target)) continue;
|
|
136
136
|
// The repo-root README routes by intent (templates/root-readme.md): its Map names owning package and system
|
|
137
|
-
// docs, its
|
|
137
|
+
// docs, its Destinations rows name procedures and rules. Individual feature docs stay off it — the ownership index finds them.
|
|
138
138
|
if (isRootReadme && /(^|\/)docs\/(architecture\/(packages|systems|common)\/|operations\/)[^/]+\.md$|(^|\/)\.claude\/rules\/[^/]+\.md$/.test(target)) continue;
|
|
139
139
|
if (isRootReadme && /(^|\/)docs\/features\/[^/]+\.md$/.test(target)) { findings.push({ path, n, severity: 'warn', id: 'root-readme-feature-link', message: `root README links an individual feature doc (\`${target}\`) — point at docs/features/ and let the ownership index find it`, excerpt: line.trim().slice(0, 90) }); continue; }
|
|
140
140
|
findings.push({ path, n, severity: 'block', id: 'index-lists-files', message: `index links an individual document (\`${target}\`) — name the folder and how its files are named; \`ls\` is the roster`, excerpt: line.trim().slice(0, 90) });
|
|
@@ -177,37 +177,53 @@ function lintFile(path, findings) {
|
|
|
177
177
|
if (!/^objects:/m.test(fm)) findings.push({ path, n: 1, severity: 'block', id: 'objects-missing', message: 'owning document names no `objects:` — the product objects it designs are its edge into the graph and its discovery terms' });
|
|
178
178
|
}
|
|
179
179
|
|
|
180
|
-
// The body of an owning document is
|
|
181
|
-
//
|
|
182
|
-
//
|
|
180
|
+
// The body of an owning document is scanned by people; its "For the agent" footer holds the pointers
|
|
181
|
+
// (style-guide § Owning documents — the body and the footer). Body identifiers warn, never block: a seam reference
|
|
182
|
+
// is allowed in the body, and the judgment of which identifier is a seam is the author's.
|
|
183
183
|
if (isOwningDoc) {
|
|
184
|
-
const OLD_SHAPE = /^##\s+(Background|Decisions|Promises|Objects|Related)\s*$/;
|
|
185
184
|
const footerAt = lines.findIndex(({ line }) => /^##\s+For the agent\b/.test(line));
|
|
186
185
|
const body = footerAt === -1 ? lines : lines.slice(0, footerAt);
|
|
187
186
|
let section = null; // proseLines already dropped the frontmatter and the fences
|
|
188
187
|
const sections = [];
|
|
189
188
|
for (const { n, line } of body) {
|
|
190
189
|
if (/^##\s+/.test(line)) {
|
|
191
|
-
|
|
192
|
-
section = { n, title: line.replace(/^##\s+/, '').trim(), bullets: 0, lines: 0, ids: 0, boldRun: 0, maxRun: 0 };
|
|
190
|
+
section = { n, title: line.replace(/^##\s+/, '').trim(), ids: 0 };
|
|
193
191
|
sections.push(section);
|
|
194
192
|
continue;
|
|
195
193
|
}
|
|
196
|
-
if (!section
|
|
197
|
-
section.lines++;
|
|
198
|
-
const isBullet = /^\s*[-*]\s+/.test(line);
|
|
199
|
-
if (isBullet) section.bullets++;
|
|
200
|
-
if (/^\s*[-*]\s+\*\*/.test(line)) { section.boldRun++; section.maxRun = Math.max(section.maxRun, section.boldRun); } else section.boldRun = 0;
|
|
194
|
+
if (!section) continue;
|
|
201
195
|
for (const m of line.matchAll(/`([^`]+)`/g)) {
|
|
202
196
|
const t = m[1];
|
|
197
|
+
// What a person types or sees is the feature's surface, not code: a page path, a flag, an environment variable, a command.
|
|
198
|
+
if (/^\/[a-z]|^--?[a-z]|^[A-Z][A-Z0-9_]+(=\S*)?$|^[a-z][\w-]* [a-z-]/.test(t)) continue;
|
|
203
199
|
if (/[\/]|\.(ts|tsx|mjs|js|md|json|sql)$|_|\(|^[a-z]+[A-Z]|^[A-Z][a-z]+[A-Z]|^(GET|POST|PUT|PATCH|DELETE) /.test(t)) section.ids++;
|
|
204
200
|
}
|
|
205
201
|
}
|
|
206
202
|
for (const s of sections) {
|
|
207
|
-
if (/^(Ownership|Known gaps)$/.test(s.title)) continue;
|
|
208
|
-
if (!disabled.has('body-identifier') && s.ids > 3) findings.push({ path, n: s.n, severity: 'warn', id: 'body-identifier', message: `${s.ids} code identifiers in a body section — the body names code only at a cross-cutting seam (a middleware, gate, hook, store); the rest is plain names
|
|
209
|
-
|
|
210
|
-
|
|
203
|
+
if (/^(Ownership|Gaps|Known gaps)$/.test(s.title)) continue;
|
|
204
|
+
if (!disabled.has('body-identifier') && s.ids > 3) findings.push({ path, n: s.n, severity: 'warn', id: 'body-identifier', message: `${s.ids} code identifiers in a body section — the body names code only where a person types or sees it, or at a cross-cutting seam (a middleware, gate, hook, store); the rest is plain names, with pointers in "For the agent"`, excerpt: s.title });
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
// A heading or a bold bullet label names; it never says. A label with a finite verb drags in a tense,
|
|
209
|
+
// a person and a voice ("What was decided", "You already belong to…"), so a label opening with a
|
|
210
|
+
// wh-word or a personal pronoun, or ending in a full stop, is a clause (style-guide § Labels).
|
|
211
|
+
const isLabelledDoc = isOwningDoc || (scope === 'truth' && !isFolderIndex && /(^|\/)docs\/architecture\/common\/[^/]+\.md$/.test(path));
|
|
212
|
+
if (isLabelledDoc && !disabled.has('clause-label')) {
|
|
213
|
+
const CLAUSE = /^(how|what|why|where|when|who|which|whose|you|your|we|our|i|it)\b|\b(you|your)\b|\.$/i;
|
|
214
|
+
for (const { n, line } of lines) {
|
|
215
|
+
const heading = /^#{2,4}\s+(.+?)\s*$/.exec(line);
|
|
216
|
+
const bold = /^\s*[-*]\s+\*\*(.+?)\*\*/.exec(line);
|
|
217
|
+
const label = heading ? heading[1] : bold ? bold[1].replace(/:$/, '').trim() : null;
|
|
218
|
+
if (!label || /^For the agent$/i.test(label)) continue;
|
|
219
|
+
if (CLAUSE.test(label.replace(/`[^`]*`/g, 'X'))) findings.push({ path, n, severity: 'warn', id: 'clause-label', message: 'a heading or bold label written as a clause — a label is a noun phrase with no verb, tense or person ("Decisions", not "What was decided"; "Organization member:", not "You already belong to an organization:")', excerpt: label.slice(0, 90) });
|
|
220
|
+
}
|
|
221
|
+
// The sentences after a label describe the product in the third person; quoted interface copy keeps its own "you".
|
|
222
|
+
if (!disabled.has('second-person')) {
|
|
223
|
+
for (const { n, line } of lines) {
|
|
224
|
+
const bare = line.replace(/`[^`]*`/g, '').replace(/\*\*[^*]+\*\*/g, 'X').replace(/\*"[^"]*"\*|\*[^*]+\*|"[^"]*"/g, '');
|
|
225
|
+
if (/\b(you|your|yours|yourself)\b/i.test(bare)) findings.push({ path, n, severity: 'warn', id: 'second-person', message: 'second person in a truth document — the sentence after a label is third person ("user lands…", never "you land…"); quoted interface copy is exempt', excerpt: line.trim().slice(0, 90) });
|
|
226
|
+
}
|
|
211
227
|
}
|
|
212
228
|
}
|
|
213
229
|
}
|
|
@@ -9,16 +9,15 @@ Truth document. Use for **one concern the platform handles everywhere**: authent
|
|
|
9
9
|
- the frontmatter
|
|
10
10
|
- the opening (the question, the boundary, and the authority sentence)
|
|
11
11
|
- **The model**, ending in numbered principles, each with its reason
|
|
12
|
-
- **The parts**: one table or diagram placing every part in the model, then
|
|
12
|
+
- **The parts**: one table or diagram placing every part in the model, then their relations
|
|
13
13
|
- **one section per part**
|
|
14
14
|
- **For the agent**
|
|
15
15
|
|
|
16
16
|
**Optional:**
|
|
17
17
|
|
|
18
18
|
- an `UNBUILT` block for decided-but-unbuilt intent
|
|
19
|
-
- **Related**
|
|
20
19
|
|
|
21
|
-
Nothing else. Expect one hundred and fifty to three hundred lines; past that, mechanism has usually crept in.
|
|
20
|
+
Nothing else: the neighbouring documents live in **For the agent**, the one closing link surface (`references/style-guide.md` § Self-contained documents and the link surface). Expect one hundred and fifty to three hundred lines; past that, mechanism has usually crept in.
|
|
22
21
|
|
|
23
22
|
```yaml
|
|
24
23
|
---
|
|
@@ -37,31 +36,31 @@ objects: [principal, credential, device grant] # recommended — the concepts
|
|
|
37
36
|
|
|
38
37
|
## The model
|
|
39
38
|
|
|
40
|
-
### {
|
|
39
|
+
### {The ownership boundary, as a noun phrase — e.g. "Identity: checked, not owned"}
|
|
41
40
|
|
|
42
|
-
{The one framing fact a reader needs before anything else
|
|
41
|
+
{The one framing fact a reader needs before anything else. Plain words, no addresses.}
|
|
43
42
|
|
|
44
|
-
### {The
|
|
43
|
+
### {The participants, as a noun phrase — e.g. "Callers"}
|
|
45
44
|
|
|
46
|
-
{Who or what participates
|
|
45
|
+
{Who or what participates: one bullet each, a bold noun-phrase label in plain words, its term of art in parentheses, then one line.}
|
|
47
46
|
|
|
48
|
-
### {The axis
|
|
47
|
+
### {The organizing axis, as a noun phrase — e.g. "Proof checking"}
|
|
49
48
|
|
|
50
|
-
{The one or two dimensions every part is placed on
|
|
49
|
+
{The one or two dimensions every part is placed on. A small table is right here.}
|
|
51
50
|
|
|
52
|
-
###
|
|
51
|
+
### Principles
|
|
53
52
|
|
|
54
|
-
{Numbered invariants that hold across every part
|
|
53
|
+
{Numbered invariants that hold across every part, each a bold noun-phrase label, then the rule and its reason in a sentence or two. Later sections cite them by number.}
|
|
55
54
|
|
|
56
|
-
## {The parts
|
|
55
|
+
## {The parts, as a noun phrase — e.g. "Credential families"}
|
|
57
56
|
|
|
58
|
-
{One table: each part placed on the model's axes. Then "
|
|
57
|
+
{One table: each part placed on the model's axes. Then a "Relations" subsection: what they share, where they meet, what keeps them apart, and the order in which they are tried — each a bullet with a bold noun-phrase label and its reason. A role-level diagram (mermaid) where the relationships are a flow.}
|
|
59
58
|
|
|
60
|
-
## {
|
|
59
|
+
## {The parts in depth, as a noun phrase — e.g. "Families in depth"}
|
|
61
60
|
|
|
62
|
-
### {
|
|
61
|
+
### {One part, named for who meets it — e.g. "Browser person", "Trusted system"}
|
|
63
62
|
|
|
64
|
-
{
|
|
63
|
+
{One line on why the part exists, then the decisions it rests on as bullets — a bold noun-phrase label, then the reason — citing principles by number. A sequence diagram at role level where the part is a flow. Detail that a person or test can check is welcome; detail that only restates the code is not.}
|
|
65
64
|
|
|
66
65
|
## For the agent
|
|
67
66
|
|
|
@@ -1,12 +1,31 @@
|
|
|
1
1
|
# Feature Documentation (docs/features/{feature}.md)
|
|
2
2
|
|
|
3
|
-
Truth document. Use for
|
|
3
|
+
Truth document. Use for every feature in `docs/features/`: something a person points at, such as an address, a command family or a named control. One file per feature, cut by the objects it designs, never by the code's routers, tables, plans or packages. The file persists from design (`status: draft`) to live reference (`status: active`).
|
|
4
4
|
|
|
5
|
-
**A document is
|
|
5
|
+
**A feature document is sharp, bulleted and actionable** (`references/style-guide.md` § Labels; § Shape — the model first, the detail after). A reader scans it rather than reads it:
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
- **Headings and bullet labels are noun phrases.** For example `Flows`, `Organization member`, `Dead grant` — never a clause like "How it works" or "You already belong to an organization".
|
|
8
|
+
- **Each bullet is a bold label, then one or two third-person sentences** saying what happens: "**Organization user:** user lands in their existing organization", never "you land…".
|
|
9
|
+
- **Flows carry the journey; Decisions carry the reasons; Promises run deepest.**
|
|
8
10
|
|
|
9
|
-
|
|
11
|
+
Every computable fact (columns, vocabularies, foreign keys, writers, routes, guards, files) is the code graph's (`docs/architecture/systems/knowledge-layer.md`), and a hand-typed copy is the defect this genre removes. Code is 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.
|
|
12
|
+
|
|
13
|
+
**A feature document runs deepest toward its end.** Scope and Flows are the model and the journey. **Promises** goes as deep as the behaviour does: every state the surface can be in, every edge case, what a refusal tells the person, and the exact wording wherever the wording itself is promised. That depth is earned because a person or a test checks it and the code cannot state it as intent. It still stops before mechanism. A promise reads "a removed membership shows a panel, not a redirect", never which route answers it.
|
|
14
|
+
|
|
15
|
+
**Sections:**
|
|
16
|
+
|
|
17
|
+
| Section | When |
|
|
18
|
+
| --- | --- |
|
|
19
|
+
| Frontmatter | required |
|
|
20
|
+
| Goal line | required |
|
|
21
|
+
| `Scope` | required |
|
|
22
|
+
| `Flows` | required |
|
|
23
|
+
| `Decisions` | once any choice was made that the code cannot explain |
|
|
24
|
+
| `Promises` | required |
|
|
25
|
+
| `Gaps` | only when there is one |
|
|
26
|
+
| `For the agent` | required |
|
|
27
|
+
|
|
28
|
+
Nothing else. `doc-lint` blocks the retired mechanism sections (`mechanism-section`), and warns on code identifiers in the body (`body-identifier`), on a heading or bullet label written as a clause (`clause-label`), and on "you" outside quoted copy (`second-person`).
|
|
10
29
|
|
|
11
30
|
```yaml
|
|
12
31
|
---
|
|
@@ -24,36 +43,53 @@ applies: [docs/architecture/common/security.md] # optional — doctrine this su
|
|
|
24
43
|
|
|
25
44
|
{One sentence: what this lets a person do.}
|
|
26
45
|
|
|
27
|
-
##
|
|
46
|
+
## Scope
|
|
28
47
|
|
|
29
|
-
|
|
48
|
+
- **Covers:** {the surfaces, commands and journeys this document owns}
|
|
49
|
+
- **Bound by:** {the doctrine documents it applies, each with what it settles}
|
|
50
|
+
- **Not here:** {the neighbouring features a reader might expect here, each linked}
|
|
30
51
|
|
|
31
|
-
##
|
|
52
|
+
## Flows
|
|
32
53
|
|
|
33
|
-
{
|
|
54
|
+
### {Entry point or situation, as a noun phrase — e.g. "Browser", "Terminal", "Landing", "Sign-out"}
|
|
34
55
|
|
|
35
|
-
|
|
56
|
+
- **{Noun-phrase label — e.g. "Signed-out visitor", "Claimed domain", "`nustack login`"}:** {what the user does or meets, and what happens. One or two sentences, third person, present tense — "user lands…", never "you land…".}
|
|
57
|
+
- {a sub-case, only where the parent genuinely branches}
|
|
36
58
|
|
|
37
|
-
|
|
59
|
+
## Decisions
|
|
38
60
|
|
|
39
|
-
|
|
61
|
+
- **{The decision as a noun phrase — e.g. "Single entry, no sign-up", "Unsigned organization cookie"}:** {why, in one or two sentences, and the alternative a reader would reach for if it matters.}
|
|
40
62
|
|
|
41
|
-
|
|
63
|
+
## Promises
|
|
42
64
|
|
|
43
|
-
|
|
65
|
+
### {Theme as a noun phrase — e.g. "Sign-in failures", "Gate outcomes", "Terminal grant states"}
|
|
44
66
|
|
|
45
|
-
{
|
|
67
|
+
{A table where the cases are parallel states — | Situation | What the person sees | — carrying the exact wording where the wording is promised. Bullets otherwise:}
|
|
68
|
+
|
|
69
|
+
- **{Noun-phrase label}:** {the guarantee or refusal, checkable by a person or a test.}
|
|
70
|
+
|
|
71
|
+
## Gaps
|
|
72
|
+
|
|
73
|
+
- **{Noun-phrase label}:** {what the code does not keep, and what closing it would take. The backlog row carries the rest.}
|
|
46
74
|
|
|
47
75
|
## For the agent
|
|
48
76
|
|
|
49
|
-
Objects
|
|
77
|
+
- **Objects:** {object}: {one plain line}; {object}: {…}
|
|
78
|
+
- **Pages:** {`/…`}
|
|
79
|
+
- **Commands:** {`nustack …`}
|
|
80
|
+
- **Code roots:** {`packages/…/src/…/`}, directories where the graph should start
|
|
81
|
+
- **Seams:** {`name`}, only where the roots would not lead to them
|
|
82
|
+
- **Checklist:** `tests/{feature}.md`
|
|
83
|
+
- **See also:** {neighbour}: {why}
|
|
84
|
+
|
|
85
|
+
No tables, routes or symbol rosters — those are the graph's.
|
|
50
86
|
```
|
|
51
87
|
|
|
52
88
|
### Lifecycle
|
|
53
89
|
|
|
54
90
|
| When | What is written |
|
|
55
91
|
| --- | --- |
|
|
56
|
-
| `status: draft` (design) | goal,
|
|
57
|
-
| `status: active` |
|
|
92
|
+
| `status: draft` (design) | goal, Scope, Decisions, Promises (with gaps named), For the agent; the LLD research goes to the plan |
|
|
93
|
+
| `status: active` | Flows written from the shipped surface; `owns:` confirmed against real code |
|
|
58
94
|
|
|
59
95
|
A feature whose code is gone is deleted, or `status: deprecated` with its footer pointing at what replaced it.
|
|
@@ -80,7 +80,7 @@ Each was taken because waiting would have stopped the run. Sorted by cost to rev
|
|
|
80
80
|
|
|
81
81
|
## 6. What was built
|
|
82
82
|
|
|
83
|
-
| Unit |
|
|
83
|
+
| Unit | Role for a person | Landed | Proof |
|
|
84
84
|
| --- | --- | --- | --- |
|
|
85
85
|
| {name} | {one clause, behaviour before mechanism} | {branch · PR · release} | {suite + counts, or "driven only", or empty} |
|
|
86
86
|
|
|
@@ -2,13 +2,27 @@
|
|
|
2
2
|
|
|
3
3
|
Truth document. Use for: **one workspace package** — one unit of distribution: a manifest, a build, a binary, a bundle, a Worker. One file per package, named for its folder.
|
|
4
4
|
|
|
5
|
-
**A document is read by people, and its footer is for the agent** (`references/style-guide.md` §
|
|
5
|
+
**A document is read by people, and its footer is for the agent** (`references/style-guide.md` § Owning documents — the body and the footer). A package document tells a person what the package is for, why it is its own unit, how it ships and to whom, how it is meant to be used, and what its consumers can rely on. Its manifest, build, entry, internal layout and test wiring are the code graph's (`docs/architecture/systems/knowledge-layer.md`), not a roster here.
|
|
6
6
|
|
|
7
|
-
**A package document's deepest layer is its public contract** (`references/style-guide.md` § Shape — the model first, the detail after): the commands and flags a person types, the exports another package imports, what is installed and where. For a CLI the flags *are* the promise, so they belong in
|
|
7
|
+
**A package document's deepest layer is its public contract** (`references/style-guide.md` § Shape — the model first, the detail after): the commands and flags a person types, the exports another package imports, what is installed and where. For a CLI the flags *are* the promise, so they belong in Usage. It stops before internal layout, build steps and which file holds what.
|
|
8
8
|
|
|
9
9
|
**A package document is the residual owner of its own tree.** Its `owns:` is the whole package glob — the broadest claim on those paths, so it loses to every narrower system or feature claim. The one enumerable fact it declares is the ownership table: which subtrees other documents claim.
|
|
10
10
|
|
|
11
|
-
**
|
|
11
|
+
**Sharp, bulleted, labelled with noun phrases** (`references/style-guide.md` § Labels). Every section after the goal line is bullets under a noun-phrase heading, each bullet a bold noun-phrase label followed by one or two sentences.
|
|
12
|
+
|
|
13
|
+
**Sections:** the frontmatter, the identity line and the goal line are required. Then:
|
|
14
|
+
|
|
15
|
+
| Section | When |
|
|
16
|
+
| --- | --- |
|
|
17
|
+
| `Scope` | required. Why the package is its own unit, who consumes it, and what it deliberately does not hold |
|
|
18
|
+
| `Ownership` | required, as one line or a table |
|
|
19
|
+
| `Usage` | required |
|
|
20
|
+
| `Decisions` | once any choice was made that the code cannot explain |
|
|
21
|
+
| `Promises` | required |
|
|
22
|
+
| `Gaps` | only when there is one |
|
|
23
|
+
| `For the agent` | required |
|
|
24
|
+
|
|
25
|
+
Nothing else. The feature template's lint rules apply. Forty to a hundred and twenty lines.
|
|
12
26
|
|
|
13
27
|
```yaml
|
|
14
28
|
---
|
|
@@ -27,9 +41,11 @@ applies: [docs/architecture/common/api.md] # optional
|
|
|
27
41
|
|
|
28
42
|
{One sentence: the job this package does in the product, for whom.}
|
|
29
43
|
|
|
30
|
-
##
|
|
44
|
+
## Scope
|
|
31
45
|
|
|
32
|
-
|
|
46
|
+
- **Role:** {what it holds that nothing else does}
|
|
47
|
+
- **Consumers:** {who consumes it, and how and when it ships}
|
|
48
|
+
- **Not here:** {what it deliberately does not hold, and where that lives}
|
|
33
49
|
|
|
34
50
|
## Ownership
|
|
35
51
|
|
|
@@ -39,27 +55,34 @@ This document is the residual owner of `packages/{name}/**`. Claimed at higher s
|
|
|
39
55
|
| --- | --- |
|
|
40
56
|
| `src/{machine}/**` | [{system}](../systems/{system}.md) |
|
|
41
57
|
|
|
42
|
-
##
|
|
58
|
+
## Usage
|
|
43
59
|
|
|
44
|
-
{
|
|
60
|
+
- **{Noun-phrase label — e.g. "Install", "`nustack login`", "Import"}:** {what a person or another package does with it, and what they see. The public contract (commands, flags, exports) belongs here.}
|
|
45
61
|
|
|
46
|
-
##
|
|
62
|
+
## Decisions
|
|
47
63
|
|
|
48
|
-
{
|
|
64
|
+
- **{The decision as a noun phrase}:** {why.}
|
|
49
65
|
|
|
50
|
-
##
|
|
66
|
+
## Promises
|
|
51
67
|
|
|
52
|
-
{
|
|
68
|
+
- **{Noun-phrase label}:** {what a consumer can rely on, or what the package refuses; checkable.}
|
|
53
69
|
|
|
54
|
-
##
|
|
70
|
+
## Gaps
|
|
55
71
|
|
|
56
|
-
{
|
|
72
|
+
- **{Noun-phrase label}:** {what is missing and what it would take.}
|
|
57
73
|
|
|
58
74
|
## For the agent
|
|
59
75
|
|
|
60
|
-
Objects
|
|
76
|
+
- **Objects:** {…}
|
|
77
|
+
- **Commands and exports:** {…} — the public contract
|
|
78
|
+
- **Code root:** `packages/{name}/`
|
|
79
|
+
- **Seams:** {…} by name
|
|
80
|
+
- **Checklist:** `tests/{package}.md`
|
|
81
|
+
- **See also:** {neighbour}: {why}
|
|
82
|
+
|
|
83
|
+
No file lists or symbol rosters — those are the graph's.
|
|
61
84
|
```
|
|
62
85
|
|
|
63
86
|
### Marking what is decided and unbuilt
|
|
64
87
|
|
|
65
|
-
`<!-- UNBUILT:START — {…} -->` … `<!-- UNBUILT:END -->` around the
|
|
88
|
+
`<!-- UNBUILT:START — {…} -->` … `<!-- UNBUILT:END -->` around the bullets for a decided, unbuilt half; a design decided *against* carries no marker.
|
|
@@ -7,14 +7,14 @@ Truth document. Use for: the repository root `/README.md`. It opens outward —
|
|
|
7
7
|
Sections come in this order; 1 to 3 are the outward-facing first screen, 4 onward the inward page. Skip any section the repo cannot fill truthfully. Never pad it, and never leave a stub.
|
|
8
8
|
|
|
9
9
|
1. **Identity.** The H1 plus two or three sentences in a user's terms: what the product is, where it runs, and what using it is like.
|
|
10
|
-
2. **
|
|
11
|
-
3. **
|
|
10
|
+
2. **Capabilities.** Two to four paragraphs, outward-facing: the core loop as a person meets it, what surrounds that loop, how the product follows the person across its surfaces, and who it is for, closing with what it deliberately is not. Plain words, no feature roster, no superlatives.
|
|
11
|
+
3. **Deployment.** One paragraph: the addresses, the distributed artifacts and where they are published, where identity comes from, and whether a self-hosted edition exists.
|
|
12
12
|
4. **The turn.** A rule and one paragraph saying the rest is for the team and agents, with the scope line: what lives in this repo and what lives elsewhere.
|
|
13
13
|
5. **State.** Optional: a one-line blockquote, present only while something repo-wide is true that a newcomer must know (frozen, mid-migration, mid-breaking-change on `dev`). It links the plan or runbook that owns the change. Say here which units publish and where, if any do.
|
|
14
|
-
6. **
|
|
15
|
-
7. **
|
|
14
|
+
6. **The main path.** Three to six short paragraphs, or numbered stages, along the main request or data path: who arrives, what is built, where state lives, how the result leaves. Name a technology only where it explains a stage. End with a link to the system overview.
|
|
15
|
+
7. **Repository map.** A sentence on how the tree is organised, then one table row per top-level unit (package, app, service), giving its path, what it is in one line, and its owning doc; the top folders that are not packages get a sentence each. This replaces the tree.
|
|
16
16
|
8. **Rules that bite.** Optional. At most five one-line invariants, public/internal boundaries, never-edit paths (generated, protected) or non-goals, each linked to the doc that argues it.
|
|
17
|
-
9. **
|
|
17
|
+
9. **Destinations.** An intent-to-destination table. Its last row is the one for agents.
|
|
18
18
|
10. **Everyday commands.** Optional. At most four commands run on every change, ending at the gate a push must pass. First-run commands are never here.
|
|
19
19
|
|
|
20
20
|
### What it leaves out
|
|
@@ -31,11 +31,11 @@ Sections come in this order; 1 to 3 are the outward-facing first screen, 4 onwar
|
|
|
31
31
|
|
|
32
32
|
### Writing rules
|
|
33
33
|
|
|
34
|
-
- **Budget: between 60 and 140 non-blank lines, the outward part under a third of it.** Prose is welcome —
|
|
34
|
+
- **Budget: between 60 and 140 non-blank lines, the outward part under a third of it.** Prose is welcome — The main path and Rules that bite read better as paragraphs than as rows — but past the ceiling a section is hosting content that belongs in a doc. Move it and leave the link.
|
|
35
35
|
- **Every section is either a fact the reader acts on or a link.** If a section needs a paragraph, it needs a doc.
|
|
36
36
|
- **One H1, then H2 sections, in plain Markdown.** Sentence-case headings, no emoji, no HTML layout, and no `#` comment lines inside code blocks (they parse as H1s).
|
|
37
37
|
- **Relative links into the repo only.** Never an absolute repo URL. Never an external site as the home of a canonical doc.
|
|
38
|
-
- **Link folders and mandated scaffolds, never rosters.** The allowed targets are folders, `docs/README.md`, `docs/structure.md`, `docs/operations/setup.md`, `docs/history/CHANGELOG.md`, `docs/history/backlog.md`, `CLAUDE.md` and the owning docs in the Map. A procedure is named only where a
|
|
38
|
+
- **Link folders and mandated scaffolds, never rosters.** The allowed targets are folders, `docs/README.md`, `docs/structure.md`, `docs/operations/setup.md`, `docs/history/CHANGELOG.md`, `docs/history/backlog.md`, `CLAUDE.md` and the owning docs in the Map. A procedure is named only where a Destinations row needs it. Every heading and table header is a noun phrase (`../references/style-guide.md` § Labels). Never list individual feature docs: the ownership index finds them.
|
|
39
39
|
- **No tree.** The Map stops at top-level units and never lists files. Mark paths that look primary but are not, for example "`legacy/`: reference only, never edited".
|
|
40
40
|
- **The Map is a coarse view of the ownership index, not a rival to it.** The Owning doc column names the doc that the index's `owns:` globs resolve to. When the two disagree the index wins, and the Map row is fixed in the same change.
|
|
41
41
|
- **No version numbers and no dates.** Name the file that pins a version (`.nvmrc`, `packageManager`, `rust-toolchain.toml`). Write in the present tense, with no "coming soon" and no "as of".
|
|
@@ -49,7 +49,7 @@ Sections come in this order; 1 to 3 are the outward-facing first screen, 4 onwar
|
|
|
49
49
|
|
|
50
50
|
{Two or three sentences in a user's terms: what the product is, where it runs, what using it is like.}
|
|
51
51
|
|
|
52
|
-
##
|
|
52
|
+
## Capabilities
|
|
53
53
|
|
|
54
54
|
{The core loop as a person meets it: what they bring, what the product does, what they get back and what record it leaves.}
|
|
55
55
|
|
|
@@ -59,7 +59,7 @@ Sections come in this order; 1 to 3 are the outward-facing first screen, 4 onwar
|
|
|
59
59
|
|
|
60
60
|
{Who it is for, and what it deliberately is not.}
|
|
61
61
|
|
|
62
|
-
##
|
|
62
|
+
## Deployment
|
|
63
63
|
|
|
64
64
|
{Addresses; distributed artifacts and where they publish; where identity comes from; whether a self-hosted edition exists.}
|
|
65
65
|
|
|
@@ -69,7 +69,7 @@ The rest of this page is for the team and for coding agents working in this repo
|
|
|
69
69
|
|
|
70
70
|
> **State:** {one line: what is in flux right now; which units publish where} → [{plan or runbook}](docs/history/{plans|migrations}/{file}.md) ← optional; delete when the flux ends
|
|
71
71
|
|
|
72
|
-
##
|
|
72
|
+
## The main path
|
|
73
73
|
|
|
74
74
|
1. **{Stage}**: {what happens, naming the mechanism only where it explains the step}.
|
|
75
75
|
2. **{Stage}**: {…}.
|
|
@@ -78,7 +78,7 @@ The rest of this page is for the team and for coding agents working in this repo
|
|
|
78
78
|
|
|
79
79
|
{Optional, one sentence naming the seam everything passes through, e.g. "Every client reaches data through `{path}`; nothing else talks to the database."} The full account: [{system overview}](docs/architecture/{overview}.md).
|
|
80
80
|
|
|
81
|
-
##
|
|
81
|
+
## Repository map
|
|
82
82
|
|
|
83
83
|
{One or two sentences: the workspace shape and where each unit's design document lives.}
|
|
84
84
|
|
|
@@ -99,9 +99,9 @@ The rest of this page is for the team and for coding agents working in this repo
|
|
|
99
99
|
- **{Never-edit paths}**: `{path}` is {generated by `{command}` | protected}; edit {the source} instead.
|
|
100
100
|
- **Not here:** {a non-goal stated as a refusal}.
|
|
101
101
|
|
|
102
|
-
##
|
|
102
|
+
## Destinations
|
|
103
103
|
|
|
104
|
-
|
|
|
104
|
+
| Intent | Destination |
|
|
105
105
|
| --- | --- |
|
|
106
106
|
| Set up a machine and run it the first time | [docs/operations/setup.md](docs/operations/setup.md) |
|
|
107
107
|
| Work on it day to day | [docs/operations/{local-development}.md](docs/operations/{local-development}.md) |
|
|
@@ -130,12 +130,12 @@ The rest of this page is for the team and for coding agents working in this repo
|
|
|
130
130
|
|
|
131
131
|
The baseline **does** scaffold `/README.md` when it is missing, and it fills each section from the repo:
|
|
132
132
|
|
|
133
|
-
- **Identity,
|
|
134
|
-
- **
|
|
133
|
+
- **Identity, Capabilities, Deployment:** from the product charter and vision documents under `docs/architecture/common/` (what the product is, the core loop, who it is for), the package manifests (what publishes where), and the deploy config (addresses). Written in a user's terms; where the charter is missing, the baseline writes Identity only and raises a `note:` row for the rest.
|
|
134
|
+
- **The main path:** from the system overview.
|
|
135
135
|
- **Map:** from the workspace globs and the ownership index.
|
|
136
136
|
- **Rules:** from `docs/operations/protected-files.md` and the architecture doctrine.
|
|
137
137
|
- **Commands:** from the lockfile and the root scripts.
|
|
138
|
-
- **
|
|
138
|
+
- **Destinations:** only the rows whose targets exist.
|
|
139
139
|
|
|
140
140
|
It drops every section it cannot fill concretely.
|
|
141
141
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Setup (docs/operations/setup.md)
|
|
2
2
|
|
|
3
|
-
Truth document, operations genre (`type: operations`). Use for: **the one-time path from a fresh machine to a first verified run.** It covers what the repo is built on, prerequisites, install, env files, local services, the first commands, proof that it works, and the failures a fresh clone hits. There is **one per repo**, always named `setup.md`, and it is a mandated scaffold. The root README's only setup content is a
|
|
3
|
+
Truth document, operations genre (`type: operations`). Use for: **the one-time path from a fresh machine to a first verified run.** It covers what the repo is built on, prerequisites, install, env files, local services, the first commands, proof that it works, and the failures a fresh clone hits. There is **one per repo**, always named `setup.md`, and it is a mandated scaffold. The root README's only setup content is a Destinations row linking it.
|
|
4
4
|
|
|
5
5
|
It is distinct from `local-development.md`, the daily loop: watch modes, resetting state, per-package traps, the inner test cycle. Setup runs once per machine. Local development runs every session. Setup ends by handing off to it, and neither copies the other. Deploying is `deployment.md`.
|
|
6
6
|
|
|
@@ -2,13 +2,26 @@
|
|
|
2
2
|
|
|
3
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 document is read by people, and its footer is for the agent** (`references/style-guide.md` §
|
|
5
|
+
**A document is read by people, and its footer is for the agent** (`references/style-guide.md` § Owning documents — the body and the footer). 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
|
-
**
|
|
11
|
+
**Sharp, bulleted, labelled with noun phrases** (`references/style-guide.md` § Labels). The opening paragraph defines the machine; everything after it is bullets under noun-phrase headings, each bullet a bold noun-phrase label followed by one or two sentences.
|
|
12
|
+
|
|
13
|
+
**Sections:** the frontmatter and the opening paragraph (the machine defined in its first sentence, what enters, what it leaves behind) are required. Then:
|
|
14
|
+
|
|
15
|
+
| Section | When |
|
|
16
|
+
| --- | --- |
|
|
17
|
+
| `Scope` | required. What this document does not decide, and which document does — subjects with owners, never bare links |
|
|
18
|
+
| `Flow` | required |
|
|
19
|
+
| `Decisions` | once any choice was made that the code cannot explain, including why this is one machine and not two |
|
|
20
|
+
| `Promises` | required |
|
|
21
|
+
| `Gaps` | only when there is one |
|
|
22
|
+
| `For the agent` | required |
|
|
23
|
+
|
|
24
|
+
Nothing else. The lint rules of the feature template apply. Sixty to a hundred and sixty lines.
|
|
12
25
|
|
|
13
26
|
```yaml
|
|
14
27
|
---
|
|
@@ -27,33 +40,42 @@ applies: # optional — decisions and do
|
|
|
27
40
|
|
|
28
41
|
{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.}
|
|
29
42
|
|
|
30
|
-
|
|
43
|
+
## Scope
|
|
31
44
|
|
|
32
|
-
|
|
45
|
+
- **Covers:** {what this machine decides}
|
|
46
|
+
- **Not here:** {subject} — {owning document}; {subject} — {owning document}
|
|
33
47
|
|
|
34
|
-
|
|
48
|
+
## Flow
|
|
35
49
|
|
|
36
|
-
|
|
50
|
+
### {Stage as a noun phrase — e.g. "Intake", "Settlement", "Re-drive"}
|
|
37
51
|
|
|
38
|
-
{
|
|
52
|
+
- **{Noun-phrase label}:** {what starts it or what it does at this step, as a person would describe it; what it writes that outlives it; what it refuses.}
|
|
39
53
|
|
|
40
|
-
|
|
54
|
+
{A role-level sequence or state diagram where the stages cross packages.}
|
|
41
55
|
|
|
42
|
-
|
|
56
|
+
## Decisions
|
|
43
57
|
|
|
44
|
-
|
|
58
|
+
- **{The decision as a noun phrase}:** {why; the alternative only where a reader would reach for it.}
|
|
45
59
|
|
|
46
|
-
|
|
60
|
+
## Promises
|
|
47
61
|
|
|
48
|
-
|
|
62
|
+
- **{Noun-phrase label}:** {a checkable guarantee or refusal; what holds at the far end; what a stalled run gets.}
|
|
49
63
|
|
|
50
|
-
|
|
64
|
+
## Gaps
|
|
65
|
+
|
|
66
|
+
- **{Noun-phrase label}:** {what is missing and what it would take.}
|
|
51
67
|
|
|
52
68
|
## For the agent
|
|
53
69
|
|
|
54
|
-
Objects
|
|
70
|
+
- **Objects:** {…}
|
|
71
|
+
- **Code roots:** {…} — directories, one per package the machine spans
|
|
72
|
+
- **Seams:** {…} by name
|
|
73
|
+
- **Checklist:** `tests/{system}.md`
|
|
74
|
+
- **See also:** {neighbour}: {why}
|
|
75
|
+
|
|
76
|
+
No tables, routes or symbol rosters — those are the graph's.
|
|
55
77
|
```
|
|
56
78
|
|
|
57
79
|
### Marking what is decided and unbuilt
|
|
58
80
|
|
|
59
|
-
Where a stage is decided and not built, wrap its
|
|
81
|
+
Where a stage is decided and not built, wrap its bullets in `<!-- UNBUILT:START — {what, where decided, the evidence it is not built} -->` … `<!-- UNBUILT:END -->` and say under Promises what runs instead. A design decided *against* carries no marker.
|