@nurix/etna 0.18.9 → 0.18.10

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.
@@ -1,5 +1,5 @@
1
1
  {
2
- "fingerprint": "4338c0c0f41c",
2
+ "fingerprint": "4ab2f1f94f95",
3
3
  "harnesses": {
4
4
  "code": {
5
5
  "plugin": "code",
@@ -44,12 +44,11 @@ On **Completion**: freeze the plan (`Status: Complete`) and flip the feature spe
44
44
 
45
45
  Before modifying code in an unfamiliar area:
46
46
 
47
- 1. If **[`docs/routing.md`](docs/routing.md)** exists, read it for file-pattern → module/doc/agent mapping. If it doesn't exist yet, skip.
48
- 2. Glob `docs/{features,modules/*/features}/**/*.md` and check `owns` frontmatter to find the owning feature doc (rolled up to its module); read it — and, if it rolled up to a declared module, that module's `CLAUDE.md` + `pillars/` — before changes.
49
- 3. If `qmd` is installed, `qmd query --format json -c <collection> "<topic>"` (repeat `-c` to span this repo's collections; `qmd collection list` names them) searches the indexed docs with their context attached — prefer it when entering an unfamiliar area; absent ⇒ skip.
50
- 4. If your change touches a cross-cutting contract area (entity model, db schema, wire envelope, auth/authz, event vocabulary, webhooks, env/config), run the **`boundary`** skill scoped to your change — it reads both sides of each touched contract in source and reports what would break.
51
- 5. If a `docs/memory/` file exists for the domain you're working in, read it for domain knowledge and failure modes
52
- 6. When you author a declared module's docs, its `docs/modules/{m}/CLAUDE.md` auto-loads (the pillar bootstrap) — follow it. For code work it's surfaced via step 2.
47
+ 1. Read **[`docs/routing.md`](docs/routing.md)** — the single map of file-pattern/keyword → canonical doc + module. Match your path or topic to find the owning feature doc and its module; read that doc — and, if its row names a declared module, that module's `CLAUDE.md` + `pillars/` — before changes. (If `routing.md` doesn't exist yet, the repo isn't reconciled — see Bootstrap.)
48
+ 2. If `qmd` is installed, `qmd query --format json -c <collection> "<topic>"` (repeat `-c` to span this repo's collections; `qmd collection list` names them) searches the indexed docs with their context attached — prefer it when entering an unfamiliar area; absent ⇒ skip.
49
+ 3. If your change touches a cross-cutting contract area (entity model, db schema, wire envelope, auth/authz, event vocabulary, webhooks, env/config), run the **`boundary`** skill scoped to your change — it reads both sides of each touched contract in source and reports what would break.
50
+ 4. If a `docs/memory/` file exists for the domain you're working in, read it for domain knowledge and failure modes
51
+ 5. When you author a declared module's docs, its `docs/modules/{m}/CLAUDE.md` auto-loads (the pillar bootstrap) — follow it. For code work it's surfaced via step 1.
53
52
 
54
53
  For the protocol on _writing_ to memory (which file, what belongs there, what doesn't), see **Project Memory** below.
55
54
 
@@ -83,9 +82,9 @@ When implementing a plan, if you discover work that is important but outside the
83
82
 
84
83
  ## Doc Ownership
85
84
 
86
- Feature docs (in `docs/modules/{m}/features/`, or flat `docs/features/` if the module isn't declared) must include YAML frontmatter with `owns`, `touches`, and `depends_on` fields. Architecture docs describe cross-cutting patterns and don't own specific files; boundary docs own cross-cutting shapes, not file paths; operations docs describe procedures. Only feature docs need frontmatter.
85
+ Which doc is canonical for which code paths — and which module each path belongs to — is recorded in **[`docs/routing.md`](docs/routing.md)** (File-Pattern Routes), the single hand-maintained map. Feature docs (in `docs/modules/{m}/features/`, or flat `docs/features/` if the module isn't declared) carry **no** ownership frontmatter; their code paths are their routing row(s). A module is tied to code by its routing patterns (the Module column), not by aggregated globs. Architecture docs describe cross-cutting patterns and don't own specific files; operations docs describe procedures. The only frontmatter a living doc may carry is an optional `anchors:` block (a qmd drift tripwire, not ownership).
87
86
 
88
- The spec-mode agent checks for ownership conflicts during research. If conflicts are found, address them in the spec before proceeding.
87
+ The spec-mode agent checks `routing.md` for ownership conflicts during research (overlapping patterns). If conflicts are found, address them in the spec before proceeding.
89
88
 
90
89
  ---
91
90
 
@@ -121,4 +120,4 @@ Unless explicitly requested:
121
120
  Maintenance triggers (act on these without re-reading `structure.md`):
122
121
 
123
122
  - After plan completion: add a `docs/history/changelog/` entry + update `docs/history/CHANGELOG.md` (no confirmation; include `Commits:` if multi-commit). Non-plan changes (refactors, fixes, API changes): prompt first.
124
- - When you add, move, or delete a doc: update `docs/routing.md` to match. When you move or rename source files: fix the `owns`/`touches` frontmatter in the owning doc; new docs that own code need `owns`/`touches`/`depends_on`.
123
+ - When you add, move, or delete a doc: update `docs/routing.md` to match. When you move or rename source files: update the matching File-Pattern Route(s) in `docs/routing.md`; a new doc that owns code gets its row(s) there (no frontmatter).
@@ -33,7 +33,7 @@ The heatmap needs rolling 1w / 1m / 3m windows, so default `since` to 3 months e
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** (these classification hints used to live in a separate `git-history.md` memory file — they now live here).
35
35
  2. If a recent 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** — don't re-classify commits unless the requested window changed.
36
- 3. Glob `./docs/{features,modules/*/features}/**/*.md` and read `owns` frontmatter to map churn to owning feature docs.
36
+ 3. Read `./docs/routing.md` File-Pattern Routes to map churn to owning feature docs (and their modules).
37
37
 
38
38
  ---
39
39
 
@@ -29,7 +29,7 @@ The upgrade story is the two run back-to-back: install refreshes the engine →
29
29
 
30
30
  These are different axes — keep them clean:
31
31
 
32
- - **`maintenance` audits docs-vs-code _fidelity_** — is the documented behavior _true_ of the code? (stale docs, broken `owns` globs, routing drift). It edits docs for content accuracy.
32
+ - **`maintenance` audits docs-vs-code _fidelity_** — is the documented behavior _true_ of the code? (stale docs, routing rows that match nothing, routing drift). It edits docs for content accuracy.
33
33
  - **You audit repo-vs-spec _conformance_** — is the governance _structure_ shaped to the installed harness version? (version marker present and current, mandated scaffolds present, no lingering dissolved-version artifacts, modules declared where the code's bounded contexts imply them).
34
34
 
35
35
  You never edit a doc for content fidelity (that is `maintenance`); `maintenance` never reshapes the structure to a new version (that is you). Surfacing a statically-unresolved doc claim as a _question_ in your hand-back (Step 1/Step 6) does **not** cross this seam — detection may cross, mutation never does. You observe and ask; you never assert falsity or fix the doc.
@@ -53,11 +53,11 @@ The target is the canonical structure below; converge the repo to it. For a fres
53
53
  docs/
54
54
  ├── README.md # Documentation root — quick links, section index
55
55
  ├── structure.md # Authority map + frontmatter `harness-version` (you own this field)
56
- ├── routing.md # File-pattern → module / doc / agent map
56
+ ├── routing.md # File-pattern → module / doc / agent map — the code-ownership SoT
57
57
  ├── architecture/ # Cross-module design + steering layer
58
58
  │ │ # domain-model, glossary, non-goals, references, open-questions
59
59
  │ └── adr/ # Architecture Decision Records (numbered, immutable)
60
- ├── features/ # Flat default — feature specs with ownership frontmatter
60
+ ├── features/ # Flat default — feature specs (ownership lives in routing.md, no frontmatter)
61
61
  │ └── {feature}/ # subfolder for deep features
62
62
  ├── modules/ # Declared bounded contexts — NOT scaffolded empty; appear by declaration
63
63
  │ └── {module}/ # CLAUDE.md + features/ + pillars/ (module-local doctrine, lazy)
@@ -73,7 +73,7 @@ docs/
73
73
 
74
74
  ### Step 1 — Inventory and classify
75
75
 
76
- Glob every markdown file. Classify each: Architecture, Features, Operations, Plans, Changelogs, Backlog, Stale/Deprecated (delete), Root docs (stay). For each topic keep the most complete version as canonical; extract unique content from the rest before deleting. **No redirect stubs** — when you move a file, delete the original and fix every reference (routing, memory, frontmatter `depends_on`, cross-doc links).
76
+ Glob every markdown file. Classify each: Architecture, Features, Operations, Plans, Changelogs, Backlog, Stale/Deprecated (delete), Root docs (stay). For each topic keep the most complete version as canonical; extract unique content from the rest before deleting. **No redirect stubs** — when you move a file, delete the original and fix every reference (`docs/routing.md`, memory, cross-doc links).
77
77
 
78
78
  While reading each markdown doc to classify it, if the doc names a code symbol it asserts exists that **statically resolves to nothing**, note it as an observation for the Step 6 hand-back — **only** on stacks where static resolution is reliable (stay silent on codegen/reflection/DI/barrel stacks); scoped to docs already being read here, never a whole-repo prose sweep; **docs only**, never code-file comments.
79
79
 
@@ -88,6 +88,9 @@ This is what makes reconcile more than a fresh scaffold. Detect old-shape artifa
88
88
  | repo-wide `docs/pillars/` | module-local `docs/modules/{m}/pillars/`; cross-module doctrine → `docs/architecture/` |
89
89
  | `docs/architecture/overview.md` | split into `domain-model.md` / `glossary.md` / `non-goals.md` / `references.md` / `open-questions.md` |
90
90
  | flat feature docs that belong to a declared module | `docs/modules/{m}/features/` |
91
+ | feature docs carrying `owns`/`touches`/`depends_on` frontmatter (legacy ownership) | migrate each into `docs/routing.md` File-Pattern rows (Pattern ← `owns`; Module ← its module or `—`; Canonical Doc ← the doc), then **strip the ownership frontmatter** from the doc — keep only an optional `anchors:` block if present |
92
+ | `docs/OWNERSHIP_INDEX.md` (legacy derived ownership index) | delete — ownership lives in `docs/routing.md` |
93
+ | no `docs/routing.md` (and the repo owns code) | scaffold it (Step 4) and populate from any legacy `owns`/index above |
91
94
  | no `harness-version` in `structure.md` | stamp it (Step 5) |
92
95
 
93
96
  Only fold what is present. `log()` what you skipped and why.
@@ -98,9 +101,9 @@ Table: `| File | Action | From | To | Reason |` (actions: `Move`, `Merge into {t
98
101
 
99
102
  ### Step 4 — Execute
100
103
 
101
- Create the folder structure; move/fold/merge/delete per the plan; add `Status:` to plan files; add ownership frontmatter to feature docs (call the `documentation` skill's **frontmatter derivation** for `owns`/`touches`/`depends_on`); merge scattered backlogs into `docs/history/backlog.md`; fix links broken by moves. Scaffold missing mandated files **by calling the `documentation` skill for each template** — you orchestrate, the skill supplies templates:
104
+ Create the folder structure; move/fold/merge/delete per the plan; add `Status:` to plan files; record each feature doc's code paths as `docs/routing.md` File-Pattern rows (call the `documentation` skill's **routing-map derivation**) and strip any legacy ownership frontmatter; merge scattered backlogs into `docs/history/backlog.md`; fix links broken by moves. Scaffold missing mandated files **by calling the `documentation` skill for each template** — you orchestrate, the skill supplies templates:
102
105
 
103
- - `docs/structure.md` (with `harness-version`), `docs/history/CHANGELOG.md`, `docs/history/backlog.md`, `docs/memory/index.md`, `docs/memory/main.md`, and the repo-root `README.md` (filled from the real lockfile/scripts/layout — **never overwrite an existing root README**).
106
+ - `docs/structure.md` (with `harness-version`), `docs/routing.md` (the code-ownership map — scaffold when the repo owns code), `docs/history/CHANGELOG.md`, `docs/history/backlog.md`, `docs/memory/index.md`, `docs/memory/main.md`, and the repo-root `README.md` (filled from the real lockfile/scripts/layout — **never overwrite an existing root README**).
104
107
 
105
108
  Scaffold `docs/memory/facts/` so the distilled tier has a home from day one: the `session-reflect` hook appends session lessons to the per-actor inbox at `docs/memory/inbox/{actor}.md` (not a scaffold — created mechanically on first reflection), and the `distiller` digests that queue down into fact-cards under `docs/memory/facts/`, consuming the entries it digests (no high-water mark, no `.digest-state.md`). Without the facts dir, a freshly-baselined consumer accrues inbox entries the distiller has nowhere to land — so seed the empty distilled tier alongside the hook-written inbox tier.
106
109
 
@@ -130,10 +133,10 @@ This augments routing; it never supersedes the Step 6 ownership resolution.
130
133
 
131
134
  ### Step 6 — Module proposal
132
135
 
133
- Modules are _declared_, never inferred from physical layout. Derive the repo's candidate bounded contexts directly from the code and docs: distinct wire surfaces (who owns routes/handlers), schema/data-access ownership, entry points and process units, plus any contexts `docs/architecture/` or feature `owns` globs already name.
136
+ Modules are _declared_, never inferred from physical layout. Derive the repo's candidate bounded contexts directly from the code and docs: distinct wire surfaces (who owns routes/handlers), schema/data-access ownership, entry points and process units, plus any contexts `docs/architecture/` or `docs/routing.md` patterns already name.
134
137
 
135
- - Propose the derived contexts as candidate modules. For each, partition existing flat feature docs by `owns`-glob overlap.
136
- - **Propose — don't force.** Declaration is opt-in: a single-context app stays flat (so does a monolith whose contexts all share one kernel); declare `docs/modules/{m}/` only when the author accepts a context as a module. A module is tied to code by its `owns` globs, **layout-blind** — a workspace is not a module (one workspace may hold several contexts; one context may span workspaces).
138
+ - Propose the derived contexts as candidate modules. For each, partition existing flat feature docs by `docs/routing.md` pattern overlap (which docs' routing patterns fall inside the context's code).
139
+ - **Propose — don't force.** Declaration is opt-in: a single-context app stays flat (so does a monolith whose contexts all share one kernel); declare `docs/modules/{m}/` only when the author accepts a context as a module. A module is tied to code by its `docs/routing.md` patterns (recorded in the Module column), **layout-blind** — a workspace is not a module (one workspace may hold several contexts; one context may span workspaces). When a context is accepted, set the Module column on its routing rows.
137
140
 
138
141
  If Step 5b skipped because `qmd` was absent, carry its one advisory line into the hand-back — _"qmd not installed — semantic retrieval unavailable; glob routing active."_ — advisory, never an error, never a gate.
139
142
 
@@ -149,7 +152,7 @@ If the user **declines** the advisory rather than running the follow-up, record
149
152
 
150
153
  ### Step 7 — Verify
151
154
 
152
- Confirm all mandated files exist; `structure.md` carries the current `harness-version`; no dead links in `docs/structure.md`; every plan has a `Status:`; feature docs have ownership frontmatter; no dissolved-version artifacts remain; no docs outside the canonical structure.
155
+ Confirm all mandated files exist; `structure.md` carries the current `harness-version`; `docs/routing.md` exists and its File-Pattern rows cover the owned code paths; no dead links in `docs/structure.md`; every plan has a `Status:`; no feature doc carries `owns`/`touches`/`depends_on` frontmatter; no dissolved-version artifacts remain; no docs outside the canonical structure.
153
156
 
154
157
  ---
155
158
 
@@ -161,7 +164,7 @@ Conformance, not fidelity. Report a table; fix nothing destructively without ask
161
164
  - **Published-version currency** _(advisory, network)_ — the installed `.claude/harness.json` records the kit's `version`; the published kit may have moved past it. Attempt `npm view @nurix/etna version` (the kit is a restricted package — needs npm auth + network). **Guard:** on _any_ failure — offline, no auth, npm absent, timeout — skip and report one line: _"couldn't check the published harness version — re-run `npx @nurix/etna --name=code` to refresh to the latest."_ On success, compare the published version against `.claude/harness.json`'s `version`; if published is ahead, recommend re-running the CLI to pull the newer kit. Never a gate, never blocks.
162
165
  - **Kit build fingerprint (digest)** _(informational)_ — `.claude/harness.json` carries a `digest`: a deterministic fingerprint of the exact kit **build** the consumer installed (`build-data` computes it over the shipped bundle). Two installs share a digest iff they are byte-identical builds; a hotfix that changes kit bytes without bumping `version` still moves the digest — so it answers _which build am I on_, finer than `version` alone. **Don't recompute it over `.claude/` to self-check:** the installed layout is a superset of the build (the project `CLAUDE.md` sits at the repo root, `.claude/` adds `settings.json`/`harness.json`/local rule files), so paths and file sets differ **by design** — a recompute would never match. The actionable upgrade signals are the two checks above (major-version reconcile + published-version); the digest is provenance, and the seed for any future published-digest drift check.
163
166
  - **Scaffold completeness** — every mandated file present.
164
- - **Dissolved-version residue** — any `operations/guardrails.md`, repo-wide `docs/pillars/`, `architecture/overview.md`, a persisted `docs/boundaries/` tree, or other old-shape artifact lingering.
167
+ - **Dissolved-version residue** — any `operations/guardrails.md`, `docs/OWNERSHIP_INDEX.md`, feature docs still carrying `owns`/`touches`/`depends_on` frontmatter, repo-wide `docs/pillars/`, `architecture/overview.md`, a persisted `docs/boundaries/` tree, or other old-shape artifact lingering.
165
168
  - **Module declaration coverage** — do the repo's bounded contexts have declared module homes where the author intended them? (Surface gaps; never auto-declare.)
166
169
  - **`docs/tests/` ownership** — present-with-content, or absent. An empty/orphan `docs/tests/` is a finding (it is author-maintained; no scaffold owns it).
167
170
 
@@ -169,7 +172,7 @@ Conformance, not fidelity. Report a table; fix nothing destructively without ask
169
172
 
170
173
  - **Declarative, idempotent.** Re-running on a current repo is a no-op. Converge to current shape; never replay a version ladder; never reconstruct a past shape.
171
174
  - **One sentinel.** `docs/structure.md` `harness-version` is the only baseline/version marker. Do not reintroduce a `docs/memory/index.md` "is-baselined" check.
172
- - **Modules are declared, layout-blind.** Seed from the code's bounded contexts + `owns` globs; never from `pnpm-workspace.yaml`/workspace walls. Propose, don't force.
175
+ - **Modules are declared, layout-blind.** Seed from the code's bounded contexts + `docs/routing.md` patterns; never from `pnpm-workspace.yaml`/workspace walls. Propose, don't force.
173
176
  - **You orchestrate docs; the `documentation` skill supplies templates.** It is a library — you never expect it to baseline.
174
177
  - **Never overwrite an existing root `README.md`.** It is human-authored.
175
178
  - **Stay in `docs/` (+ root `README.md` scaffold) and `docs/memory/harness-manager.md`.** You do not edit `CLAUDE.md` (the CLI ships it) or production code.
@@ -18,22 +18,22 @@ Out of scope (handled by the `boundary` skill, which derives contracts dynamical
18
18
 
19
19
  1. If `./docs/memory/maintenance.md` exists, read it for last review state, ownership snapshots, high-churn paths, and known failure modes.
20
20
  2. If `./docs/memory/boundary.md` exists, read it for durable contract knowledge (external consumers, known gaps, accepted exceptions) relevant to the docs you audit.
21
- 3. If `./docs/routing.md` exists, read it for the current file-pattern-to-doc mapping.
21
+ 3. Read `./docs/routing.md` — the code-ownership map (file-pattern → canonical doc + module). It is the ownership source of truth for this audit.
22
22
 
23
23
  ## Step 1: Build Ownership Map
24
24
 
25
25
  1. Read `docs/structure.md` for the authority map
26
- 2. Glob `docs/{features,modules/*/features}/**/*.md` and extract YAML frontmatter (`owns`, `touches`, `depends_on`)
27
- 3. Build a map: glob pattern → owning doc
26
+ 2. Read `docs/routing.md` File-Pattern Routes
27
+ 3. Build a map: pattern → owning doc + module (this IS the source of truth — there is no frontmatter to glob)
28
28
 
29
- **Architecture-first fallback.** If that glob yields **no `owns` frontmatter at all** (a fresh-baseline repo can carry thousands of LOC and zero feature docs), drive this pass's ownership/drift surface off `docs/architecture/**` file-references instead — they become the **primary** ownership map for Steps 2–5. Feature-`owns` stays primary the moment any appears — this is a fallback, not a replacement.
29
+ **Architecture-first fallback.** If `docs/routing.md` is absent or has no File-Pattern rows (a fresh-baseline repo can carry thousands of LOC and zero feature docs), drive this pass's ownership/drift surface off `docs/architecture/**` file-references instead — they become the **primary** ownership map for Steps 2–5. The routing map stays primary the moment any row appears — this is a fallback, not a replacement.
30
30
 
31
31
  ## Step 2: Validate Ownership
32
32
 
33
- For each doc with `owns` frontmatter:
33
+ For each File-Pattern row in `docs/routing.md`:
34
34
 
35
- - Verify the glob patterns match existing files
36
- - Report deleted paths, empty globs, orphaned ownership
35
+ - Verify the pattern matches existing files
36
+ - Report patterns matching nothing, deleted paths, orphaned rows (doc no longer exists)
37
37
 
38
38
  For each code symbol or path a doc explicitly **names** (function/export/route/type):
39
39
 
@@ -52,8 +52,8 @@ Run `git log --since="2 weeks ago" --name-only --pretty=format:"%h %s"` to find
52
52
 
53
53
  For each changed file:
54
54
 
55
- - Match against `owns` patterns from every feature doc — flat and module-local alike (`docs/{features,modules/*/features}/**/*.md`) → identify the owning doc
56
- - If no owner exists → flag as unowned
55
+ - Match against the File-Pattern routes in `docs/routing.md` (narrower pattern wins) → identify the owning doc
56
+ - If no route matches → flag as unowned
57
57
  - If owner exists → compare last modified dates (`git log -1 --format="%ci" -- <path>`), flag docs where code changed more recently (14-day threshold)
58
58
 
59
59
  ## Step 4: Check Routing Table Drift
@@ -64,7 +64,7 @@ If `./docs/routing.md` exists:
64
64
  2. Check for new top-level source directories (the repo's actual source roots — derive them, never assume `src/`) not covered by any routing entry
65
65
  3. Fix drift directly, or backlog if unclear
66
66
 
67
- Also flag **unowned paths** — top-level source directories with no owning feature doc (no `owns` glob covers them).
67
+ Also flag **unowned paths** — top-level source directories with no owning feature doc (no `docs/routing.md` pattern covers them).
68
68
 
69
69
  Also catch a **stale greenfield self-label.** If `routing.md` (or `structure.md`) asserts the repo is greenfield — _"Greenfield. No source code or feature docs exist yet"_ or similar — **but a real source tree exists** (the derived source roots from this step's item 2 above, or Step 5's Unowned-code derivation, are non-empty, e.g. a populated `packages/` of real workspaces), the self-label has gone stale: the scaffold filled in but the doc still announces an empty repo. Raise it as a question (e.g. `routing.md says "No source code exists yet" but packages/ holds 5 workspaces — confirm the greenfield label should be retired`).
70
70
 
@@ -72,7 +72,7 @@ Also catch a **stale greenfield self-label.** If `routing.md` (or `structure.md`
72
72
 
73
73
  **Architecture drift:** Grep `docs/architecture/` for file path references. Verify referenced paths still exist. Remove or update stale references.
74
74
 
75
- **Unowned code:** Compare the repo's actual top-level source directories (derive them — the top-level dirs that contain code, or the roots named across `owns` globs in `structure.md` / feature frontmatter; do not assume `src/`) against the union of all `owns` patterns from both flat and module-local feature docs (`docs/{features,modules/*/features}/**/*.md`). Report directories with no feature doc ownership.
75
+ **Unowned code:** Compare the repo's actual top-level source directories (derive them — the top-level dirs that contain code, or the roots named across `docs/routing.md` patterns; do not assume `src/`) against the File-Pattern routes in `docs/routing.md`. Report directories no routing pattern covers.
76
76
 
77
77
  **Backlog health:** Read `docs/history/backlog.md`. Report items older than 30 days. Count pending by priority.
78
78
 
@@ -95,7 +95,7 @@ For unowned code paths:
95
95
  2. Update `docs/memory/maintenance.md` with last review date, stale docs fixed, unowned paths, backlog items created
96
96
  3. Report findings: stale docs, broken ownership, unowned code, architecture drift, backlog health
97
97
  4. **Inbox-distillation threshold.** Count undigested inbox entries — `## ` entry blocks across `docs/memory/inbox/*.md` (the inbox is consume-on-digest, so every block present is undigested). If the count is **≥5**, add one line to the report **proposing** a `distiller` `facts` run — propose only, never auto-run, no cron. If the user declines or ignores it, do nothing: the count keeps growing and the proposal reappears next pass — that recurrence _is_ the dedupe, so never backlog it.
98
- 5. **Docs-distillation threshold.** Per target doc, count undigested fact-cards (`invalid_from: null`, the doc's path not in their `digested_into:`) that **touch** it by the structural intersection in `skills/distiller/references/docs-mode.md` Resolution 1 (provenance∩`owns` strong, entities∩declared-ownership supporting — qmd-independent). If **≥10** map to **one** doc, add one line to the report **proposing** a `distiller docs --doc <path>` run on that doc — propose only, never auto-run, no cron. Declined or ignored ⇒ the count keeps growing and the proposal reappears next pass; that recurrence _is_ the dedupe, so never backlog the proposal.
98
+ 5. **Docs-distillation threshold.** Per target doc, count undigested fact-cards (`invalid_from: null`, the doc's path not in their `digested_into:`) that **touch** it by the structural intersection in `skills/distiller/references/docs-mode.md` Resolution 1 (provenance ∩ the doc's `routing.md` patterns strong, entities ∩ declared-ownership supporting — qmd-independent). If **≥10** map to **one** doc, add one line to the report **proposing** a `distiller docs --doc <path>` run on that doc — propose only, never auto-run, no cron. Declined or ignored ⇒ the count keeps growing and the proposal reappears next pass; that recurrence _is_ the dedupe, so never backlog the proposal.
99
99
 
100
100
  ## Step 8: Refresh Index (Optional)
101
101
 
@@ -21,7 +21,7 @@ First, understand the documentation landscape:
21
21
  2. If `./docs/features/README.md` exists, read it to see existing feature specs and where the new spec fits; otherwise glob the feature docs directly
22
22
  3. If `./docs/memory/spec-mode.md` exists, read it for feature doc inventory, ownership conflict zones, and lessons from previous research
23
23
  4. Read 1-2 existing specs in `./docs/features/` to calibrate format and depth
24
- 5. Glob `./docs/{features,modules/*/features}/**/*.md` and read YAML frontmatter (`owns`, `touches`, `depends_on`) from each to build the ownership map.
24
+ 5. Read `./docs/routing.md` (File-Pattern Routes) to build the ownership map — pattern → canonical doc + module. This is the source of truth for what code paths are already owned (feature docs carry no ownership frontmatter).
25
25
 
26
26
  This tells you what already exists, what's adjacent, how detailed the spec should be, and what code paths are already owned.
27
27
 
@@ -32,7 +32,7 @@ This tells you what already exists, what's adjacent, how detailed the spec shoul
32
32
  3. **Affected modules** — Identify what files, routes, components, and data flows are relevant
33
33
  4. **Current state** — Understand how the system works today in the area being specified
34
34
  5. **Dependencies** — Map what this feature touches and what depends on it
35
- 6. **Ownership conflicts** — Compare the new feature's intended code paths against existing `owns`/`touches` declarations. Report overlaps.
35
+ 6. **Ownership conflicts** — Compare the new feature's intended code paths against existing `docs/routing.md` patterns. Report overlaps.
36
36
 
37
37
  ## What You Return
38
38
 
@@ -43,7 +43,7 @@ Structure your findings as:
43
43
  - **Affected modules**: Files, routes, components that will be involved
44
44
  - **Current behavior**: How the relevant part of the system works today
45
45
  - **Conventions**: Naming, structure, and patterns to follow based on existing code
46
- - **Ownership conflicts**: Existing feature docs whose `owns` or `touches` paths overlap with the proposed feature. Include the conflicting paths and the owning doc name.
46
+ - **Ownership conflicts**: Existing feature docs whose `docs/routing.md` patterns overlap with the proposed feature. Include the conflicting paths and the owning doc name.
47
47
  - **Risks or concerns**: Anything the spec should address or call out
48
48
 
49
49
  Use the documentation skill's style guide and conventions when structuring your findings — imperative voice, ASCII diagrams for flows, function signatures over implementations, concise.
@@ -1,11 +1,11 @@
1
1
  {
2
2
  "harness": "code",
3
3
  "name": "code",
4
- "version": "1.1.1",
4
+ "version": "2.0.0",
5
5
  "files": [
6
6
  ".prettierrc.json",
7
7
  ".prettierignore",
8
8
  ".vscode/settings.json"
9
9
  ],
10
- "digest": "9f47af1e10a9"
10
+ "digest": "3d1464ab6963"
11
11
  }
@@ -66,16 +66,16 @@ Read [`method.md`](method.md) (surprisal / EDU / reconciliation / bi-temporal vo
66
66
  ### 1. Resolve the target doc, read the three roots in order
67
67
 
68
68
  1. `method.md` (algorithm vocabulary).
69
- 2. The **target doc** — full current prose + its `owns`/`touches` frontmatter. This is the SSoT you are proposing to revise; you read it before you draft so conflicts surface as questions, not silent overwrites.
69
+ 2. The **target doc** — full current prose + the `docs/routing.md` patterns that map to it (the paths it owns). This is the SSoT you are proposing to revise; you read it before you draft so conflicts surface as questions, not silent overwrites.
70
70
  - `--doc <path>` → that doc.
71
- - `--feature <slug>` / bare → the spec that just flipped to `Active` (Completion names it), or the feature doc whose `owns` glob covers the plan's Proposed-Changes paths. Glob `docs/{features,modules/*/features}/**/*.md`, match `owns` against changed paths. Architecture/operations docs have no `owns` — for those, fall to entity/semantic match.
71
+ - `--feature <slug>` / bare → the spec that just flipped to `Active` (Completion names it), or the feature doc whose `docs/routing.md` pattern covers the plan's Proposed-Changes paths. Match the routing patterns against changed paths. Architecture/operations docs own no paths in routing — for those, fall to entity/semantic match.
72
72
  - No doc resolves → Edge Case A.
73
73
  3. The **pillar headlines** — the doctrine pillar (`## Pn —` headlines) and the decisions pillar (`## Dn —` headlines) plus each one's one-line Principle/Decision statement. Read **every** decision headline except those marked superseded: a decision carrying a `Reversed by D-M` marker (or a legacy `Status: tentative`) is NOT a binding pillar headline and is skipped; absence of any status marker means the decision is live (the new append-only model has no `Status: committed` field — a live decision is simply one nothing has reversed). Headlines only, never the bodies — this is the conservative contradiction-check substrate (Resolution 4).
74
74
 
75
75
  ### 2. INPUT SELECTION — gather the cards "touching" the target (Resolution 1) — _closes F2, F3, F5_
76
76
 
77
- 1. **Structural retriever (always runs, qmd-independent).** Read every card in `docs/memory/facts/*.md`. A card _structurally touches_ the target when its `provenance` paths or `entities` intersect the target's `owns`/`touches` globs — match defined precisely in Resolution 1.
78
- 2. **Semantic retriever (qmd, optional).** If `command -v qmd` succeeds, for the target's identity (title + each `owns` glob stem + any `anchors:` query) run `qmd query --format json -c {repo}-facts "<the doc's subject>"`. `{repo}` = repo dir name; scope with `-c` always; repeat `-c` per relevant `{repo}-*` facts collection (the set `qmd collection list` names). qmd absent ⇒ skip silently, note in the report that selection ran structural-only (changes recall, not correctness).
77
+ 1. **Structural retriever (always runs, qmd-independent).** Read every card in `docs/memory/facts/*.md`. A card _structurally touches_ the target when its `provenance` paths or `entities` intersect the target's `docs/routing.md` patterns — match defined precisely in Resolution 1.
78
+ 2. **Semantic retriever (qmd, optional).** If `command -v qmd` succeeds, for the target's identity (title + each routing-pattern stem + any `anchors:` query) run `qmd query --format json -c {repo}-facts "<the doc's subject>"`. `{repo}` = repo dir name; scope with `-c` always; repeat `-c` per relevant `{repo}-*` facts collection (the set `qmd collection list` names). qmd absent ⇒ skip silently, note in the report that selection ran structural-only (changes recall, not correctness).
79
79
  3. **Bi-temporal + digestion gate (F2, F3).** From the union, drop:
80
80
  - any card with `invalid_from` ≠ `null` (superseded — list as "skipped: superseded");
81
81
  - any card whose `digested_into:` already lists the target doc path (already consumed here);
@@ -169,8 +169,8 @@ A card **touches** the target doc iff it satisfies **either** retriever, and is
169
169
 
170
170
  **(a) Structural intersection (exact, always evaluated).** True when ANY of:
171
171
 
172
- 1. **Provenance match (STRONG signal).** A `commit <sha>` entry in the card's `provenance` resolves to changed files (`git show --name-only <sha>` when the commit is local); a changed file under the target's `owns`/`touches` globs is a match. (`session <id>` entries carry no paths and do not participate; an ADR/brainstorm path matches the globs directly.) This is strong because the card derives from a commit that edited code the doc owns.
173
- 2. **Entity match (SUPPORTING signal).** A normalized name in the card's `entities` equals (case-insensitively, after kebab/camel normalization) a module/feature stem in an `owns` glob, the doc title, or a symbol the doc explicitly names. **Bare prose mentions do NOT count** — only declared ownership, so "touching" can't be triggered by a doc that merely discusses an entity it doesn't own.
172
+ 1. **Provenance match (STRONG signal).** A `commit <sha>` entry in the card's `provenance` resolves to changed files (`git show --name-only <sha>` when the commit is local); a changed file under the target's `docs/routing.md` patterns is a match. (`session <id>` entries carry no paths and do not participate; an ADR/brainstorm path matches the patterns directly.) This is strong because the card derives from a commit that edited code the doc owns.
173
+ 2. **Entity match (SUPPORTING signal).** A normalized name in the card's `entities` equals (case-insensitively, after kebab/camel normalization) a module/feature stem in one of the target's `docs/routing.md` patterns, the doc title, or a symbol the doc explicitly names. **Bare prose mentions do NOT count** — only declared ownership (its routing patterns), so "touching" can't be triggered by a doc that merely discusses an entity it doesn't own.
174
174
 
175
175
  **(b) Semantic neighborhood (qmd, optional, recall-only).** A card returned by `qmd query -c {repo}-facts "<doc subject>"` within qmd's default result window. Semantic hits with **no** structural intersection are still candidates but flagged `[semantic-only]` in the delta — the link is associative, not provenance-grounded, so the reviewer treats it as lower-trust and may reject on link-strength alone.
176
176
 
@@ -189,7 +189,7 @@ A card may touch **several** docs (its entities span modules) — expected, hand
189
189
  | **`## Architecture` / `## Key Functions`** (feature doc) | Additive correction only when a card names a concrete, code-anchored fact (a new function, a moved file). Prefer Current Behavior unless the card is structural. | Code-anchored structure, not prose. |
190
190
  | **A new changelog entry** in `docs/history/changelog/` (via `documentation` skill's Changelog template, `### Added`/`### Modified`/`### Removed`) | Draft a changelog line for a code change a card witnesses, when a plan just completed. | Append-only history; a _new_ file, never an edit. |
191
191
 
192
- **Never writable by distill②** (hard stops): `## Goal`, `## Goals & Non-Goals`, `## Approach`, `## Open Questions`, `## State`, frontmatter `owns`/`touches`/`anchors` (maintenance/spec axis — P19), any **pillar** file, any **plan** (frozen), any **existing** changelog entry (frozen history), any **boundary** file. A card implying one of these needs a change becomes a **question** (below) or, for pillars, an **escape item** (Resolution 4).
192
+ **Never writable by distill②** (hard stops): `## Goal`, `## Goals & Non-Goals`, `## Approach`, `## Open Questions`, `## State`, the optional `anchors:` frontmatter (the only frontmatter a doc carries; ownership lives in `docs/routing.md` — maintenance/spec axis — P19), any **pillar** file, any **plan** (frozen), any **existing** changelog entry (frozen history), any **boundary** file. A card implying one of these needs a change becomes a **question** (below) or, for pillars, an **escape item** (Resolution 4).
193
193
 
194
194
  **Per-line provenance (the invariant, mechanized).** Every drafted line carries `[from: fact-<slug>]` for each contributing card. A line with no such tag is a **defect** — not presented (Acceptance A2). On accept the tag is stripped from the final doc prose (it was review scaffolding); the durable forward-link survives as `digested_into:` (Resolution 3) — so traceability is preserved without polluting human-owned prose.
195
195
 
@@ -1,15 +1,15 @@
1
1
  ---
2
2
  name: documentation
3
- description: Template & generator library for technical docs — the skill agents call to produce a doc from a template. Use to (1) document a feature or module, (2) create or update a changelog entry, (3) document data flows or Redux state, (4) add to protected files, (5) record an architecture decision (ADR), (6) create or update the project root README, (7) create or update a plan, (8) derive ownership frontmatter (`owns`/`touches`/`depends_on`) from code, (9) scaffold a standard doc (README, structure.md, CHANGELOG, backlog, memory) from its template, or (10) co-author any technical doc. Baselining / reconciling a repo's docs to the installed harness version is the **`harness-manager` agent** (which calls this skill for each template) — this skill does not orchestrate baseline. Triggers on "document this", "create docs", "update changelog", "add to protected files", "ADR", "architecture decision", "root README", "plan", "feature doc".
3
+ description: Template & generator library for technical docs — the skill agents call to produce a doc from a template. Use to (1) document a feature or module, (2) create or update a changelog entry, (3) document data flows or Redux state, (4) add to protected files, (5) record an architecture decision (ADR), (6) create or update the project root README, (7) create or update a plan, (8) derive the routing map (code path → canonical doc + module) for `docs/routing.md` from code, (9) scaffold a standard doc (README, structure.md, routing.md, CHANGELOG, backlog, memory) from its template, or (10) co-author any technical doc. Baselining / reconciling a repo's docs to the installed harness version is the **`harness-manager` agent** (which calls this skill for each template) — this skill does not orchestrate baseline. Triggers on "document this", "create docs", "update changelog", "add to protected files", "ADR", "architecture decision", "root README", "plan", "feature doc".
4
4
  ---
5
5
 
6
6
  # Technical Documentation Skill
7
7
 
8
- **This skill is a template & generator library, not an orchestrator.** It supplies the templates, the frontmatter-derivation generator, and the co-authoring workflow that _agents_ call to produce individual docs. It does **not** baseline, audit, or reconcile a repo's doc tree — that is the **`harness-manager` agent**, which calls this skill for each template it scaffolds. Reach here to generate _one_ doc from a template; reach for `harness-manager` to bring a whole repo into shape.
8
+ **This skill is a template & generator library, not an orchestrator.** It supplies the templates, the routing-map-derivation generator, and the co-authoring workflow that _agents_ call to produce individual docs. It does **not** baseline, audit, or reconcile a repo's doc tree — that is the **`harness-manager` agent**, which calls this skill for each template it scaffolds. Reach here to generate _one_ doc from a template; reach for `harness-manager` to bring a whole repo into shape.
9
9
 
10
10
  Document contracts and architecture, not implementation details. Show function signatures and API shapes — never paste full implementations (they rot fast). Use ASCII diagrams over prose for flows. Only document state at persistence boundaries (Redux persistence, DB schemas, API shapes), not component-level or transient state. Mark deprecated fields with `// UNUSED:` comments. Breaking changes belong in changelogs only, not module docs.
11
11
 
12
- **No redirect docs.** When moving a doc to a new location, delete the old file entirely. Update all references (routing, memory files, frontmatter `depends_on`, cross-doc links) to point to the new path. Never leave a stub file that says "Moved to X" — redirect docs rot, clutter the repo, and create false search hits.
12
+ **No redirect docs.** When moving a doc to a new location, delete the old file entirely. Update all references (`docs/routing.md`, memory files, cross-doc links) to point to the new path. Never leave a stub file that says "Moved to X" — redirect docs rot, clutter the repo, and create false search hits.
13
13
 
14
14
  **Present tense, current state only.** Active docs (everything outside `docs/history/`) describe the system _as it is now_ — what exists and how it works today. They never narrate how it got there: no migration/fold history, no dated "shipped/verified/built on YYYY-MM-DD" markers, no "ex-`@nurix/X`, folded 2026-06-12" provenance, no "was X → now Y" change journeys, no "removed/deleted in the <date> fold". The historical record — when and how things changed — lives **only** in `docs/history/` (changelog, plans, ADRs); `docs/memory/` is the agent's dated log and is likewise exempt. A doc may cite an ADR for the _why_ (the decision rationale), but must not narrate the _when/how it changed_. Routing/index docs point only to current authority docs — never to a historical plan or changelog as the "read first" source. When you find historical narration in an active doc, rewrite it to the present-tense fact and let `docs/history/` carry the story.
15
15
 
@@ -54,54 +54,48 @@ User request
54
54
 
55
55
  ---
56
56
 
57
- ## Frontmatter Derivation
57
+ ## Routing-Map Derivation
58
58
 
59
- When creating or updating a feature doc in `docs/features/`, generate `owns`, `touches`, `depends_on` frontmatter from the source code the doc describes.
59
+ When creating or updating a feature doc, derive its **`docs/routing.md` File-Pattern Routes row(s)** — the code paths it is canonical for — from the source the doc describes. Code ownership lives in `routing.md`, never in feature-doc frontmatter.
60
60
 
61
61
  ### When to run
62
62
 
63
- - **Baseline audit Step 6** — for every feature doc missing frontmatter
64
- - **New feature doc** — when creating a doc via the Module Documentation template
65
- - **Doc update** — when updating an existing feature doc and the frontmatter is missing or the documented scope changed
63
+ - **Baseline / reconcile** — for every feature doc whose code paths aren't yet mapped in `routing.md` (the `harness-manager` agent calls this)
64
+ - **New feature doc** — when creating a doc via the Feature/Module template, add its routing row(s)
65
+ - **Doc update** — when the documented scope changes, update the doc's routing row(s)
66
66
 
67
- ### How to derive values
67
+ ### How to derive a row
68
68
 
69
- **1. Identify `owns` patterns**
69
+ A routing row is `| Pattern | Module | Canonical Doc | Memory |`.
70
70
 
71
- Read the feature doc's content. Extract every source file path referenced in the doc (file listings, function locations, component paths). Group them into the narrowest glob patterns that cover all referenced files without overlapping other features.
71
+ **1. Pattern** (the path scope — the old `owns`)
72
72
 
73
- | Doc references | `owns` pattern |
73
+ Read the doc's content. Extract every source file path it references (file listings, function locations, component paths). Group them into the narrowest glob patterns that cover all referenced files without overlapping another doc's pattern at equal specificity. A doc may need several rows.
74
+
75
+ | Doc references | Pattern |
74
76
  | ------------------------------------ | ------------------------- |
75
77
  | Multiple files under one directory | `src/feature/**` |
76
78
  | Specific files in a shared directory | List each file explicitly |
77
79
  | A single entry-point file | The exact file path |
78
80
 
79
- Verify patterns match real files — glob each pattern against the codebase. Remove any that match nothing.
80
-
81
- **2. Identify `touches` patterns**
82
-
83
- From the same source files the doc describes, find imports and calls to code outside the `owns` scope. These are files the feature uses but doesn't own.
81
+ Glob each pattern against the codebase; drop any that match nothing.
84
82
 
85
- Common `touches` candidates:
83
+ **2. Module**
86
84
 
87
- - Shared Redux slices the feature reads/writes
88
- - Utility functions from other modules
89
- - Shared hooks the feature calls
90
- - API route files the feature's frontend calls
85
+ The declared module the pattern belongs to (the `docs/modules/{m}/` it lives under), or `—` if the repo is flat. Rows sharing a Module value are what ties that module to code.
91
86
 
92
- Keep `touches` to direct dependencies only — not transitive ones.
87
+ **3. Canonical Doc & Memory**
93
88
 
94
- **3. Identify `depends_on` docs**
89
+ Canonical Doc = this doc's path (`features/…` when flat, `modules/{m}/features/…` when the module is declared). Memory = the `docs/memory/` file for the area, or `—`.
95
90
 
96
- Check for explicit cross-references to other docs in `docs/features/` or `docs/architecture/`. Also check if the feature's `touches` paths are `owns`-ed by another feature doc — that doc is a dependency.
91
+ > The old `touches`/`depends_on` relationships are no longer recorded as ownership. A doc's dependencies on other docs are expressed inline in its prose (links); cross-cutting contracts are diagnosed by the `boundary` skill from source, not persisted.
97
92
 
98
93
  ### Rules
99
94
 
100
- - Every feature doc must have all three fields, even if empty (`depends_on: []`)
101
- - Use glob patterns for directories, explicit paths for individual files
102
- - Don't list paths that don't exist in the codebase
103
- - When a doc covers a deep feature with sub-specs (e.g., `editor/`), each sub-spec gets its own frontmatter — don't duplicate ownership across siblings
104
- - For baseline audits with 10+ files needing frontmatter, use parallel sub-agents to read and analyze the source files
95
+ - One canonical doc per path. A pattern must not overlap another row at equal specificity — the narrower pattern wins; equal-specificity overlap is a conflict to resolve.
96
+ - Use glob patterns for directories, explicit paths for individual files. Don't list paths that don't exist in the codebase.
97
+ - When a doc covers a deep feature with sub-specs (e.g., `editor/`), each sub-spec gets its own row(s) — don't duplicate a path across siblings.
98
+ - For baseline/reconcile with many docs, use parallel sub-agents to read source and propose rows.
105
99
 
106
100
  ---
107
101
 
@@ -125,6 +119,6 @@ For docs that don't match templates:
125
119
 
126
120
  | File | Use For |
127
121
  | --- | --- |
128
- | `references/templates.md` | docs/README.md, structure.md, frontmatter, scaffolds (CHANGELOG, backlog, memory), feature, changelog, plan, protected files, ADR, project root README templates |
122
+ | `references/templates.md` | docs/README.md, structure.md, routing.md, scaffolds (CHANGELOG, backlog, memory), feature, changelog, plan, protected files, ADR, project root README templates |
129
123
  | `references/style-guide.md` | Writing rules, formatting conventions |
130
124
  | `references/examples.md` | Good vs bad documentation examples |
@@ -91,6 +91,7 @@ Each topic has one canonical location. Read from here, not from plans or changel
91
91
 
92
92
  | Topic | Authority | Key Files |
93
93
  | ----- | --------- | --------- |
94
+ | Code-path ownership (path → doc + module) | `docs/routing.md` | File-Pattern Routes |
94
95
  | System architecture + steering | `docs/architecture/` | domain-model, glossary, non-goals, references, adr/ |
95
96
  | Feature behavior | `docs/features/` (or `docs/modules/{m}/features/`) | {key files} |
96
97
  | Declared modules (bounded contexts) | `docs/modules/{m}/` | `features/` + `pillars/` |
@@ -109,9 +110,10 @@ Plan (Status: Draft) → Implementation → Feature Doc or Architecture Update
109
110
 
110
111
  ## Folder Rules
111
112
 
112
- - `docs/features/`: Living reference for implemented features. Each spec includes YAML frontmatter with `owns`, `touches`, `depends_on` fields declaring code ownership.
113
+ - `docs/routing.md`: The single hand-maintained map from code paths (and keywords) to the canonical doc and module for each. Code ownership lives here, not in feature-doc frontmatter. Update it whenever you add/move/delete a doc or move/rename owned source.
114
+ - `docs/features/`: Living reference for implemented features. Carry **no** ownership frontmatter — a feature doc's code paths are declared by its row(s) in `docs/routing.md`. (An optional `anchors:` block — a qmd drift tripwire, see §3 — is the only frontmatter a doc may carry.)
113
115
  - `docs/architecture/`: System-wide patterns and the cross-module steering layer (domain model, glossary, non-goals, references, ADRs). Update when cross-cutting concerns change.
114
- - `docs/modules/{m}/`: Vertical bounded contexts, **declared** (not inferred from layout) and tied to code by their `owns` globs. Each owns `features/` + module-local `pillars/` (doctrine, lazy). There is no repo-wide `docs/pillars/`. Worth declaring at ≥2 genuine bounded contexts; a single-context app stays flat under `docs/features/`.
116
+ - `docs/modules/{m}/`: Vertical bounded contexts, **declared** (not inferred from layout) and tied to code by their `docs/routing.md` patterns (the Module column groups routes into modules). Each owns `features/` + module-local `pillars/` (doctrine, lazy). There is no repo-wide `docs/pillars/`. Worth declaring at ≥2 genuine bounded contexts; a single-context app stays flat under `docs/features/`.
115
117
  - `docs/operations/`: How-to procedures for setup, development, and deployment. Update when workflows change.
116
118
  - `docs/history/plans/`: Historical. Must have `Status:` field. Never modify after completion.
117
119
  - `docs/history/changelog/`: Historical. Append-only.
@@ -127,28 +129,64 @@ Plan (Status: Draft) → Implementation → Feature Doc or Architecture Update
127
129
 
128
130
  ---
129
131
 
130
- ## 3. Feature Ownership Frontmatter
132
+ ## 2.5 docs/routing.md (Code-Path Ownership Map)
131
133
 
132
- Use for: every feature doc in `docs/features/`. Declares which source files this doc is authoritative for.
134
+ Use for: the single hand-maintained map from code paths (and keywords) to the canonical doc + module. This is the source of truth for code ownership — feature docs carry no ownership frontmatter. Scaffold it once any feature doc owns code.
135
+
136
+ ```
137
+ # Routing
138
+
139
+ The single map from code paths (and keywords) to the doc that is canonical for them, and the module each belongs to. The source of truth for code-path ownership — feature docs carry no ownership frontmatter. Read this before touching unfamiliar code, then read the mapped doc.
140
+
141
+ > **One canonical doc per path.** When two patterns match the same path, the **narrower** pattern wins; an equal-specificity overlap is a conflict — resolve it before merging. Hand-maintained — there is no generator. Keep it in sync when you add/move/delete a doc or move/rename owned source.
142
+
143
+ ## File-Pattern Routes
144
+
145
+ | Pattern | Module | Canonical Doc | Memory |
146
+ | ------- | ------ | ------------- | ------ |
147
+ | `src/auth/**` | auth | features/login.md | memory/main.md |
148
+ | `src/billing/**` | billing | modules/billing/features/invoicing.md | — |
149
+
150
+ - **Pattern** — the narrowest glob covering the files the doc is canonical for. A doc may have several rows.
151
+ - **Module** — the declared module the pattern belongs to, or `—` if the repo is flat (no module declared). Grouping rows by this column is how a module is tied to code.
152
+ - **Canonical Doc** — the one doc to read before changing matching files (`features/…` when flat, `modules/{m}/features/…` when the module is declared).
153
+ - **Memory** — the `docs/memory/` file with domain knowledge for this area, or `—`.
154
+
155
+ ## Keyword Routes
156
+
157
+ | Keyword / topic | Canonical Doc |
158
+ | --------------- | ------------- |
159
+ | auth, login, SSO, refresh | features/login.md |
160
+
161
+ ## Top-Level Folders
162
+
163
+ | Folder | Purpose | Doc |
164
+ | ------ | ------- | --- |
165
+ | `src/` | {what lives here} | {doc} |
166
+
167
+ ## How to Add a Route
168
+
169
+ 1. Add/extend a **File-Pattern Routes** row — narrowest pattern that doesn't overlap an existing row at equal specificity; set its Module (or `—`).
170
+ 2. Add keyword row(s) for discoverability.
171
+ 3. When you move/rename owned source, update the matching pattern(s) here — this map is hand-maintained.
172
+ ```
173
+
174
+ ---
175
+
176
+ ## 3. Code-Path Ownership & Anchors
177
+
178
+ **Ownership.** A feature doc is the canonical reference for the code paths mapped to it in `docs/routing.md` (File-Pattern Routes). Feature docs declare ownership through their routing row(s), **not** through frontmatter. To find what a doc owns, read its rows in `routing.md`; to find the doc for a path, match the path against the patterns there (narrower wins). See the **routing-map derivation** in `SKILL.md` for turning code into routing rows.
179
+
180
+ **Anchors (optional — the only frontmatter a living doc may carry).** A doc may carry an `anchors:` block — a qmd drift tripwire, orthogonal to ownership:
133
181
 
134
182
  ```yaml
135
183
  ---
136
- owns:
137
- - src/feature-name/**
138
- - app/feature-name/**
139
- touches:
140
- - src/shared/utils/feature-helper.js
141
- depends_on:
142
- - docs/architecture/system-design.md
143
184
  anchors:
144
185
  - "qmd query: feature-name persistence shape"
145
186
  ---
146
187
  ```
147
188
 
148
- - `owns`: Glob patterns for files this feature doc is the canonical reference for
149
- - `touches`: Files this feature interacts with but doesn't own
150
- - `depends_on`: Other docs that must be read for full context
151
- - `anchors` (optional): A list of qmd queries (or `#docid`s) that re-resolve to the code/facts this doc abstracts as they move; anchors are retrieval context plus a drift tripwire, never a contract — an anchor that returns nothing IS the drift signal, nothing auto-rewrites from an anchor result, and the doc's prose stays the human-owned abstraction. They detect **doc-area drift** (the subject moving or vanishing from the corpus), not a pure code rename — the query also matches the doc's own prose, so a rename that leaves the text unchanged won't shift the result; code-symbol drift is the maintenance named-referent check's job, and anchors complement it rather than replace it. Resolved via `qmd query --format json -c <collection>` against this repo's collections; absent qmd ⇒ anchors are inert (no error). Never required on any doc. The feature template ships the exemplar, but `anchors:` may appear on any living doc the maintenance anchor-drift check globs — `docs/features/`, `docs/architecture/`, and `docs/operations/` — so the convention and the check stay one mental model.
189
+ `anchors` is a list of qmd queries (or `#docid`s) that re-resolve to the code/facts this doc abstracts as they move; anchors are retrieval context plus a drift tripwire, never a contract — an anchor that returns nothing IS the drift signal, nothing auto-rewrites from an anchor result, and the doc's prose stays the human-owned abstraction. They detect **doc-area drift** (the subject moving or vanishing from the corpus), not a pure code rename — the query also matches the doc's own prose, so a rename that leaves the text unchanged won't shift the result; code-symbol drift is the maintenance named-referent check's job, and anchors complement it rather than replace it. Resolved via `qmd query --format json -c <collection>` against this repo's collections; absent qmd ⇒ anchors are inert (no error). Never required on any doc. `anchors:` may appear on any living doc the maintenance anchor-drift check globs — `docs/features/`, `docs/architecture/`, and `docs/operations/`.
152
190
 
153
191
  ---
154
192
 
@@ -294,17 +332,13 @@ The four research-derived sections (**Affected Modules**, **Conventions to Follo
294
332
 
295
333
  ```yaml
296
334
  ---
297
- owns:
298
- - src/feature-name/** # projected at Draft, confirmed at Active
299
- touches:
300
- - src/shared/state/feature.js
301
- depends_on:
302
- - docs/features/related-feature.md
303
- anchors: # optional — see §3 frontmatter reference
335
+ anchors: # optional — the only frontmatter a feature doc may carry; see §3
304
336
  - "qmd query: wire envelope invariants"
305
337
  ---
306
338
  ```
307
339
 
340
+ > This doc carries **no** ownership frontmatter. Declare the code paths it owns as File-Pattern Routes row(s) in `docs/routing.md` (§2.5) — projected at Draft, confirmed at Active.
341
+
308
342
  ```
309
343
  # {Feature Name}
310
344
 
@@ -351,7 +385,7 @@ High-level shape of the solution. ASCII diagram if it helps. Implementation spec
351
385
 
352
386
  ## Ownership Conflicts
353
387
 
354
- (From spec-mode research) Existing feature docs whose `owns` or `touches` overlap with the projected scope. Resolve per row before the plan starts — leave nothing unresolved.
388
+ (From spec-mode research) Existing feature docs whose `docs/routing.md` patterns overlap with the projected scope. Resolve per row before the plan starts — leave nothing unresolved.
355
389
 
356
390
  | Conflicting doc | Overlapping path(s) | Resolution |
357
391
  |-----------------|---------------------|------------|
@@ -431,7 +465,7 @@ Sections fill in across the feature's lifecycle. No template swap — they accum
431
465
  | --- | --- | --- |
432
466
  | Status: Draft (design) | Goal, Goals & Non-Goals, Background, Approach, Open Questions, Risks | User interview |
433
467
  | Status: Draft (research) | Affected Modules, Conventions to Follow, Current Behavior, Ownership Conflicts | spec-mode agent |
434
- | Status: Draft → Active (implementation lands) | Architecture, Key Functions, State, Redux, Files; frontmatter `owns`/`touches` confirmed against real code | Main agent (from actual code) |
468
+ | Status: Draft → Active (implementation lands) | Architecture, Key Functions, State, Redux, Files; `docs/routing.md` row(s) confirmed against real code | Main agent (from actual code) |
435
469
 
436
470
  Resolved Open Questions can be summarized into Background; unresolved ones stay visible.
437
471
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nurix/etna",
3
- "version": "0.18.9",
3
+ "version": "0.18.10",
4
4
  "description": "Bootstrap a project with a Nurix harness — copies the harness's CLAUDE.md, skills, agents, rules, and hooks directly into the project from a bundled payload (no marketplace fetch, no network).",
5
5
  "type": "module",
6
6
  "bin": {