@nurix/etna 0.20.25 → 0.20.26

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (72) hide show
  1. package/data/harness-index.json +1 -1
  2. package/data/harnesses/code/CLAUDE.md +4 -4
  3. package/data/harnesses/code/agents/bookkeeper.md +1 -1
  4. package/data/harnesses/code/agents/change-review.md +1 -1
  5. package/data/harnesses/code/agents/lld-mode.md +1 -1
  6. package/data/harnesses/code/agents/maintenance.md +7 -9
  7. package/data/harnesses/code/docs/structure.md +133 -71
  8. package/data/harnesses/code/harness.json +4 -4
  9. package/data/harnesses/code/hooks/awareness.mjs +0 -10
  10. package/data/harnesses/code/hooks/lib/ownership.mjs +4 -2
  11. package/data/harnesses/code/hooks/lib/sweep.mjs +4 -8
  12. package/data/harnesses/code/skills/documentation/SKILL.md +19 -8
  13. package/data/harnesses/code/skills/documentation/references/frontmatter.md +3 -3
  14. package/data/harnesses/code/skills/documentation/references/style-guide.md +70 -27
  15. package/data/harnesses/code/skills/documentation/references/untemplated.md +2 -1
  16. package/data/harnesses/code/skills/documentation/scripts/doc-lint.mjs +87 -1
  17. package/data/harnesses/code/skills/documentation/templates/Readme.md +4 -3
  18. package/data/harnesses/code/skills/documentation/templates/bookkeeping.md +1 -1
  19. package/data/harnesses/code/skills/documentation/templates/docs-readme.md +15 -36
  20. package/data/harnesses/code/skills/documentation/templates/doctrine.md +82 -0
  21. package/data/harnesses/code/skills/documentation/templates/feature.md +31 -123
  22. package/data/harnesses/code/skills/documentation/templates/handover.md +174 -0
  23. package/data/harnesses/code/skills/documentation/templates/operations-procedure.md +1 -1
  24. package/data/harnesses/code/skills/documentation/templates/package.md +28 -94
  25. package/data/harnesses/code/skills/documentation/templates/root-readme.md +103 -65
  26. package/data/harnesses/code/skills/documentation/templates/setup.md +138 -0
  27. package/data/harnesses/code/skills/documentation/templates/system.md +25 -109
  28. package/data/harnesses/delivery/agents/lld-mode.md +1 -1
  29. package/data/harnesses/delivery/agents/maintenance.md +7 -9
  30. package/data/harnesses/delivery/harness.json +2 -2
  31. package/data/harnesses/delivery/skills/documentation/SKILL.md +19 -8
  32. package/data/harnesses/delivery/skills/documentation/references/frontmatter.md +3 -3
  33. package/data/harnesses/delivery/skills/documentation/references/style-guide.md +70 -27
  34. package/data/harnesses/delivery/skills/documentation/references/untemplated.md +2 -1
  35. package/data/harnesses/delivery/skills/documentation/scripts/doc-lint.mjs +87 -1
  36. package/data/harnesses/delivery/skills/documentation/templates/Readme.md +4 -3
  37. package/data/harnesses/delivery/skills/documentation/templates/bookkeeping.md +1 -1
  38. package/data/harnesses/delivery/skills/documentation/templates/docs-readme.md +15 -36
  39. package/data/harnesses/delivery/skills/documentation/templates/doctrine.md +82 -0
  40. package/data/harnesses/delivery/skills/documentation/templates/feature.md +31 -123
  41. package/data/harnesses/delivery/skills/documentation/templates/handover.md +174 -0
  42. package/data/harnesses/delivery/skills/documentation/templates/operations-procedure.md +1 -1
  43. package/data/harnesses/delivery/skills/documentation/templates/package.md +28 -94
  44. package/data/harnesses/delivery/skills/documentation/templates/root-readme.md +103 -65
  45. package/data/harnesses/delivery/skills/documentation/templates/setup.md +138 -0
  46. package/data/harnesses/delivery/skills/documentation/templates/system.md +25 -109
  47. package/data/harnesses/etna/agents/change-review.md +1 -1
  48. package/data/harnesses/etna/agents/lld-mode.md +1 -1
  49. package/data/harnesses/etna/agents/maintenance.md +7 -9
  50. package/data/harnesses/etna/harness.json +2 -2
  51. package/data/harnesses/etna/skills/documentation/SKILL.md +19 -8
  52. package/data/harnesses/etna/skills/documentation/references/frontmatter.md +3 -3
  53. package/data/harnesses/etna/skills/documentation/references/style-guide.md +70 -27
  54. package/data/harnesses/etna/skills/documentation/references/untemplated.md +2 -1
  55. package/data/harnesses/etna/skills/documentation/scripts/doc-lint.mjs +87 -1
  56. package/data/harnesses/etna/skills/documentation/templates/Readme.md +4 -3
  57. package/data/harnesses/etna/skills/documentation/templates/bookkeeping.md +1 -1
  58. package/data/harnesses/etna/skills/documentation/templates/docs-readme.md +15 -36
  59. package/data/harnesses/etna/skills/documentation/templates/doctrine.md +82 -0
  60. package/data/harnesses/etna/skills/documentation/templates/feature.md +31 -123
  61. package/data/harnesses/etna/skills/documentation/templates/handover.md +174 -0
  62. package/data/harnesses/etna/skills/documentation/templates/operations-procedure.md +1 -1
  63. package/data/harnesses/etna/skills/documentation/templates/package.md +28 -94
  64. package/data/harnesses/etna/skills/documentation/templates/root-readme.md +103 -65
  65. package/data/harnesses/etna/skills/documentation/templates/setup.md +138 -0
  66. package/data/harnesses/etna/skills/documentation/templates/system.md +25 -109
  67. package/lib/install/materialize.mjs +4 -12
  68. package/lib/install/plan.mjs +4 -11
  69. package/package.json +3 -2
  70. package/data/harnesses/code/skills/documentation/templates/structure.md +0 -71
  71. package/data/harnesses/delivery/skills/documentation/templates/structure.md +0 -71
  72. package/data/harnesses/etna/skills/documentation/templates/structure.md +0 -71
@@ -1,5 +1,5 @@
1
1
  {
2
- "fingerprint": "c24bc6f1af10",
2
+ "fingerprint": "9db89d92a35b",
3
3
  "harnesses": {
4
4
  "code": {
5
5
  "plugin": "code",
@@ -67,11 +67,11 @@ These four mechanisms work in tandem to keep the repo self-updating and to preve
67
67
 
68
68
  ### Ownership — route before editing
69
69
 
70
- Which doc is canonical for which code paths is the **feature doc's own frontmatter**. A feature doc (in `docs/features/`) carries `owns:` (code-path globs — the only ownership key), `module:` (a bounded-context label, omitted when cross-cutting), `keywords:` (discovery), and `status:`. Code → doc ownership is the union of every feature doc's `owns:` globs, surfaced as the generated ownership index at session start. A module is tied to code by the `owns:` globs of the docs carrying its `module:` label — not a folder, not a separate map. Architecture docs describe cross-cutting patterns and own no files; operations docs describe procedures. Every doc carries `type:` — its genre, stamped by document generators or at authoring, read by tooling (UI grouping, protected-file mapping); the `maintenance` agent stamps it where missing. Like `last-reviewed:`, `rev:`, and `slug:`, it is tooling metadata: preserve it on edits, never inject or narrate it.
70
+ Which doc is canonical for which code paths is the **feature doc's own frontmatter**. A feature doc (in `docs/features/`) carries `objects:` (the product objects it designs — its discovery terms and its edge into the knowledge graph), `owns:` (code-path globs — the only ownership key, kept until the graph computes ownership), `module:` (a bounded-context label, omitted when cross-cutting), and `status:`. Code → doc ownership is the union of every feature doc's `owns:` globs, surfaced as the generated ownership index at session start. A module is tied to code by the `owns:` globs of the docs carrying its `module:` label — not a folder, not a separate map. Architecture docs describe cross-cutting patterns and own no files; operations docs describe procedures. Every doc carries `type:` — its genre, stamped by document generators or at authoring, read by tooling (UI grouping, protected-file mapping); the `maintenance` agent stamps it where missing. Like `last-reviewed:`, `rev:`, and `slug:`, it is tooling metadata: preserve it on edits, never inject or narrate it.
71
71
 
72
72
  Before modifying code in an unfamiliar area:
73
73
 
74
- 1. Consult the **injected ownership index** (`glob → doc · module · keywords · status`). Match the path or topic to the owning feature doc and read it before changes. (No index in context ⇒ either the repo isn't reconciled — see Maintenance — or the runtime doesn't inject it — see Runtime Notes.)
74
+ 1. Consult the **injected ownership index** (`glob → doc · module · objects · status`). Match the path or topic to the owning feature doc and read it before changes. (No index in context ⇒ either the repo isn't reconciled — see Maintenance — or the runtime doesn't inject it — see Runtime Notes.)
75
75
  2. If a `docs/memory/` file exists for the domain, read it for domain knowledge and failure modes.
76
76
 
77
77
  The `lld-mode` agent checks for ownership conflicts during LLD research — feature docs whose `owns:` globs overlap at equal specificity. Resolve them in the LLD before proceeding.
@@ -97,7 +97,7 @@ Boundaries are **diagnosed, not documented** — the `boundary` skill derives th
97
97
  - **[override]** Keep `docs/` updated when code changes affect documented behavior. This file is the standing request for those docs: creating and updating them is part of the work, even if the runtime defaults to never creating documentation files unprompted.
98
98
  - After plan completion **[override]**: write the `docs/history/changelog/` entry as a **draft** immediately, while the context is fresh — no confirmation needed — and append its `docs/history/CHANGELOG.md` row; the commit fills what the draft left open and freezes it. Non-plan work needs no separate prompt: every non-exempt commit carries its own entry (the `changelog` rule).
99
99
  - When moving or renaming source files: update the `owns:` globs of the feature doc that owns them so the generated ownership index stays accurate. A new doc that owns code declares its paths in its own `owns:` frontmatter — there is no separate map to update.
100
- - `docs/structure.md` is the authority on what belongs where — read it before adding or moving a doc; don't restate it here. One canonical source per topic — link, don't copy. Only `CLAUDE.md`, `AGENTS.md`, and `README.md` live at the repo root.
100
+ - `docs/structure.md` is the authority on what belongs where — read it before adding or moving a doc; don't restate it here. One canonical source per topic — link, don't copy. Only `CLAUDE.md`, `AGENTS.md`, and `README.md` live at the repo root — and the root `README.md` orients and routes (identity, how it works, a Map of units, rules that bite, where to go); install, stack and first run are `docs/operations/setup.md`, the tree is `docs/structure.md`'s.
101
101
 
102
102
  > Agents and skills live under `.claude/agents/` and `.claude/skills/`. Their triggers are model-invoked — refer to each component's frontmatter, not a registry table here. Runtimes that can't invoke them natively: see Runtime Notes.
103
103
 
@@ -158,7 +158,7 @@ Defaults — ❌ prohibitions hold unless the user explicitly asks otherwise;
158
158
  - ❌ **Dependencies** – Never upgrade pinned packages without asking; security patches and test-tooling installs at `latest` (`testing.md`) are exempt.
159
159
  - ❌ **Compatibility** – Never maintain backward compatibility unless specified.
160
160
  - ❌ **Branches & Worktrees [override]** – `dev` and `production` are merge-only. Work on a short-lived branch cut from `dev` (`feat/<slug>`, `fix/<slug>`, `docs/<slug>`; `hotfix/<slug>` off `production`), commit there, and open a pull request into `dev` (or `production` for a hotfix) — never commit to either long-lived branch, and never create a worktree. The branch is created when the first commit is due, not at session start. This replaces any built-in "branch first on the default branch" default: the branch is required, and it is never `main`.
161
- - ❌ **Protected Files** – Once per session, if `docs/operations/protected-files.md` exists, read it and never modify any path it lists; never modify `AGENTS.md` (harness-regenerated) or `protected-files.md` itself.
161
+ - ❌ **Protected Files** – Once per session, if `docs/operations/protected-files.md` exists, read it and never modify any path it lists; never modify `AGENTS.md` or `docs/structure.md` (both harness-regenerated — the installer rewrites them on every refresh; the `maintenance` agent's `harness-version` stamp is the one write `structure.md` takes) or `protected-files.md` itself.
162
162
  - ✅ **Browser Automation** – If the runtime provides browser automation, use it freely; no need to ask first. If it doesn't — or the executing agent can't hold the browser connection (see Runtime Notes) — return a browser-verification checklist (URLs, actions, expected outcomes) for the orchestrating session or the user to run.
163
163
  - ✅ **Bookkeeping [override]** — dispatching outranks a runtime default that reserves sub-agents for explicit requests (§ Delegation), and `hooks/compliance.mjs` enforces it: Stop is blocked on unresolved rows unless the transcript carries a real `subagent_type: bookkeeper` record. Hooks append doc-debt rows to `docs/operations/bookkeeping.md`; three walls read it at three widths (Stop = your session's rows · commit = rows implicating staged files · CI = all), each re-verifying conditions at gate time. Dispatch the `bookkeeper` for your rows — **never drain `auto:`/`note:` rows in your own loop**, whichever agent you are: the drain is dispatched work at every nesting level (a sub-agent dispatches its own `bookkeeper` — § Delegation), and only `needs-session:` rows are yours to resolve directly. A drained row is **deleted**. The full grammar arrives in the deny message when a wall fires.
164
164
  - ✅ **Session gate log** — a denial with no `resolved` line blocks Stop; resolution mechanics arrive in the block message. Never delete log lines.
@@ -21,7 +21,7 @@ Ground every edit in this ladder, in order. Never invent content; a fact you can
21
21
  | `header-missing` | add the file-path header comment in the file's native comment syntax |
22
22
  | `source-lint` | run `.claude/skills/documentation/scripts/source-lint.mjs <file>` and clear its BLOCK findings: a stale or absent header path is rewritten to the file's own repo-relative path, and `comment-ratio-added` — over a quarter of the lines the change added are comments — is cleared by moving the rationale into the owning doc and leaving one sentence per symbol. Never clear either with a `source-lint-disable`: the one comment that earns its length is a booby trap, and that one takes the disable with its reason beside it. The file-level `comment-ratio` warning is **not** yours — it grades density somebody else wrote, and rewriting an inherited file is a unit of work with an owner, not a queue drain |
23
23
  | `doc-lint` | fix the finding, or add `<!-- doc-lint-disable: id -->` with a reason beside it when the flagged text is deliberate |
24
- | `index-row-missing` | add the doc's row to `docs/README.md` |
24
+ | `index-row-missing` | a retired kind — delete the row. An index names folders, never files; a doc is found by `ls` and by the ownership index, not by a README row |
25
25
  | `doc-implicated` | read the diff of the named source file (`git diff` / `git log -p`), and update the owning doc **only where the diff contradicts documented behavior**; if nothing documented changed, the row's resolution is deleting it |
26
26
  | `package-rejected` | re-check the named manifest: the package no longer declared → delete the row; still declared → `needs-session:` — changing a package decision is the user's call, never yours |
27
27
  | `frozen-record-edited` | re-check `git diff HEAD -- {path}`: clean again → delete the row; still modified → `needs-session:` — never revert another session's work |
@@ -33,7 +33,7 @@ Parse these from the user's prompt; use the default when unstated.
33
33
 
34
34
  1. If `./docs/memory/change-review.md` exists, read it for historical velocity snapshots, prior risk-zone flags, known concentration risks, and the project's **Module Taxonomy** / **Feature Taxonomy**.
35
35
  2. If a CSV from a prior run already exists at the project root (`change-review-YYYY-MM-DD.csv`), prefer it as input and **skip Phase 1** — re-classify only when the requested window changed.
36
- 3. Build the ownership map from feature `owns:` frontmatter — consult the injected ownership index (`glob → doc · module · keywords · status`), or glob `docs/features/**/*.md` and read each doc's `owns:` globs — to map churn to owning feature docs and their `module:` labels.
36
+ 3. Build the ownership map from feature `owns:` frontmatter — consult the injected ownership index (`glob → doc · module · objects · status`), or glob `docs/features/**/*.md` and read each doc's `owns:` globs — to map churn to owning feature docs and their `module:` labels.
37
37
 
38
38
  ---
39
39
 
@@ -21,7 +21,7 @@ Map the documentation landscape — what exists, what is adjacent, how detailed
21
21
  2. Locate the repo's feature-doc layer from `structure.md` — the standard shape is `./docs/features/`, but a repo may document components under their own subject folders. Read that layer's index if it has one; otherwise glob for docs carrying `owns:` frontmatter
22
22
  3. If `./docs/memory/lld-mode.md` exists (or the legacy `./docs/memory/spec-mode.md`), read it for feature doc inventory, ownership conflict zones, and lessons from previous research
23
23
  4. Read 1-2 existing feature LLDs from that layer to calibrate format and depth
24
- 5. Consult the **injected ownership index** (the generated `glob → doc · module · keywords · status` map — the union of every feature doc's `owns:` frontmatter) to build the ownership map. It is the source of truth for what code paths are already owned. If the index isn't present in context, glob the docs tree (excluding `docs/history/`) and read the `owns:` frontmatter of every doc that declares it.
24
+ 5. Consult the **injected ownership index** (the generated `glob → doc · module · objects · status` map — the union of every feature doc's `owns:` frontmatter) to build the ownership map. It is the source of truth for what code paths are already owned. If the index isn't present in context, glob the docs tree (excluding `docs/history/`) and read the `owns:` frontmatter of every doc that declares it.
25
25
 
26
26
  ## What You Research
27
27
 
@@ -95,8 +95,6 @@ Run `git log --since="2 weeks ago" --name-only --pretty=format:"%h %s"` to find
95
95
 
96
96
  **Unowned paths.** Compare the repo's actual top-level source directories (derive them — the top-level dirs that contain code, or the roots named across the `owns:` globs; do not assume `src/`) against the `owns:` map. Report directories no `owns:` glob covers.
97
97
 
98
- **Stale greenfield self-label.** If `structure.md` asserts the repo is greenfield — _"No source code or feature docs exist yet"_ or similar — **but a real source tree exists** (the derived source roots above are non-empty, e.g. a populated `packages/` of real workspaces), the self-label has gone stale. Raise it as a question (e.g. `structure.md says "No source code exists yet" but packages/ holds 5 workspaces — confirm the greenfield label should be retired`).
99
-
100
98
  **Architecture drift.** Grep `docs/architecture/` for file-path references. Verify referenced paths still exist. Remove or update stale references.
101
99
 
102
100
  **Backlog health.** Read `docs/history/backlog.md`. Report items older than 30 days. Count pending by priority.
@@ -117,7 +115,7 @@ For an unowned code **region**, append: `- **[P2]** No feature doc owns \`{dir}/
117
115
 
118
116
  ### Step 6: Report & update tracking
119
117
 
120
- 1. Update `docs/structure.md` Health Log with today's date and summary — **append to the end**, never date-sorted into the middle. Rows are positional: one may say "the row above is…", and an inserted row silently breaks that reference. A Health Log entry is a **generated row, not a narrative essay**: one line — date · counts (stale docs fixed, dead globs, unowned paths, backlog items created) · links to anything that needs a human.
118
+ 1. Append today's row to `docs/history/health-log.md` — **append to the end**, never date-sorted into the middle. Rows are positional: one may say "the row above is…", and an inserted row silently breaks that reference. A Health Log entry is a **generated row, not a narrative essay**: one line — date · counts (stale docs fixed, dead globs, unowned paths, backlog items created) · links to anything that needs a human.
121
119
  2. Update `docs/memory/maintenance.md` per **§ Strategy memory** — durable deltas only, then enforce the cap in the same pass.
122
120
  3. Report findings: stale docs, broken ownership, unowned code, architecture drift, backlog health.
123
121
 
@@ -132,7 +130,7 @@ Baseline mode converges the repo's `docs/` to the **installed** harness shape, t
132
130
  ```
133
131
  docs/
134
132
  ├── README.md ✱ # Documentation root — quick links, section index
135
- ├── structure.md ✱ # Authority map + frontmatter `harness-version` (you own this field)
133
+ ├── structure.md # Harness-owned authority map — the installer writes it on every refresh; you stamp only `harness-version`
136
134
  ├── architecture/ # Cross-module design + steering layer
137
135
  │ │ # domain-model, glossary, non-goals, references, open-questions
138
136
  │ └── decisions/ # Architecture Decisions (ADs — one per subject, updated in place; journey in each AD's Decision Changelog)
@@ -156,7 +154,7 @@ docs/
156
154
  └── tests/ # Behavioral test checklists ({feature}.md, step → **Assert**), derived at plan Completion via the `documentation` skill; author-maintained
157
155
  ```
158
156
 
159
- **✱ marks the five scaffolded files — the only paths a baseline creates, and the only shape signals.** Every **folder** in this tree is created on first use and is simply absent until it holds a file; git cannot track an empty directory, so a missing folder is never evidence of drift and is never scaffolded to satisfy the shape. Record its role in `docs/structure.md` instead.
157
+ **✱ marks the scaffolded files — the only paths a baseline creates, and the only shape signals.** `docs/structure.md` is not one of them: the installer owns it and rewrites it on every install or refresh, so a missing or hand-edited `structure.md` means the harness needs refreshing (`npx @nurix/etna`), never a scaffold from a template — and its body is never converged, only its `harness-version` field stamped. Every **folder** in this tree is created on first use and is simply absent until it holds a file; git cannot track an empty directory, so a missing folder is never evidence of drift and is never scaffolded to satisfy the shape. Its role is already in `docs/structure.md`; a repo's own notes about legacy folders go in `docs/README.md` § Notes for this repository.
160
158
 
161
159
  There is **no `docs/routing.md`**, **no `docs/modules/{m}/`**, **no `docs/pillars/`**, **no `docs/boundaries/`**. Code ownership lives in feature `owns:` frontmatter; a module is a `module:` label, not a folder; boundaries are diagnosed from source; brainstorm records live in `docs/research/` (active) and `docs/history/brainstorms/` (harvested).
162
160
 
@@ -192,7 +190,7 @@ B2 folds artifacts whose **shape dissolved** — a file in the wrong place or th
192
190
 
193
191
  | Nature | Genres | Treatment |
194
192
  | --- | --- | --- |
195
- | **Truth document** | features, ux, architecture, operations, `docs/tests/` checklists, `structure.md`, READMEs | **Converge in place.** These state what is true now, so rewriting them to the current schema is not revision, it is the genre working as designed. Add missing frontmatter keys, add missing required sections, rename keys the template renamed |
193
+ | **Truth document** | features, ux, architecture, operations, `docs/tests/` checklists, READMEs (never `structure.md`, which the installer owns) | **Converge in place.** These state what is true now, so rewriting them to the current schema is not revision, it is the genre working as designed. Add missing frontmatter keys, add missing required sections, rename keys the template renamed |
196
194
  | **Record** | plans, changelog entries, migration runbooks, brainstorm records | **Never rewritten.** A completed plan and a committed entry are frozen — immutability begins at commit, and a record edited to match a newer schema stops being evidence of what happened. Report non-conformance; repair only the **living index** that points at the record (an absent `docs/history/CHANGELOG.md` row is an index defect, not a record defect, and is backfilled with a note saying so) |
197
195
 
198
196
  **Never invent content to satisfy a field.** A frozen changelog entry missing `Skills:` is missing the *judgement* that field carries, and no later session holds it — writing one is fabrication wearing a schema's clothes. Report it, backlog the pattern if it recurs, and leave the entry alone. The same restraint applies to a truth document: a genre's new section that needs knowledge the repo does not contain is raised as a question, not filled with plausible prose.
@@ -203,9 +201,9 @@ B2 folds artifacts whose **shape dissolved** — a file in the wrong place or th
203
201
 
204
202
  Table: `| File | Action | From | To | Reason |` (actions: `Move`, `Merge into {target}`, `Delete`, `Keep`, `Create`, `Fold`). For a fresh baseline this is mostly `Create`; for an upgrade it is mostly `Fold`/`Move`. Ask once: **"Approve this reconcile?"** — you own this interaction (the `documentation` skill is a library and has none).
205
203
 
206
- On approval, execute: create the folder structure; move/fold/merge/delete per the plan; apply B2b's schema convergences to the truth documents (records are reported, never rewritten); add `Status:` to plan files; for each feature doc, derive and write its `owns:` globs (+ `module:` label + `keywords:`) from the source it describes, and each checklist's `verifies:` edge, by calling the `documentation` skill's **frontmatter derivation**; merge scattered backlogs into `docs/history/backlog.md`; fix links broken by moves.
204
+ On approval, execute: create the folder structure; move/fold/merge/delete per the plan; apply B2b's schema convergences to the truth documents (records are reported, never rewritten); add `Status:` to plan files; for each feature doc, derive and write its `owns:` globs (+ `module:` label + `objects:`) from the source it describes, and each checklist's `verifies:` edge, by calling the `documentation` skill's **frontmatter derivation**; merge scattered backlogs into `docs/history/backlog.md`; fix links broken by moves.
207
205
 
208
- Scaffold missing mandated files **by calling the `documentation` skill for each template** — you orchestrate, the skill supplies templates: `docs/structure.md` (with `harness-version`), `docs/history/CHANGELOG.md`, `docs/history/backlog.md`, `docs/memory/main.md`, and the repo-root `README.md` (filled from the real lockfile/scripts/layout — **never overwrite an existing root README**).
206
+ Scaffold missing mandated files **by calling the `documentation` skill for each template** — you orchestrate, the skill supplies templates: `docs/history/CHANGELOG.md`, `docs/history/backlog.md`, `docs/memory/main.md`, `docs/operations/setup.md` (when the repo has a lockfile and a runnable root script; **never a second first-run doc** — propose a rename with a `note:` row if one exists under another name), and the repo-root `README.md` (an outward opening in a user's terms from the charter and vision documents, then orientation and routing filled from the manifests, the ownership index and the root scripts — **never overwrite an existing root README**).
209
207
 
210
208
  ### Step B4 — Stamp the version
211
209
 
@@ -237,7 +235,7 @@ Apply the **§ Strategy memory** retirement procedure to `docs/memory/maintenanc
237
235
  - **Enforce the memory cap on every run** (§ Strategy memory) — you are its only writer, so no one else can do it.
238
236
  - **A clean report is valid** — do not invent issues.
239
237
  - **Declarative, idempotent.** Re-running baseline mode on a current repo reshapes nothing — a second pass is just the audit plus the module proposal. Converge to the current shape; never replay a version ladder; never reconstruct a past shape.
240
- - **Brownfield extraction (operator-ruled 2026-08-19).** When baseline mode meets a repo with a real source tree and few or no feature docs, the module *proposal* is not enough — run the extraction pass: produce feature docs for the recognized modules (docs/features/, full frontmatter: `owns:` · `module:` · `keywords:` · `status:` · `last-reviewed:` · `type: feature` · `derivation: "extracted (baseline YYYY-MM-DD, nustack graph + source read)"`), plus the architecture, tests, and operations layers. Use the `nustack-graph` skill where installed — localize through the index before reading; the docs record intent, the index answers facts. **Every extracted feature doc carries a `## History & Ownership` section** — top contributors with recency, churn posture, and bus-factor notes, dated "as of YYYY-MM-DD" (operator ruling: this section is mandatory in extraction output even though doc-lint flags dated narrative in truth docs; the findings are accepted for now, and a future harness version may retire the section in favor of live index pointers). `status:` is evidence-graded: `deprecated` only when history shows the area dead, never by guess. Scale by fan-out (one extraction lane per module, a completeness critic over the result) rather than one long cold read.
238
+ - **Brownfield extraction (operator-ruled 2026-08-19).** When baseline mode meets a repo with a real source tree and few or no feature docs, the module *proposal* is not enough — run the extraction pass: produce feature docs for the recognized modules (docs/features/, full frontmatter: `objects:` · `owns:` · `module:` · `status:` · `last-reviewed:` · `type: feature` · `derivation: "extracted (baseline YYYY-MM-DD, nustack graph + source read)"`), plus the architecture, tests, and operations layers. Use the `nustack-graph` skill where installed — localize through the index before reading; the docs record intent, the index answers facts. **Every extracted feature doc carries a `## History & Ownership` section** — top contributors with recency, churn posture, and bus-factor notes, dated "as of YYYY-MM-DD" (operator ruling: this section is mandatory in extraction output even though doc-lint flags dated narrative in truth docs; the findings are accepted for now, and a future harness version may retire the section in favor of live index pointers). `status:` is evidence-graded: `deprecated` only when history shows the area dead, never by guess. Scale by fan-out (one extraction lane per module, a completeness critic over the result) rather than one long cold read.
241
239
  - **Diagrams ride the baseline (operator-ruled 2026-08-24).** Whenever baseline mode produces or converges the architecture layer, draw two ASCII diagrams from the real source, each in its own fenced code block: (1) an **architecture diagram** in the system-design/architecture doc — the actual processes, entry points, and wire surfaces as boxes, the calls/queues/files between them as labelled arrows; (2) a **DB ER diagram** wherever the repo declares a relational schema (DDL, migrations, an ORM schema) — one box per table listing its key columns, FK edges drawn to the table they reference, cardinality on the edge; it lands in the domain-model doc, or `docs/architecture/data-model.md` when none exists. Box-drawing characters (`┌─┐│└┘├┤`), width ≤ 100 columns. Derived only from what the code declares — a diagram never invents a component the source does not show, and a repo with no relational schema gets **no** ER diagram rather than an imagined one. Diagrams are truth-document sections: later baselines and audits converge them in place like any other section.
242
240
  - **Tool tiers.** The SessionStart context names each manifest-declared tool with its tier; calibrate the run to it, never stall on it. **Present-fresh** (`Tool: nustack 0.9.0`): use it — localize every question through `nustack graph` before reading source, and never run an index step first: the family re-indexes a stale store before it answers, so the only freshness decision left is the deliberate `--no-refresh`. **Present-stale** (below the catalog minimum): still use it, but note the version gap and the upgrade command in the run report — a stale contract may lack answer shapes the skill assumes. **Absent** (`Tool: nustack MISSING`): fall back to the cold method (Glob/Grep/read), state in the run report that the tool was absent and give the install command — degraded output is acceptable, silent degradation is not.
243
241
  - **One sentinel.** `docs/structure.md` `harness-version` is the only baseline/version marker.
@@ -1,74 +1,136 @@
1
- # Documentation Structure
2
-
3
- > This file is the entry point for understanding the docs folder.
4
- > The `harness-version` frontmatter field is the repo's single baseline/version sentinel — the `maintenance` agent (baseline mode) owns it and stamps the installed harness version (semver) on every reconcile. This seeded copy ships without the field: its absence is what tells the first session the repo has not been baselined yet.
5
-
6
- ## Authority Map
7
-
8
- Each topic has one canonical location. Read from here, not from plans or changelogs.
9
-
10
- | Topic | Authority | Key Files |
11
- | ----- | --------- | --------- |
12
- | Code-path ownership (path → doc + module) | feature `owns:` frontmatter | the generated ownership index |
13
- | System overview | `docs/architecture/` | system-design.md |
14
- | Steering (domain model, glossary, non-goals) | `docs/architecture/` | domain-model.md, glossary.md, non-goals.md |
15
- | Architecture decisions (ADs) | `docs/architecture/decisions/` | AD-NNN-*.md |
16
- | API surface | `docs/architecture/` | api.md |
17
- | Security | `docs/architecture/` | security.md |
18
- | Feature behavior | `docs/features/` | one `kebab-case.md` doc per feature |
19
- | UX behavior — one surface | `docs/features/` | `{surface}-ux.md`, `type: ux` |
20
- | UX behavior — cross-cutting (routing, information architecture, stream presentation) | `docs/architecture/` | `type: ux`, owns no code |
21
- | Product specification (PRD, personas, journeys, information architecture) | `docs/architecture/` | prd.md, personas.md, journeys.md, information-architecture.md |
22
- | Acceptance criteria | `docs/acceptance/` | one `kebab-case.md` doc per capability, `AC-n` keyed assert lines |
23
- | Setup & development | `docs/operations/` | setup.md |
24
- | Environment / config surface | `docs/operations/` | environment.md |
25
- | Testing strategy | `docs/tests/` | strategy.md |
26
- | Historical plans | `docs/history/plans/` | YYYY-MM-DD-name.md |
27
- | Change records | `docs/history/changelog/` | `YYYY-MM-DD-{three-words}.md` — one per unit of work, written at commit time |
28
- | Migration runbooks | `docs/history/migrations/` | YYYY-MM-DD-name.md |
29
- | Deep-research artifacts | `docs/history/research/{topic}/` | README.md + findings.md + sources.md |
30
- | Brainstorm design records | `docs/research/{topic}-brainstorm/` (active; legacy `-brainstorming/`) → `docs/history/brainstorms/{topic}/` (harvested; user deletes or commits) | thesis.md + forks.md + ledger.md + state.md |
31
- | Backlog | `docs/history/` | backlog.md |
32
-
33
- ## The Two Natures
34
-
35
- Every doc is a **truth document** (states current absolutes, topic-named, updated in place) or a **record** (dated account of activity, frozen or append-only). `architecture/`, `features/`, `operations/`, `tests/` hold truth; `history/`, `research/`, `memory/` hold records.
36
-
37
- - Truth documents are rewritten in place when reality changes — the change-story goes to a changelog entry, never into the truth doc's body.
38
- - Records freeze: plans at `Complete`/`Abandoned`, changelog entries and migration runbooks once written/executed. A scope change is a new dated record that links back.
39
- - Feature docs are the living reference for implemented features; an AD is the living truth for one decision subject, with its dated journey confined to its Decision Changelog tail.
40
-
41
- ## Folder Rules
42
-
43
- - `docs/features/`: Living reference for implemented features. Each feature doc **carries** the `owns:` / `module:` / `keywords:` / `status:` frontmatter — `owns:` declares the code-path globs it owns (the only ownership key), `module:` is an optional bounded-context label, `keywords:` are discovery terms, `status:` is `active`/`draft`/`deprecated`. The SessionStart hook unions every feature's `owns:` globs into the injected ownership index.
44
- - `docs/architecture/`: The truth layer for system-wide shape: overview, domain model, glossary, non-goals, API surface, security, and `decisions/` (ADs — one per subject, updated in place, journey in each AD's Decision Changelog). Update when cross-cutting reality changes.
45
- - `docs/operations/`: How-to procedures for setup, development, and deployment, plus the environment registry. Update when workflows change. One-shot migrations do NOT live here — they are records (`docs/history/migrations/`).
46
- - `docs/acceptance/`: Acceptance-criteria documents — one per capability, stating the promises the
47
- built product must keep as `AC-n` keyed assert lines that verification surfaces parse as claims.
48
- Written at specification time, before implementation; carries frontmatter (`type:`, `status:`)
49
- like every generated doc. Keys are stable once published — a criterion is retired by marking it,
50
- never by renumbering. Distinct from `docs/tests/`: acceptance criteria state what the product
51
- promises up front; the checklists in `docs/tests/` are the verification gate's own driving
52
- scripts, authored and maintained at the gate.
53
- - **UX behavior** (`type: ux`) is placed by **scope, never by medium** — there is no `docs/ui/`.
54
- One surface's observable behavior is a feature concern and lives beside its LLD as
55
- `docs/features/{surface}-ux.md`; routing, information architecture, and the presentation
56
- contracts every surface obeys are whole-product concerns the interface merely renders, so they
57
- live in `docs/architecture/` and own no code. The genre exists because an LLD states what a
58
- feature *is* — which stays plausibly true through a rewrite of the surface — while nothing else
59
- states what a person *observes*, so a wire change lands, the interface absorbs it, and the
60
- absorption reads as maintenance. This document is what such a change contradicts. It **decides**
61
- behavior and is written before the code; the `docs/tests/` checklist only verifies it afterwards.
62
- - `docs/tests/`: Behavioral checklists — the verification gate's driving scripts, one per feature (`docs/tests/{feature}.md`). **Each carries `type: checklist` and `verifies:`** — the feature or UX doc whose promises it proves. That edge is what makes a checklist reachable: a same-named file is a coincidence a resolver cannot trust, so without `verifies:` nothing implicates the checklist when its subject changes and it rots undetected. The inverse — which checklists cover a feature — is generated and injected, never listed in the feature doc.
63
- - `docs/history/plans/`: Records. Must have `Status:` field. Never modify after completion.
64
- - `docs/history/changelog/`: Records. One entry per unit of work (`YYYY-MM-DD-{three-words}.md`), written by whoever does the work and frozen inside the commit it describes. Entries carry the refinement context a diff cannot show — the ask in the user's words, iterations and rejections, skill survived/overridden verdicts, discoveries, pins. Format is the `documentation` skill's `templates/changelog-entry.md`; trigger and lifecycle are the `changelog` rule; distillation is the `retro` agent. Immutability begins at commit — a draft in the working tree is mutable until then, never after. Every entry appends a row to `docs/history/CHANGELOG.md`.
65
- - `docs/history/migrations/`: Records. One-shot migration/upgrade runbooks — authored before execution, outcome-stamped and frozen after.
66
- - `docs/history/research/{topic}/`: Deep-research artifacts — the dumped output of a research pass, one folder per topic (conventionally `README.md` synthesis + `findings.md` verified claims & citations + `sources.md`). A point-in-time, cited record — **not** a living authority doc: it owns no code (no `owns:` frontmatter) and is never edited to "stay current." A spec/plan links to it for grounding; a new question gets a new topic folder.
67
- - `docs/research/{topic}-brainstorm/` → `docs/history/brainstorms/{topic}/`: Brainstorm design records — the Brainstorming-Mode session for a topic (working surface `thesis.md` + `forks.md` + `ledger.md` + `state.md` + `basis/` + `fragments/`, plus an untracked `ops/` capture layer deleted at stop), written by the `brainstorm` skill and its twin agent. An active session lives under `docs/research/` (legacy folders carry the older `-brainstorming/` suffix); on a **passed harvest** it **moves** to `docs/history/brainstorms/` — the completion marker — and the **user decides whether the moved folder is deleted or committed** as provenance. Each of the two folders carries a `Readme.md` index (the skill reads it at start instead of scanning). Author-created (never scaffolded empty), one folder per design conversation. Owns no code (no `owns:` frontmatter); the harvest routes its conclusions into `architecture/`/`features/`/`history/`. (Distinct from `docs/history/research/{topic}/` above — that is a frozen deep-research record, not a brainstorm session.)
68
- - `docs/history/backlog.md`: Open work items — a drain queue: append on discovery, delete when done (the changelog entry or plan that did the work is the record).
1
+ # Documentation Structure — Authority Map
2
+
3
+ This file is the authority on **what belongs where** in `docs/`: the folder map, naming, lifecycle, the doctrine every genre follows, and the decision table for adding a doc. Read it before adding or moving any documentation. Start reading from [`README.md`](README.md).
4
+
5
+ **This file is the harness's, not the project's.** The installer writes it on every install and refresh, so nothing in it describes one repository: a folder a repo does not use is simply absent on disk, and a repo's own notes — legacy folders kept as provenance, retired genres, local exceptions — live in [`README.md`](README.md) § Notes for this repository, never here. Hand edits are overwritten on the next refresh. The one field written in place is `harness-version` in the frontmatter, stamped by the `maintenance` agent after its baseline reconcile; its absence is what tells a session the repo has not been baselined against the installed harness.
6
+
7
+ One canonical source per topic — link, don't copy. Only `CLAUDE.md`, `AGENTS.md`, and `README.md` live at the repo root.
8
+
9
+ ---
10
+
11
+ ## Folder map
12
+
13
+ ```
14
+ docs/
15
+ ├── README.md # Documentation root — the product in a paragraph, what each folder holds, and the repo's
16
+ │ # own notes. Describes directories, never files or a tree — `ls` is the roster
17
+ ├── structure.md # This file — harness-owned authority map; `harness-version` stamped after baseline
18
+ ├── architecture/ # The design layer, in four folders; Readme.md is its summary and names folders only
19
+ │ ├── packages/ # One `{package}.md` per project package: what it is, how it behaves. Carries
20
+ │ │ # `owns:` over `packages/<pkg>/**` RESIDUALLY — whatever no system or feature doc claims
21
+ │ ├── systems/ # One `{machine}.md` per machine spanning packages. Carries `owns:` over its
22
+ │ │ # subtrees; more specific than a package's glob
23
+ │ ├── common/ # The enterprise plane — one `{concern}.md` per concern the platform handles
24
+ │ │ # the same way everywhere. Owns no code
25
+ │ └── decisions/ # ADs — `AD-NNN-{slug}.md`, one per subject, updated in place; the journey lives in
26
+ │ # each file's Decision Changelog tail. Readme.md is the register: the current
27
+ │ # decision per subject and whether it is built
28
+ ├── features/ # Feature docs — `{feature}.md`, one per thing a person points at (an address, a command
29
+ │ # family, a named control), cut by its objects (flat, no subfolders). One of three owning genres, beside
30
+ │ # `architecture/packages/` and `architecture/systems/`; ownership is `owns:` frontmatter
31
+ ├── acceptance/ # Acceptance criteria — `{capability}.md`, stable `AC-n` assert lines. Owns no code
32
+ ├── operations/ # Procedures — `setup.md` (the one-time first run, incl. the stack), then development, deployment, signing, rotation, diagnostics;
33
+ │ │ # one topic-named `{procedure}.md` each. Also holds bookkeeping.md, the shared
34
+ │ │ # doc-sync work queue (hook-appended, bookkeeper-drained, a drained row deleted)
35
+ │ ├── release-notes/ # One operator-facing note per release (`YYYY-MM-DD-vX.Y.Z.md`); its README.md indexes them
36
+ │ ├── issues/ # Local-tracker issue records (`type: issue`, `YYYY-MM-DD-{slug}.md`) — the
37
+ │ │ # `issue-bridge` skill's local pack; `status:` is the lifecycle
38
+ │ └── triage/ # Triage dossiers (`type: triage`, `YYYY-MM-DD-{slug}.md`) — one per investigated
39
+ │ # issue, written by the `issue-bridge` skill; owns no code, never a feature doc
40
+ ├── tests/ # Behavioral test checklists (truth docs) — `{feature}.md`, step → **Assert**, named for
41
+ │ # the doc whose promises it proves. `ls docs/tests/` is the roster
42
+ ├── research/ # Records — in-progress brainstorm sessions (`{topic}-brainstorm/`), standing-research
43
+ │ # folders (`{topic}/`) and loose standing-research notes (`{topic}.md`). Readme.md is the index
44
+ ├── history/
45
+ │ ├── CHANGELOG.md # Master changelog index
46
+ │ ├── changelog/ # Individual changelog entries, `YYYY-MM-DD-{three-words}.md` (frozen at commit)
47
+ │ ├── plans/ # Dated implementation plans, `YYYY-MM-DD-{slug}.md` (Status: field; Complete/Abandoned = frozen)
48
+ │ ├── migrations/ # One-shot migration runbooks, `YYYY-MM-DD-{slug}.md` — authored ahead, outcome-stamped, frozen
49
+ │ ├── brainstorms/ # Harvested brainstorm sessions (`{topic}/`), kept as provenance; Readme.md is the index
50
+ │ ├── research/ # Deep-research records (`{topic}/` — README.md synthesis + findings.md + sources.md).
51
+ │ │ # Frozen, cited, owns no code. Distinct from research/ at the docs root
52
+ │ ├── health-log.md # The maintenance agent's append-only pass record, one generated row per pass
53
+ │ ├── journal.md # Append-only mid-execution knowledge capture, one line per fact; a line resolves by
54
+ │ │ # landing in its owning doc (delete the row, cite it in the changelog entry)
55
+ │ └── backlog.md # Tracked work items by priority (P0–P3)
56
+ └── memory/ # Project knowledge + per-agent strategy memory
57
+ ├── main.md # Main-agent project memory
58
+ └── {agent}.md # One strategy-memory file per sub-agent that keeps one
59
+ ```
60
+
61
+ ## Doctrine every genre follows
62
+
63
+ - **`docs/architecture/`** is the design layer in four folders: **`packages/`** (one per project package — what it is and how it behaves), **`systems/`** (one per machine spanning packages), **`common/`** (the enterprise plane) and **`decisions/`** (the ADs, one per subject, updated in place, each journey confined to that file's Decision Changelog tail).
64
+ **`common/` and `decisions/` own no code; `packages/` and `systems/` do.** Ownership is a frontmatter fact, not a folder fact: it is the union of every `owns:` glob in `features/`, `architecture/packages/` and `architecture/systems/`, and the more specific glob wins — a feature's beats a system's, a system's beats a package's. **A package document is the residual owner of its tree**, so a package's exhaustive behavior spec is that document, not a feature doc.
65
+ **What earns which genre.** A project package earns a `packages/` document — one, always. A machine whose parts sit in several packages, which a reader asks about as one thing, earns a `systems/` document. A **feature** document exists for something a person points at — an address, a command family, a named control — and is cut by the objects it designs, never by the code's routers, tables, plans or packages; a machine nobody navigates to is a `systems/` document even when it owns tables, and a fragment whose central object is declared in a sibling merges into it. A concern handled the same way everywhere is `common/` and owns nothing — including the governing-decisions register (fixed product decisions `F-###`, baseline defaults `B-###`, external boundaries, out-of-scope), which is authored doctrine the `boundary` skill never persists to.
66
+ - **`history/research/` is not legacy — it is the installed deep-research genre**, one `{topic}/` folder per research pass in the three-file shape. A record is frozen and cited, owns no code, and is never edited to stay current; a new question gets a new topic folder. Entries that predate the three-file convention — a single file or a single-report folder — are kept as authored.
67
+ - **`docs/features/` is flat — every feature authority is a file, and no subfolder exists.** A subject too large for one file is two files, not a folder: the `owns:` frontmatter already states authority, and a nested doc is one the ownership scan and the index rows reach last.
68
+ - **`docs/research/`** holds records, not authorities: its standing-research folders and loose notes ground plans and decisions, and its `Readme.md` lists every folder so the `brainstorm` skill reads it instead of scanning.
69
+ - **`docs/tests/`** holds behavioral test checklists — one `{feature}.md` per surface, written as `- [ ] step` → `- [ ] **Assert**` (how to verify a feature's promised behavior). A checklist is written or updated **at the verification gate, before the driving** — it is the script the real surface is driven against and the menu the pinned suite tests are drawn from, so each behavior section closes with a `> Pinned:` line naming the test that guards it, `driven only` with the reason, or `none yet` with the test it owes. **No section carries a date** — the *event* of driving (its date, environment, evidence, a `FAIL` and the backlog item it raised) belongs to the changelog entry of the unit that drove it. A section a drive cannot reach says `not reachable — {what blocks it}` on its trace line until the blocker is gone. **The gate that drives a checklist maintains it** — retiring dead sections and repairing traces is part of the run, because a checklist owns no code and no ownership glob implicates it. The cross-system testing strategy is doctrine in `architecture/common/`. A checklist carries `type: checklist` plus `verifies:`, the doc(s) whose promises it proves; a target is legitimately a feature, a package or a system document, and several values are correct where one checklist proves promises two docs decide.
70
+ **`verifies:` is the load-bearing key, and the filename convention is not a substitute for it.** A same-named file is a coincidence no resolver can trust — it breaks the moment a checklist spans two docs or a feature is renamed. The inverse — which checklists cover a feature — is **generated, never listed in the feature doc**.
71
+ - **`docs/operations/bookkeeping.md`** is the shared doc-sync work queue — hooks append rows, the `bookkeeper` agent drains them, and the commit wall blocks while rows remain. It is **author-created, never scaffolded**, and its rows are **live work, never drift**: a drained row is deleted, so a fully drained file holds no rows at all. Read a waiver's referent before deleting it; deleting the record while the condition survives re-appends the finding as an `auto:` row that fails the wall the waiver passed.
72
+ - **`type:` is a required frontmatter key** on every doc that carries frontmatter — the genre stamp, its enum being the `documentation` skill's template names (`feature`, `architecture-decision`, `project-memory`, `ux`, `acceptance-criteria`, …). It is tooling metadata like `last-reviewed:` and `status:`: external tooling reads it, sessions **preserve it on edits** and never narrate it in the body. The `maintenance` agent stamps it on docs that lack it.
73
+ **No genre is frontmatter-less by policy; the gaps are the templates.** `architecture/common/**` carries `type: doctrine` with `status:` and `objects:` and no `owns:`, from the documentation skill's doctrine template. `architecture/Readme.md` carries no block, because its template ships none and a block is never manufactured on a doc whose template has none. `architecture/packages/**` and `architecture/systems/**` carry `type: package` / `type: system` with `objects:`, `owns:`, `status:` and optional `applies:`, because those genres own code and the ownership scan reads frontmatter. The `operations/` procedures carry a hand-authored `type: operations` block; the bookkeeping queue carries none. Docs written by a skill that ships a block (`issue-bridge`'s `type: issue` / `type: triage`) carry it.
74
+ - **The docs tree is a graph, and every edge is declared at the consuming end.** Three frontmatter keys carry it: `owns:` (doc → code), **`verifies:`** (checklist → the doc whose promises it proves), and **`applies:`** (a feature, package or system doc → the doctrine it is *bound by* — an obligation, deliberately not a bibliography, so a key that collected everything consulted would stop meaning anything). Every inverse is **generated** — `buildEdgeIndex()` in `.claude/hooks/lib/ownership.mjs`, injected at SessionStart beside the ownership index — and authoring one by hand is a defect: a parent that hand-lists its children doubles the staleness surface instead of halving it. `check-ownership` fails on an edge naming a doc that does not exist, waivable as `dangling-edge`. **`applies:` is reported, never inferred** — an obligation is an assertion only the consuming doc's author can make.
75
+ - **`docs/acceptance/` holds the acceptance-criteria genre** — one `kebab-case.md` per capability, written at specification time, before implementation, holding stable `AC-n` assert lines that verification surfaces parse as claims to grade the built product against; each file is keyed to the checklist sections that grade it. The folder is created on first use and never scaffolded. The `AC-n:` line grammar is load-bearing: the key sits at line start, exactly `AC-<number>:`, followed by the assert sentence — tables, emphasis-wrapped keys, and nested bullets break the parse.
76
+ - **The `ux` genre decides observable behavior; `docs/tests/` only verifies it.** A feature doc states what a feature is and which contracts it honours — all of which stay plausibly true through a rewrite of the surface — so a UX-behavior doc states what a person *observes*, and is written **before** the code. This repo holds no standalone `ux` document: what a person observes on a surface is a section of the feature doc that owns that surface's components and wire. A surface needing the genre gets `features/{surface}-ux.md` with real `owns:` over its unclaimed component globs — an `owns: []` doc nothing implicates is one no change reaches.
77
+ - **`docs/history/journal.md` is the temporary lane, and `docs/memory/` is not.** The journal holds mid-execution facts one line each, each resolved by landing in its owning doc; memory holds only per-agent strategy and project knowledge no single doc owns. A fact an owning doc will eventually carry goes to the journal, never to memory — memory has no drain, so what lands there stays until somebody distils it.
78
+ - **There is no `docs/history/sessions/`.** Per-session gate logs are machine-local, written by `.claude/hooks/lib/session-log.mjs` into `.claude/state/sessions/` (self-ignored), so they never enter `docs/` or git. A `docs/history/sessions/` folder is residue, not shape.
79
+ - **The repo-root `README.md` opens outward and turns inward.** What the product does, for whom and where it runs, in a user's terms; then, for the team and agents, how it works, a Map of top-level units with their owning doc, the rules that bite, where to go by intent, and at most four everyday commands. It carries no install, stack or tree — install and stack are `operations/setup.md`, the tree is this file's. Template: the `documentation` skill's `templates/root-readme.md`.
80
+ - **`docs/README.md` describes directories, never files.** One entry per folder: what it holds, who reads it, how its files are named — no per-file rows, no tree. It closes with the repository's own notes, the one place project-specific placement facts live.
81
+ - **`operations/setup.md` is the one first-run document**, fixed name, one per repo: stack by layer naming the pinning file, prerequisites, install, env files, first run, verification, failures by exact error text. Every other procedure is topic-named and recurring.
82
+
83
+ ---
84
+
85
+ ## Lifecycle
86
+
87
+ - **Plans** (`history/plans/YYYY-MM-DD-{slug}.md`) carry a `Status:` field (`Draft` / `Ready` / `Active` / `Executed` / `Complete` / `Abandoned`). Once `Complete`/`Abandoned`, a plan is frozen — never edited; scope changes get a new dated plan that links back.
88
+ - **Migration runbooks** (`history/migrations/YYYY-MM-DD-{slug}.md`) are authored ahead of execution and record a one-shot infra/cutover procedure; once executed, the outcome is stamped into the file and it is frozen — a re-run gets a new dated runbook.
89
+ - **Changelog** entries land in `history/changelog/` and are indexed in `history/CHANGELOG.md`.
90
+ - **Backlog** items live in `history/backlog.md` under P0–P3 priorities (living, append-only).
91
+ - **Brainstorm sessions** are author-created by the `brainstorm` skill: an active session at `docs/research/{topic}-brainstorm/` (older folders carry the legacy `-brainstorming/` suffix; both are canonical), moved to `docs/history/brainstorms/{topic}/` on a passed harvest — the move is the completion marker, and the moved folder's fate (delete or commit) is the author's call. Never scaffolded empty; each folder carries a `Readme.md` index.
92
+ - **Source-of-truth audits** write nothing to `docs/`. The `polygraph` skill runs in two modes — **audit** on a named target (a doc, a feature, a folder, a code path) and **gate** at plan completion — and both keep their rows under `.claude/state/polygraph/{run}/`, machine-local, never tracked, deleted in the same turn as the report. What survives a run is the corrected document itself, the backlog rows it registered, and the plan's `Polygraph:` segment. Folders an earlier audit mode left behind are provenance a repo lists in its `README.md` notes, never a place anything writes.
93
+ - **Boundaries** are a plan-time diagnostic — the `boundary` skill reads contracts fresh from source; there is no persisted `boundaries/` tree.
94
+ - **Modules** are _declared labels_ (a `module:` key on a feature doc), never inferred from physical layout and never a folder. A feature always lives flat in `features/`.
95
+
96
+ ---
97
+
98
+ ## Add-a-doc decision table
99
+
100
+ | You are adding… | It goes in… | Needs frontmatter? |
101
+ | --- | --- | --- |
102
+ | A feature document — something a person points at (an address, a command family, a named control), cut by the objects it designs | `features/` (flat) | Yes — `objects:`, `owns:`, `status:`, `type: feature` (+ optional `module:`, `applies:`, `last-reviewed:`) |
103
+ | A package's behavior document | `architecture/packages/<package>.md`, one per package | Yes — `type: package`, `objects:`, `owns:` (its tree, residually), `status:`, optional `applies:` |
104
+ | A system's behavior document | `architecture/systems/{system}.md`, one per machine | Yes — `type: system`, `objects:`, `owns:` (the machine's subtrees), `status:`, optional `applies:` |
105
+ | Cross-cutting design / steering | `architecture/common/` | No |
106
+ | An Architecture Decision (AD) | `architecture/decisions/` — one file per subject, updated in place; the journey lives in that file's Decision Changelog | Yes — `type: architecture-decision` (+ `title:`, `status:`, `created:`, `last-updated:`, `decision-owner:`, `tags:`) |
107
+ | One-time machine setup, first run, stack, prerequisites, env files | `operations/setup.md` — fixed name, one per repo, linked from the root README; a diverging package gets a `### {unit}` subsection, never a second first-run doc | Yes — `type: operations` |
108
+ | A recurring procedure (develop, deploy, rotate, diagnose, CI) | `operations/{procedure}.md` | Yes — `type: operations` |
109
+ | A tracker issue held in the repo | `operations/issues/YYYY-MM-DD-{slug}.md` (via the `issue-bridge` skill's local pack) | Yes — `type: issue`, `id:`, `status:`, `labels:`, `author:`, `created:`, `github:` |
110
+ | A triage dossier for an investigated issue | `operations/triage/YYYY-MM-DD-{slug}.md` (via the `issue-bridge` skill) | Yes — `type: triage`, `tracker:`, `issue:`, `date:`, `confidence:`. A dated working artifact: it never claims `owns:` and never masquerades as a feature doc |
111
+ | A behavioral test checklist | `tests/{feature}.md` | Yes — `type: checklist`, `verifies:` (the doc(s) whose promises it proves; several values are legitimate). No `owns:` — it owns no code. Truth doc, present-tense; written at the verification gate before the driving, each section carrying a `Pinned:` trace |
112
+ | What a person sees and can do on a surface (UX behavior) | `features/{surface}-ux.md` with `owns:` over that surface's unclaimed component globs; a section of the owning feature doc where the surface has one owner; `architecture/common/` when it is cross-cutting | Yes — `type: ux` (+ the feature-doc keys when it lives in `features/`) |
113
+ | Acceptance criteria for one capability | `acceptance/{capability}.md` — stable `AC-n` assert lines verification surfaces parse as claims; keys are never renumbered or reused, a retired criterion is marked retired in place | Yes — `type: acceptance-criteria`, `status:`; no `owns:` (owns no code) |
114
+ | An in-progress brainstorm session | `research/{topic}-brainstorm/` (via the `brainstorm` skill) | No |
115
+ | A source-of-truth audit | Nowhere in `docs/` — the `polygraph` skill (audit mode) corrects the target doc in place and keeps its rows under `.claude/state/polygraph/{run}/`, deleted with the report | No |
116
+ | An implementation plan | `history/plans/YYYY-MM-DD-{slug}.md` | No (but `Status:` required) |
117
+ | A one-shot migration runbook | `history/migrations/YYYY-MM-DD-{slug}.md` | No (authored ahead; outcome-stamped and frozen once executed) |
118
+ | A deep-research record | `history/research/{topic}/` — `README.md` synthesis + `findings.md` + `sources.md`; frozen and cited, owns no code, never edited to stay current (a new question gets a new topic folder) | No |
119
+ | A harvested brainstorm session | `history/brainstorms/{topic}/` (via the `brainstorm` skill's harvest) | No |
120
+ | A changelog entry | `history/changelog/` + index in `CHANGELOG.md` | No |
121
+ | A tracked work item | `history/backlog.md` | No |
122
+ | A doc-sync debt row | `operations/bookkeeping.md` (hook-appended; drained by the `bookkeeper` agent, deleted on drain) | No |
123
+ | A mid-execution fact worth keeping | `history/journal.md` (append-only; resolves by landing in its owning doc) | No |
124
+ | Agent strategy / project memory | `memory/` | Yes — `type: project-memory` on `main.md` |
125
+
126
+ ---
127
+
128
+ ## Harness version
129
+
130
+ `harness-version` in this file's frontmatter is the **single** baseline/version sentinel for a repo — the semver of the installed harness (`.claude/harness.json`) the `docs/` tree was last reconciled to. The installer ships this file without the field; the `maintenance` agent (baseline mode) stamps it after reconciling the tree, and a session whose installed version is ahead of the stamp — or that finds no stamp — dispatches that agent before anything else. There is no second marker.
131
+
132
+ ---
69
133
 
70
134
  ## Health Log
71
135
 
72
- <!-- Updated by maintenance agent — the sanctioned dated tail in this truth doc (SKILL.md § The Two Natures names the two bridges) -->
73
- | Date | Review Summary |
74
- | ---- | -------------- |
136
+ The `maintenance` agent appends its pass record to [`history/health-log.md`](history/health-log.md) — an append-only record, kept out of this file, which it never otherwise edits.
@@ -1,15 +1,15 @@
1
1
  {
2
2
  "harness": "code",
3
3
  "name": "code",
4
- "version": "3.19.3",
4
+ "version": "3.19.4",
5
5
  "files": [
6
6
  ".prettierignore",
7
7
  ".prettierrc.json",
8
- ".vscode/settings.json"
8
+ ".vscode/settings.json",
9
+ "docs/structure.md"
9
10
  ],
10
11
  "seeds": [
11
12
  "docs/README.md",
12
- "docs/structure.md",
13
13
  "docs/history/CHANGELOG.md",
14
14
  "docs/history/backlog.md",
15
15
  "docs/memory/main.md",
@@ -25,5 +25,5 @@
25
25
  }
26
26
  ],
27
27
  "docsRoot": "docs",
28
- "digest": "5181bf532ddd"
28
+ "digest": "f3f36722fca1"
29
29
  }
@@ -360,16 +360,6 @@ function detectorForFile(projectDir, rel, meta, rows) {
360
360
  );
361
361
  }
362
362
  }
363
- if (rel.startsWith(`${root}/features/`) && !readSafe(path.join(projectDir, root, "README.md")).includes(path.basename(rel))) {
364
- rows.push(
365
- formatAutoRow({
366
- ...meta,
367
- kind: "index-row-missing",
368
- description: `${rel} is not linked from ${root}/README.md`,
369
- action: "add its row to the Features index",
370
- })
371
- );
372
- }
373
363
  return;
374
364
  }
375
365
 
@@ -130,7 +130,7 @@ export function isOwningDocPath(projectDir, relPath) {
130
130
  }
131
131
 
132
132
  // Scan the docs tree and return one entry per document that declares owns:.
133
- // Shape: { doc (repo-relative, /-separated), owns[], module, keywords[], status }.
133
+ // Shape: { doc (repo-relative, /-separated), owns[], module, objects[], keywords[] (legacy, read only as a fallback), status }.
134
134
  //
135
135
  // OWNERSHIP IS A FRONTMATTER FACT, NOT A FOLDER FACT. This scanned `docs/features/` alone, which
136
136
  // silently un-owned every path claimed by a genre living elsewhere — a `type: package` doc under
@@ -163,6 +163,7 @@ export function scanOwningDocs(projectDir) {
163
163
  owns,
164
164
  module: (field(block, "module") || "—").toString(),
165
165
  keywords: asList(field(block, "keywords")),
166
+ objects: asList(field(block, "objects")),
166
167
  status: (field(block, "status") || "active").toString().toLowerCase(),
167
168
  });
168
169
  }
@@ -194,7 +195,8 @@ export function buildIndex(projectDir) {
194
195
  // of its globs makes the index grow with the dependency graph rather than the doc count: on a
195
196
  // 42-keyword doc owning 15 paths the same 42 facts were repeated 15 times, and keywords
196
197
  // outweighed the glob paths — the only part that routes — by more than four to one.
197
- const kw = entry.keywords.length ? `[${entry.keywords.join(", ")}]` : "[]";
198
+ const terms = entry.objects.length ? entry.objects : entry.keywords;
199
+ const kw = terms.length ? `[${terms.join(", ")}]` : "[]";
198
200
  lines.push(
199
201
  `${entry.doc} · ${entry.module} · ${entry.status}\n ${kw}\n` +
200
202
  entry.owns.map((glob) => ` ${glob}`).join("\n")
@@ -49,7 +49,7 @@ export function sourceLint(projectDir, rel) {
49
49
  }
50
50
 
51
51
  // Verifier keys the detector no longer emits — swept when machine-raised, never taught to authors.
52
- export const RETIRED_KINDS = ["doc-placement", "boundary-scan-suggested"];
52
+ export const RETIRED_KINDS = ["doc-placement", "boundary-scan-suggested", "index-row-missing"];
53
53
 
54
54
  export const ROW_VERIFIERS = {
55
55
  // "<rel> lacks its file-path header comment" — dead once the header is there (or the file is gone).
@@ -140,13 +140,9 @@ export const ROW_VERIFIERS = {
140
140
  return docLint(projectDir, m[1]).length === 0;
141
141
  },
142
142
 
143
- // "<rel> is not linked from docs/README.md" — dead once the index names it (or it is gone).
144
- "index-row-missing": (projectDir, body) => {
145
- const m = /·\s+index-row-missing\s+·\s+(\S+)\s+is not linked/.exec(body);
146
- if (!m) return false;
147
- if (!fs.existsSync(path.join(projectDir, m[1]))) return true;
148
- return readSafe(path.join(projectDir, docsRoot(projectDir), "README.md")).includes(path.basename(m[1]));
149
- },
143
+ // "<rel> is not linked from docs/README.md" — retired: an index names folders, never files
144
+ // (the documentation skill § Indexes name folders, never files), so nothing raises it.
145
+ "index-row-missing": (projectDir, body, ctx, row) => row.kind === "auto",
150
146
 
151
147
  // "<rel> declares `<name>` (package-rejected)" — dead once the manifest drops the package
152
148
  // or the table stops rejecting it.