@nurix/etna 0.16.0 → 0.17.0

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 (38) hide show
  1. package/data/harness-index.json +1 -1
  2. package/data/harnesses/code/CLAUDE.md +5 -8
  3. package/data/harnesses/code/agents/change-review.md +13 -14
  4. package/data/harnesses/code/agents/harness-manager.md +14 -26
  5. package/data/harnesses/code/agents/maintenance.md +10 -18
  6. package/data/harnesses/code/harness.json +3 -3
  7. package/data/harnesses/code/hooks/hooks.json +2 -2
  8. package/data/harnesses/code/hooks/lib/{redact.js → redact.mjs} +2 -4
  9. package/data/harnesses/{code-fable/hooks/prompt-recall.js → code/hooks/prompt-recall.mjs} +5 -7
  10. package/data/harnesses/{code-fable/hooks/session-reflect.js → code/hooks/session-reflect.mjs} +9 -7
  11. package/data/harnesses/code/rules/general.md +23 -40
  12. package/data/harnesses/code/rules/nomenclature.md +0 -4
  13. package/data/harnesses/code/rules/typescript.md +19 -0
  14. package/data/harnesses/code/skills/boundary/SKILL.md +53 -239
  15. package/data/harnesses/code/skills/brainstorm/harvest.md +2 -2
  16. package/data/harnesses/code/skills/documentation/SKILL.md +2 -4
  17. package/data/harnesses/code/skills/documentation/references/templates.md +12 -89
  18. package/data/harnesses/code-fable/CLAUDE.md +5 -8
  19. package/data/harnesses/code-fable/agents/change-review.md +13 -14
  20. package/data/harnesses/code-fable/agents/harness-manager.md +14 -26
  21. package/data/harnesses/code-fable/agents/maintenance.md +10 -18
  22. package/data/harnesses/code-fable/harness.json +3 -3
  23. package/data/harnesses/code-fable/hooks/hooks.json +2 -2
  24. package/data/harnesses/code-fable/hooks/lib/{redact.js → redact.mjs} +2 -4
  25. package/data/harnesses/{code/hooks/prompt-recall.js → code-fable/hooks/prompt-recall.mjs} +5 -7
  26. package/data/harnesses/{code/hooks/session-reflect.js → code-fable/hooks/session-reflect.mjs} +9 -7
  27. package/data/harnesses/code-fable/rules/general.md +23 -40
  28. package/data/harnesses/code-fable/rules/nomenclature.md +0 -4
  29. package/data/harnesses/code-fable/rules/typescript.md +19 -0
  30. package/data/harnesses/code-fable/skills/boundary/SKILL.md +53 -239
  31. package/data/harnesses/code-fable/skills/brainstorm/harvest.md +2 -2
  32. package/data/harnesses/code-fable/skills/documentation/SKILL.md +2 -4
  33. package/data/harnesses/code-fable/skills/documentation/references/templates.md +12 -89
  34. package/data/harnesses/discover/harness.json +1 -1
  35. package/data/harnesses/discover/rules/evaluation.md +13 -1
  36. package/data/harnesses/discover/rules/ingestion.md +15 -0
  37. package/data/harnesses/discover/rules/tradecraft.md +13 -0
  38. package/package.json +1 -1
@@ -1,262 +1,76 @@
1
1
  ---
2
2
  name: boundary
3
- description: The single home for a repo's typed application boundaries — the cross-cutting contracts (db-schema, wire envelope, store shape, auth, tenancy, event schemas, edge bindings, …) where editing one module silently breaks another. One skill, four modes — `generate` (baseline all boundaries from the detected stack + IA), `create` (add/update one boundary), `check` (pre-implementation: does this plan touch a boundary? severity-ranked impact), `init` (reconcile: ensure files exist, scan live code for violations + drift, backfill new catalog types). All four read one shared knowledge root, `references/boundary-taxonomy.md`, so they can never drift apart. Triggers on "application boundary", "baseline boundaries", "map boundaries", "generate boundaries", "create a boundary", "introspect", "check this plan", "impact analysis", "what could break", "scan for boundary violations", "boundary drift", "/boundary".
3
+ description: Boundary diagnostic for implementation plans. Given a plan file, reads the source files the plan touches, identifies the application boundaries they participate in — the cross-cutting contracts (db schema, wire envelope, auth, events, env/config, …) where editing one side silently breaks the other — and reports whether the planned changes would violate any of them, severity-ranked, with suggested plan amendments. Read-only; the report lands in chat. Can also run against a diff or named code area instead of a plan. Triggers on "boundary check", "check this plan", "what could break", "impact analysis", "/boundary".
4
4
  ---
5
5
 
6
- # Application Boundary Skill
6
+ # Boundary Diagnostic
7
7
 
8
- The one place a repo's **typed application boundaries** are produced, checked, and
9
- maintained. A boundary is a horizontal cross-cutting contract — an *edge* between
10
- modules, layers, services, or deploy units — where editing one side silently
11
- breaks another. They live as one file per boundary in `docs/boundaries/`.
8
+ You diagnose whether a plan's changes would break an application boundary.
12
9
 
13
- This skill merges what used to be three components — `boundary-mapper` (produce),
14
- `introspect` (pre-impl check), `contract-monitor` (post-impl scan) — into one
15
- skill with four modes. The reason they're one skill: **all four share a single
16
- knowledge root** — [`references/boundary-taxonomy.md`](references/boundary-taxonomy.md),
17
- the exhaustive catalog of *what an application boundary is* and *which kinds
18
- exist* (≈170 types across persistence, wire/API, frontend, auth/tenancy,
19
- async/messaging, config/build, runtime/infra). Three separate components meant
20
- three copies of that mental model that drifted apart. One skill, one catalog,
21
- zero drift.
10
+ A boundary is a contract between two pieces of code (or code and infra) that
11
+ share an assumption with **no compile-time link** between them: the column a raw
12
+ SQL string names, the JSON envelope a client unwraps, the event string a
13
+ dispatcher parses, the env var a deploy script writes. Changing one side ships
14
+ green and breaks the other silently. Your job is to find those edges in the
15
+ plan's path *before* execution.
22
16
 
23
- > **Read [`references/boundary-taxonomy.md`](references/boundary-taxonomy.md)
24
- > first, in every mode.** It carries the boundary-file anatomy, the
25
- > `point`-vs-`transcribe` doc-mode, the technology/domain split, the per-type
26
- > severities, and the safe-change checklists. This SKILL.md only orchestrates the
27
- > four verbs over that knowledge.
17
+ [`references/boundary-taxonomy.md`](references/boundary-taxonomy.md) is the
18
+ catalog of boundary types (~170 across persistence, wire/API, frontend,
19
+ auth/tenancy, async/messaging, config/build, runtime/infra), with per-type
20
+ severities and safe-change checklists. Read it first — it tells you what to
21
+ look for; the code tells you what exists.
28
22
 
29
- ---
30
-
31
- ## Picking a mode
32
-
33
- | You want to… | Mode | Old component |
34
- |---|---|---|
35
- | Baseline a repo — generate every boundary that exists from the stack + IA | **`generate`** | boundary-mapper (baseline) |
36
- | Add or update **one** boundary file | **`create`** | boundary-mapper (create/update) |
37
- | Before coding: does this **plan** touch a boundary? Severity-ranked impact | **`check`** | introspect |
38
- | Reconcile: do files exist? scan **live code** for violations + drift; backfill new catalog types | **`init`** | contract-monitor + drift + catalog-sync |
39
-
40
- If the user's intent is ambiguous, ask which mode. `generate` and `create` are the
41
- same writer at different scope (`generate` = `create` over every detected
42
- boundary).
43
-
44
- ## Execution model — pure skill
45
-
46
- This skill runs **in the main session** — no standing sub-agents. `check` and
47
- `create` are light and always run inline. `generate` and `init` sweep the
48
- codebase; run that sweep inline too. **Only** for an unusually large repo (where
49
- an inline full-codebase sweep would blow the context budget) may you dispatch a
50
- **one-shot scan worker** sub-agent that reads this same taxonomy reference and
51
- returns structured findings — the knowledge still lives in exactly one place.
52
- Default to inline; reach for a worker only when the repo's size forces it.
53
-
54
- ## Before any mode
55
-
56
- 1. Read [`references/boundary-taxonomy.md`](references/boundary-taxonomy.md) — the
57
- boundary types, doc-modes, default severities, and safe-change checklists for
58
- the stack you're about to touch.
59
- 2. If `docs/memory/boundary.md` exists, read it for project-specific
60
- boundary exceptions, known violations the user chose not to fix, where the IA
61
- model actually lives, and stack quirks that change a doc-mode.
62
- 3. If `docs/routing.md` exists, read it for module-ownership context.
63
-
64
- ---
65
-
66
- ## Mode: `generate` (baseline)
67
-
68
- No `docs/boundaries/` yet (or a from-scratch re-baseline). Detect the stack + IA,
69
- instantiate one file per boundary that actually exists.
70
-
71
- 1. **Detect the stack** — read `package.json` (deps), the lockfile, and skim the
72
- source tree. Map detected technologies to their boundary types via the
73
- taxonomy. (Detect the package manager from the lockfile; don't assume.)
74
- 2. **Detect the information architecture** — read `docs/architecture/`
75
- (domain-model, ADRs), doctrine in any `docs/modules/*/pillars/`, and the
76
- entity/contract definitions (a `@org/contracts` package, `schema.ts`,
77
- `models.py`). The IA entity model is the flagship `domain` boundary
78
- (`information-architecture`).
79
- 3. **For each boundary the repo exhibits**, write one file to `docs/boundaries/`
80
- using the boundary-file anatomy. Decide `point` vs `transcribe` per the
81
- taxonomy: `point` boundaries get a `file:line` pointer + invariants +
82
- checklist (never a transcribed copy — it rots); `transcribe` boundaries (the
83
- composed store tree, the response envelope, the IA topology, tenancy) get the
84
- contract canonically in the file.
85
- - **Greenfield branch — contract decided, no code yet.** If the repo is
86
- pre-code (ADRs/domain-model decide the contract but the source module isn't
87
- scaffolded), a `point` boundary has no `file:line` to mirror. Don't skip it
88
- and don't fabricate a pointer — per the taxonomy's *Greenfield / pre-code
89
- boundaries*, emit it as **conventions-with-planned-pointer**: record the
90
- decided conventions inline, carry a `planned <path>` pointer, mark it `point*`
91
- (a pre-code `transcribe` source is `transcribe*`), and make the last
92
- safe-change item "replace the planned pointer with the real `file:line` once
93
- code lands." Link any item that hinges on an unresolved decision to its
94
- open-question/ADR.
95
- 4. **Set severity** from the taxonomy default, adjusted by the concrete repo +
96
- project memory. Severity is load-bearing — it drives `check` review depth and
97
- `init` scan priority.
98
- 5. **Name the bounding code units** (paths / package names) in every `Bounds`
99
- line. The distinct vertices named across all `Bounds` lines are the
100
- **module-discovery feed** `harness-manager` reads to propose modules — name
101
- them precisely.
102
- 6. **Write `docs/boundaries/README.md`** as the index per the taxonomy's index
103
- spec: a table with a **Doc-mode column**
104
- (`| Boundary | Type | Severity | Doc-mode | Bounds (summary) |`), then the
105
- standing blocks — **Active technology packs**, **Folds applied** (which catalog
106
- types collapsed into which file — surface the per-entry fold-notes as a ledger),
107
- and **Skipped** (types omitted + one-line reason each). Add the `point*`/`transcribe*`
108
- footnote if any boundary is pre-code.
109
- 7. **Don't invent boundaries the repo doesn't have.** Only instantiate types the
110
- detected stack/IA actually exhibits; `log()` what you skipped and why.
111
-
112
- Write only under `docs/boundaries/` and `docs/memory/boundary.md`.
113
- Read-only on production code.
23
+ ## Run
114
24
 
115
- ## Mode: `create` (targeted)
25
+ **Input:** a plan path (given, or the newest in `docs/history/plans/`) — or a
26
+ diff / named code area for non-plan work. Everything below is identical either
27
+ way; a diff's hunks stand in for the plan's steps.
116
28
 
117
- Add or update a single boundary file (e.g. a new contract surfaced by `check`, or
118
- a boundary the author asks for by name).
29
+ 1. **Build the touch list.** Parse the plan's Proposed Changes: files to be
30
+ created or modified, entities/state added or changed, API changes, anything
31
+ the author flags as a cross-module contract. Note missing subsections.
119
32
 
120
- 1. Identify the boundary type from the taxonomy; confirm the repo exhibits it.
121
- 2. Write/update the one file with the full anatomy (Bounds, Shape, Invariants,
122
- Blast radius, Safe-change checklist), `point` or `transcribe` per the taxonomy.
123
- 3. Update `docs/boundaries/README.md` (add/refresh the index row).
124
- 4. For an **update** that fixes drift (the `maintenance` agent flags a boundary
125
- file drifted from its source): re-read the source, refresh the `Shape` pointer
126
- or transcription, leave invariants/checklist intact unless they changed.
33
+ 2. **Identify the boundaries in the touched code.** Read each touched file (and
34
+ its immediate imports). Against the taxonomy, list the contracts this code
35
+ participates in — the schema it queries, the envelope it emits, the events
36
+ it publishes or parses, the auth checks it sits behind, the env it reads.
127
37
 
128
- ## Mode: `check` (pre-implementation)
38
+ 3. **Trace the other side.** A boundary has two sides; the danger lives on the
39
+ one the plan *doesn't* mention. For each contract, grep the shared name or
40
+ shape across the repo — the column name in other SQL strings, the response
41
+ field in client unwrappers, the event kind in subscribers, the route in
42
+ fetch calls and scripts, the env key in deploy tooling. Record consumers as
43
+ `file:line`.
129
44
 
130
- Read-only. Intersect a plan's proposed changes with the documented boundaries and
131
- surface cascading risk *before* coding. (This is the old `introspect`.)
45
+ 4. **Judge each intersection.** Does the planned change alter a shape a traced
46
+ consumer depends on, break an invariant the code establishes (append-only
47
+ vocabularies, idempotency keys, fail-closed checks, ordering guarantees), or
48
+ add a new cross-module edge? Severity:
49
+ - **CRITICAL** — can corrupt persisted data, or open an auth/money path.
50
+ - **HIGH** — silent cross-module breakage that would ship green.
51
+ - **MEDIUM** — drift-prone coupling (string-matched, duplicated constants).
52
+ - **LOW** — smell. Loud, immediately-visible breakage caps at HIGH.
132
53
 
133
- **Inputs.** Plan path (user-provided; else newest in `docs/history/plans/`). Every
134
- file in `docs/boundaries/` is mandatory input — if the folder is missing/empty,
135
- stop and tell the user to run `generate` first. Source files read on demand to
136
- verify — never guess from plan text alone.
137
-
138
- 1. **Load.** Resolve + read the plan; confirm it has a `Status:` (warn if
139
- `Complete`/`Abandoned`). Read every boundary file; parse the
140
- `[BOUNDARY: type · severity]` header + Bounds / Shape / Invariants / Blast
141
- radius / Safe-change checklist. Severity sets review depth.
142
- 2. **Parse proposed changes.** The plan template's **Proposed Changes**
143
- subsections are load-bearing: New Files / Modified Files (check against the
144
- modules each boundary **Bounds** and any `Shape` `file:line`) · New Entities /
145
- State (vs `information-architecture` + `db-schema`) · API Changes (vs
146
- `wire-response-envelope` / `rest-endpoint-shape` / `graphql-schema`) ·
147
- Cross-Module Contracts Affected (the author's own admission — start there,
148
- then verify). Note any missing subsection.
149
- 3. **Analyze each boundary × change pair** for: **Bounds overlap** (touches a
150
- bounded module or a `Shape` pointer), **Invariant overlap** (introduces a
151
- shape the invariants prohibit — raw literal where a shared constant is
152
- required, entity type not in the canonical array, persisted field without
153
- fallback), **Shape overlap** (modifies the canonical Shape). Read the actual
154
- source to verify any plausible intersection.
155
- 4. **Assign severity.** Anchor to the boundary's own severity (the floor),
156
- adjust by the concrete change. Critical = silent data loss / corrupted
157
- persistence / broken cross-entity refs; High = stale state / broken lookups /
158
- schema selectors without fallbacks; Medium = likely-to-drift string-coupling;
159
- Low = code smell.
160
- 5. **Report** (in chat — never written to disk):
54
+ 5. **Report in chat:**
161
55
 
162
56
  ```
163
- # Application Boundary — check — {plan filename}
164
-
165
- Plan: {path}
166
- Boundaries: {N} files evaluated
167
- Intersections: {N} ({critical}/{high}/{medium}/{low})
57
+ # Boundary check — {plan}
168
58
 
169
- ## Violations
170
- | # | Boundary | Risk | Severity | Plan step |
59
+ Touched files read: {N} · Boundaries identified: {N}
60
+ Violations: {N} ({critical}/{high}/{medium}/{low})
171
61
 
172
- ## Suggested Plan Additions
173
- - Violation #1 → add step X to Implementation Steps / Done Criteria …
62
+ | # | Boundary | Planned change | Other side (file:line) | Severity |
174
63
 
175
- ## Missing Subsections
176
- ## New Cross-Module Contracts Detected
177
- {describe the proposed boundary (type, Bounds, Shape, suggested severity) and
178
- recommend running `create` to formalize it — do not write the file from check}
64
+ ## Suggested plan amendments
65
+ ## Missing plan subsections
179
66
  ```
180
67
 
181
- The severity-ranked table is the load-bearing output. Suggestions are advisory —
182
- the user folds them back into the plan; **`check` never edits the plan or code.**
183
-
184
- ## Mode: `init` (reconcile — ensure, scan, backfill)
185
-
186
- Ensure boundaries are initialized and current. Three jobs in one pass:
187
-
188
- 1. **Ensure exist.** If `docs/boundaries/` is missing/empty → this is really a
189
- baseline; run `generate` instead and stop.
190
- 2. **Scan live code for violations** (the old `contract-monitor`). For each
191
- boundary file, parse its header + invariants, then scan the codebase for
192
- violations of *that* boundary. Categories: **unregistered entity types**
193
- (strings used as entity-type ids not in the canonical array) · **string-coupled
194
- constants** (raw literals where a shared constant import is required) ·
195
- **cross-entity references without propagation** (storing entity A's
196
- slug/name/id by value in B with no documented propagation) · **schema
197
- mismatches** (selectors hitting persisted fields without a fallback default) ·
198
- **undocumented endpoints** (routes with no feature-doc / `api` boundary entry).
199
- Verify by reading actual source — never guess.
200
- 3. **Detect drift + backfill the catalog.** (a) Flag any boundary file whose
201
- `Shape` has drifted from its source (refresh it via `create`/update). (b)
202
- Compare the taxonomy's boundary *types* against what the repo now exhibits —
203
- if the repo gained a technology (or the catalog gained a type) that the repo
204
- exhibits but `docs/boundaries/` lacks, surface it and offer to `generate` that
205
- one boundary.
206
-
207
- **Act on violations.** Mechanical fix (missing constant import, missing fallback,
208
- missing canonical-array entry) → fix directly with an Edit. Design-decision fix
209
- (new entity-type registration, new propagation mechanism, schema migration) →
210
- append to `docs/history/backlog.md` as P0/P1 with the specific boundary + bounded
211
- modules. Pre-existing exception (in `docs/memory/boundary.md`) → skip
212
- silently.
213
-
214
- **Report** a table `| # | Boundary | Violation | Location | Action taken |`, then
215
- update `docs/memory/boundary.md` with scan date, per-boundary
216
- violation counts, items fixed / backlogged, new exceptions, and any
217
- newly-exhibited boundary types backfilled.
218
-
219
- ---
220
-
221
68
  ## Rules
222
69
 
223
- - **One knowledge root.** Every mode reads `references/boundary-taxonomy.md`.
224
- Extend the catalog there, never inline a divergent copy in a mode.
225
- - **`check` is read-only** — never edits the plan, source, boundaries, or memory.
226
- The other modes write only under `docs/boundaries/`,
227
- `docs/memory/boundary.md`, and (for `init` mechanical fixes) the
228
- specific violating source line. Never touch frozen records
229
- (`docs/history/plans/`, `docs/history/changelog/`) or feature docs.
230
- - **Verify against source.** Never report a violation or intersection from text
231
- alone — read the files the plan/boundary names.
232
- - **One file per boundary.** Don't bundle unrelated boundaries.
233
- - **Severity is load-bearing.** It feeds `check` review depth + `init` priority.
234
- Default from the taxonomy; adjust from the repo + memory.
235
- - **Name the bounding code units** in every `Bounds` line — they're the
236
- module-discovery feed `harness-manager` reads. A workspace is *not* a module.
237
- - **Don't invent boundaries the repo doesn't have.** Only instantiate exhibited
238
- types; `log()` skips. **A clean report is valid** — empty violations/intersections
239
- means say so, don't pad.
240
- - **Docs never outrank code.** For `point` boundaries, mirror with `file:line`;
241
- don't fork the shape. `file:line` stays primary for point-mode boundaries; an
242
- `anchors:` query (see the documentation skill's frontmatter reference) MAY
243
- supplement it for refactor-resilience — optional and additive, it re-resolves
244
- the shape when the line moves, never replaces the pointer.
245
- - **Be specific** — file paths, line numbers, boundary names, the exact violating
246
- string or code shape.
247
-
248
- ## Strategy memory
249
-
250
- After a run you may append to `docs/memory/boundary.md` (git-tracked):
251
- project-specific boundary exceptions, where the IA model actually lives in this
252
- repo, stack quirks that change a doc-mode, recurring drift/violation zones,
253
- historical violation counts. Never user preferences (those are `~/.claude/`);
254
- never a transcription of a boundary's content (that's the boundary file). Date
255
- each entry `## YYYY-MM-DD — {topic}`.
256
-
257
- ## Output locations
258
-
259
- - `generate`/`create`/`init` write boundary files to `docs/boundaries/` + the
260
- index `docs/boundaries/README.md`; memory to `docs/memory/boundary.md`.
261
- - `check` returns its report in chat — never written to disk; the user folds
262
- insights back into the plan.
70
+ - **Read-only.** You never edit the plan, the code, or any doc. The user folds
71
+ your amendments into the plan.
72
+ - **Verify in source.** Never flag from plan text alone — read both sides of
73
+ every boundary you report, and cite both as `file:line`.
74
+ - **No consumer, no finding.** An intersection with no traced other side isn't
75
+ a violation; at most note it as a new edge the plan introduces.
76
+ - **A clean report is valid.** Zero violations means say so — don't pad.
@@ -4,12 +4,12 @@ Harvest is **optional and offered, never assumed**. By default the session folde
4
4
 
5
5
  ## Routing
6
6
 
7
- The harvest is a structured diff between the session pillars and the live docs, routed by scope: module-local findings → `docs/modules/{m}/pillars/`, cross-module → `docs/architecture/`, IA/contract changes → `docs/boundaries/` (via the `boundary` skill), backlog → `docs/history/`.
7
+ The harvest is a structured diff between the session pillars and the live docs, routed by scope: module-local findings → `docs/modules/{m}/pillars/`, cross-module + IA/contract changes → `docs/architecture/`, backlog → `docs/history/`.
8
8
 
9
9
  | Session source | Destination |
10
10
  |---|---|
11
11
  | `thesis.md` narrative | `docs/history/plans/YYYY-MM-DD-{slug}.md` (Status: Draft, `documentation` skill §8 Plan template) |
12
- | `domain-model.md` | `docs/architecture/domain-model.md`; if it changes the IA or a cross-cutting contract, **flag for the `boundary` skill (`create`)** — don't hand-write boundary files |
12
+ | `domain-model.md` | `docs/architecture/domain-model.md`; if it changes the IA or a cross-cutting contract, note the contract change there — the `boundary` skill will pick it up from source at the next plan check |
13
13
  | Decisions spanning 2+ modules | one ADR per cohesive theme → `docs/architecture/adr/ADR-NNN-{slug}.md`, authored to the **`documentation` skill §10 ADR template** (frontmatter `status:` is the lifecycle source of truth — no body Status line; required sections Decision/Context/Consequences); rejected alternatives → the ADR's **Options Considered** table |
14
14
  | Module-local decisions / doctrine / glossary / rejected | `docs/modules/{m}/pillars/{decisions,doctrine,glossary,rejected}.md` |
15
15
  | Cross-module doctrine / glossary | `docs/architecture/domain-model.md` / `docs/architecture/glossary.md` |
@@ -1,6 +1,6 @@
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) provide the generic boundary-file template (typed-boundary *generation* is the `boundary` skill), (6) record an architecture decision (ADR), (7) create or update the project root README, (8) create or update a plan, (9) derive ownership frontmatter (`owns`/`touches`/`depends_on`) from code, (10) scaffold a standard doc (README, structure.md, CHANGELOG, backlog, memory) from its template, or (11) 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 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".
4
4
  ---
5
5
 
6
6
  # Technical Documentation Skill
@@ -30,8 +30,6 @@ User request
30
30
  │
31
31
  ├─ "Add to protected files" ───────▶ Protected Files Template
32
32
  │
33
- ├─ "Create/update a boundary" ─────▶ boundary skill (this skill holds only the boundary-file template)
34
- │
35
33
  ├─ "Record architecture decision" ─▶ ADR Template
36
34
  │
37
35
  ├─ "Create/update root README" ────▶ Project Root README Template
@@ -122,6 +120,6 @@ For docs that don't match templates:
122
120
 
123
121
  | File | Use For |
124
122
  |------|---------|
125
- | `references/templates.md` | docs/README.md, structure.md, frontmatter, scaffolds (CHANGELOG, backlog, memory), boundary-file, feature, changelog, plan, protected files, ADR, project root README templates |
123
+ | `references/templates.md` | docs/README.md, structure.md, frontmatter, scaffolds (CHANGELOG, backlog, memory), feature, changelog, plan, protected files, ADR, project root README templates |
126
124
  | `references/style-guide.md` | Writing rules, formatting conventions |
127
125
  | `references/examples.md` | Good vs bad documentation examples |
@@ -93,7 +93,6 @@ Each topic has one canonical location. Read from here, not from plans or changel
93
93
  | ----- | --------- | --------- |
94
94
  | System architecture + steering | `docs/architecture/` | domain-model, glossary, non-goals, references, adr/ |
95
95
  | Feature behavior | `docs/features/` (or `docs/modules/{m}/features/`) | {key files} |
96
- | Cross-module contracts | `docs/boundaries/` | one file per boundary (maintained by the `boundary` skill) |
97
96
  | Declared modules (bounded contexts) | `docs/modules/{m}/` | `features/` + `pillars/` |
98
97
  | Setup & development | `docs/operations/` | {key files} |
99
98
  | Historical plans | `docs/history/plans/` | YYYY-MM-DD-name.md |
@@ -112,7 +111,6 @@ Plan (Status: Draft) → Implementation → Feature Doc or Architecture Update
112
111
 
113
112
  - `docs/features/`: Living reference for implemented features. Each spec includes YAML frontmatter with `owns`, `touches`, `depends_on` fields declaring code ownership.
114
113
  - `docs/architecture/`: System-wide patterns and the cross-module steering layer (domain model, glossary, non-goals, references, ADRs). Update when cross-cutting concerns change.
115
- - `docs/boundaries/`: Horizontal typed application boundaries — one file per cross-module contract. Generated/maintained by the `boundary` skill; read before touching a shape it defines.
116
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/`.
117
115
  - `docs/operations/`: How-to procedures for setup, development, and deployment. Update when workflows change.
118
116
  - `docs/history/plans/`: Historical. Must have `Status:` field. Never modify after completion.
@@ -150,7 +148,7 @@ anchors:
150
148
  - `owns`: Glob patterns for files this feature doc is the canonical reference for
151
149
  - `touches`: Files this feature interacts with but doesn't own
152
150
  - `depends_on`: Other docs that must be read for full context
153
- - `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 and boundary templates ship the exemplar, but `anchors:` may appear on any living doc the maintenance anchor-drift check globs — `docs/features/`, `docs/boundaries/`, `docs/architecture/`, and `docs/operations/` — so the convention and the check stay one mental model.
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.
154
152
 
155
153
  ---
156
154
 
@@ -243,7 +241,7 @@ description: Shared knowledge accumulated across agent sessions. All agents shou
243
241
  ## Documentation Baseline
244
242
 
245
243
  - **Baselined:** {today}
246
- - **Structure:** v{harness-version} (architecture, features, operations, history, memory; + boundaries/, modules/, tests/ when present)
244
+ - **Structure:** v{harness-version} (architecture, features, operations, history, memory; + modules/, tests/ when present)
247
245
  - **Spec version:** v{harness-version}
248
246
  <!-- v{harness-version} resolves to the installed design epoch — read it from `.claude/harness.json` (`epoch`) / `docs/structure.md` frontmatter (`harness-version`); never hardcode a literal version here. -->
249
247
 
@@ -284,86 +282,11 @@ Append entries below, oldest at bottom. Format:
284
282
  Memory file initialized during documentation baseline.
285
283
  ```
286
284
 
287
- > The per-actor memory **inbox** (`docs/memory/inbox/`) is *not* a baseline scaffold — the `session-reflect` hook creates it mechanically on the first reflected session. See **§12 Memory inbox entry** for its format.
285
+ > The per-actor memory **inbox** (`docs/memory/inbox/`) is *not* a baseline scaffold — the `session-reflect` hook creates it mechanically on the first reflected session. See **§11 Memory inbox entry** for its format.
288
286
 
289
287
  ---
290
288
 
291
- ## 5. Boundary File (docs/boundaries/{boundary}.md)
292
-
293
- > **This skill does not generate boundaries.** Typed-boundary generation is owned by the **`boundary`** skill (`generate` mode), which detects the stack + IA and applies its boundary taxonomy (`references/boundary-taxonomy.md`) to emit typed files. The baseline does **not** scaffold `docs/boundaries/` — `/boundary generate` runs right after the baseline ("baseline boundaries"). This section is the generic **boundary-file template** plus the guidance for *recognizing* what deserves a boundary.
294
-
295
- ### What deserves a boundary
296
-
297
- A boundary is a **horizontal, cross-module contract** where the failure is silent and crosses module boundaries — the developer in module A has no reason to know module B will break. No import error, no runtime exception — just wrong behavior.
298
-
299
- Test: "If an agent edits this while working on a single feature, could it silently break something in a different feature?" If yes, it's a boundary.
300
-
301
- **Include:**
302
-
303
- - **Shared state shapes** — Redux store slices, persisted state, global context. Any shape that multiple modules read. Document every key, its type, and what reads it. Call out which slices are persisted and how rehydration handles shape changes (e.g., new fields become `undefined` for existing users).
304
- - **Entity registration checklists** — When adding a new entity/resource type requires touching N files across N modules to avoid silent data loss. List every file and what breaks if skipped.
305
- - **Cross-entity references by value** — When entity A stores entity B's identifier (slug, name, ID) as a plain value with no referential integrity. Document which fields reference what, and that renaming the target never propagates to the source.
306
- - **Format contracts** — When two systems produce identifiers in different formats (e.g., server returns `[a-z0-9]+`, client generates `[a-z0-9_]+`). Document both formats, where each is used, and what breaks on mismatch (e.g., lookup by key returns `undefined`, key-splitting logic produces wrong matches).
307
- - **Cross-module string coupling** — Action types, event names, status enums, or document type strings referenced by raw string literal instead of imported constant. List every file that hard-codes the string and what breaks if the source is renamed.
308
- - **Pipeline ordering dependencies** — Multi-step pipelines where Step N assumes Step N-1 has already written data to shared state. Document the implicit dependency and what happens if ordering changes (silent quality degradation vs. hard failure vs. hang).
309
- - **Completion signal contracts** — When modules communicate via return values, status fields, or Redux state transitions. Document the expected shape/type (e.g., `Promise<boolean>`, status enum values) and what happens if the contract changes (e.g., returning `undefined` instead of `true` causes permanent "failed" status).
310
- - **Host/plugin contracts** — Config objects consumed by a framework/host where some fields are validated and others aren't. Document which fields are unvalidated and what breaks silently if they change.
311
- - **Persistence shape safety** — How the persistence layer handles schema evolution. Document what happens when you add, remove, or rename a field in persisted state (e.g., no migration → stale data, new fields default to `undefined`).
312
-
313
- **Exclude:**
314
-
315
- - Module-internal architecture (well-encapsulated, no cross-module blast radius)
316
- - Authentication/authorization flows (behind adapters, feature code doesn't touch them)
317
- - Hook taxonomies and API reference (useful docs, but not boundaries — they don't cause cascading failures)
318
- - Networking details (WebSocket, HTTP client setup) — unless the event routing has cross-module string coupling
319
- - Feature folder conventions and code style (conventions, not breakage vectors)
320
- - Anything where failure produces an import error, a clear runtime exception, or a visible UI error — those are self-diagnosing and don't need a boundary
321
-
322
- ### How to research a boundary
323
-
324
- When mapping a boundary (the `boundary` skill's `generate`/`create` job — this guidance is shared), investigate:
325
-
326
- 1. **Shared state consumers** — For each Redux slice/context, find all files that read from it. Flag any file reading a slice it doesn't own (cross-module dependency).
327
- 2. **String-coupled actions** — Grep for Redux action type strings referenced as raw strings rather than imported constants. These are invisible breakage points.
328
- 3. **Entity lifecycle** — For each entity type, trace the full lifecycle: creation → change tracking → save payload → API → server. Identify every file that must be touched to support a new entity type.
329
- 4. **Identifier format mismatches** — Compare how identifiers are generated (server vs. client) and how they're used as keys. Look for format divergence.
330
- 5. **Pipeline data dependencies** — For multi-step processes, check what each step reads from shared state and what previous step wrote it. Test: "If I reorder these steps, does it fail loudly or silently?"
331
- 6. **Persistence rehydration** — Check what reconciler is used, whether transforms exist, and what happens to existing users when a persisted shape changes.
332
-
333
- ### Generic boundary-file template
334
-
335
- One file per boundary in `docs/boundaries/`. The `boundary` skill emits typed files using its boundary taxonomy; this is the generic fallback shape.
336
-
337
- ```markdown
338
- ---
339
- anchors: # optional — see §3 frontmatter reference
340
- - "qmd query: store slice rehydration fallback"
341
- ---
342
-
343
- # {Boundary Name}
344
-
345
- [BOUNDARY: {type} · {severity}] <!-- type from the Application Boundary Scale; severity CRITICAL | HIGH | MED | LOW -->
346
-
347
- **Bounds:** {module A} ↔ {module B} <!-- which modules sit on each side -->
348
-
349
- ## Shape
350
- <!-- `transcribe`: a synthesized contract with no single code home (composed store tree, API envelope, the IA entity model, tenancy) — written inline, canonical here.
351
- `point`: a self-locating shape (DB schema, route table) — a `file:line` pointer + invariants. Never copy a self-locating shape; it rots on the next change.
352
- greenfield/pre-code `point` (contract decided, no code yet — e.g. boundary generate after a brainstorm): there's no file:line to point at, so instead (a) record the decided conventions inline here, (b) add a `planned <path>` line naming where the canonical source will land (e.g. `planned packages/api/src/db/schema.ts`), and (c) mark this row `point*` in the README index. Converts to (or gains) a real file:line pointer when the module lands. README index footnote: "* point-mode boundary whose pointer lands at implementation". -->
353
-
354
- ## Invariants
355
- <!-- The rules that must hold across the boundary. -->
356
-
357
- ## Blast radius
358
- <!-- What breaks, and where, if an invariant is violated. -->
359
-
360
- ## Safe-change checklist
361
- <!-- Ordered steps to change this contract without silent breakage. Mark steps that fail silently if skipped. -->
362
- ```
363
-
364
- ---
365
-
366
- ## 6. Feature Documentation (docs/features/{feature}.md)
289
+ ## 5. Feature Documentation (docs/features/{feature}.md)
367
290
 
368
291
  Use for: every feature in `docs/features/`. The same file persists from design (Status: Draft) through implementation to live reference (Status: Active). Sections fill in as the feature matures — no template swap.
369
292
 
@@ -514,7 +437,7 @@ Resolved Open Questions can be summarized into Background; unresolved ones stay
514
437
 
515
438
  ---
516
439
 
517
- ## 7. Changelog
440
+ ## 6. Changelog
518
441
 
519
442
  Use for: recording code changes with function-level detail.
520
443
 
@@ -563,11 +486,11 @@ Brief description of what changed and why.
563
486
 
564
487
  ---
565
488
 
566
- ## 8. Plan (docs/history/plans/YYYY-MM-DD-feature-name.md)
489
+ ## 7. Plan (docs/history/plans/YYYY-MM-DD-feature-name.md)
567
490
 
568
491
  Use for: every implementation plan. Plans are created here directly with `Status: Draft`, flip to `Status: In Progress` when work starts, and freeze at `Status: Complete` or `Status: Abandoned`. Once frozen, never edit — write a new dated plan if scope changes.
569
492
 
570
- The `boundary` skill (`check` mode) parses the **Proposed Changes** sections to check boundary impact. Keep that structure stable — section headings and bullet shape are load-bearing for the parser.
493
+ The `boundary` skill parses the **Proposed Changes** sections to check boundary impact before execution. Keep that structure stable — section headings and bullet shape are load-bearing for the parser.
571
494
 
572
495
  ```
573
496
  # {Feature Name}
@@ -603,7 +526,7 @@ Why this work is happening *now*. Link to the spec for *what* we're building; th
603
526
 
604
527
  ### Cross-Module Contracts Affected
605
528
 
606
- - List which boundaries (from `docs/boundaries/`) this plan touches by name
529
+ - List which cross-cutting contracts this plan touches (db schema, wire envelope, auth, events, env/config, …)
607
530
  - "None" is a valid answer and means the `boundary` check will pass cleanly
608
531
 
609
532
  ## Implementation Steps
@@ -630,7 +553,7 @@ Why this work is happening *now*. Link to the spec for *what* we're building; th
630
553
 
631
554
  ---
632
555
 
633
- ## 9. Protected Files
556
+ ## 8. Protected Files
634
557
 
635
558
  Use for: documenting critical files that need approval before modification.
636
559
 
@@ -675,7 +598,7 @@ path/to/another/file.js
675
598
 
676
599
  ---
677
600
 
678
- ## 10. Architecture Decision Record (ADR)
601
+ ## 9. Architecture Decision Record (ADR)
679
602
 
680
603
  Use for: capturing a single, point-in-time architectural decision with its context, alternatives considered, and consequences. Lives in `docs/architecture/adr/`.
681
604
 
@@ -792,7 +715,7 @@ tags: [adr]
792
715
 
793
716
  ---
794
717
 
795
- ## 11. Project Root README
718
+ ## 10. Project Root README
796
719
 
797
720
  Use for: the human-facing entry point at the repository root (`/README.md`) — what visitors and new contributors land on. Distinct from `docs/README.md` (the agent/doc index — see §1). The two coexist; don't merge them.
798
721
 
@@ -899,7 +822,7 @@ The baseline audit **does** scaffold the project root README when missing. The r
899
822
 
900
823
  ---
901
824
 
902
- ## 12. Memory inbox entry (docs/memory/inbox/{actor}.md)
825
+ ## 11. Memory inbox entry (docs/memory/inbox/{actor}.md)
903
826
 
904
827
  Use for: the capture tier of the knowledge gradient — the durable lessons of each session (corrections, root-caused failures, decisions with rationale, discovered constraints), reflected by the `session-reflect` hook at session end. It is the raw input to distillation: `distiller facts` digests entries into fact-cards and **consumes** them, so the file holds exactly what is undigested.
905
828
 
@@ -3,5 +3,5 @@
3
3
  "name": "discover",
4
4
  "version": "0.1.7",
5
5
  "epoch": null,
6
- "digest": "9617ebd1d5c1"
6
+ "digest": "459be63d0534"
7
7
  }
@@ -34,6 +34,15 @@ published SDK source) that calls the same routes is **independent of both market
34
34
  wrapper**, and corroborates it → promotes. (A legacy/granular route family seen only in a third-party
35
35
  MCP becomes a real finding once the official OSS client calls it too.)
36
36
 
37
+ **Open-core lineage as an absence oracle (independent corroboration of the open/closed seam).** When a
38
+ target is an **open-core product with a closed cloud edition** (a clonable `codebase` lineage repo + a
39
+ closed `session` runtime), a feature **verified ABSENT in the lineage repo** (grep/structure-map) **and
40
+ observed PRESENT in the cloud session** is **two independent lanes agreeing on the *seam*** → promotes the
41
+ open/closed-boundary claim to fact (the cloud-feature value itself stays a direct `session` observation).
42
+ The lineage repo is as useful as an *absence map* (what is NOT in the open floor) as it is a presence map;
43
+ "verified-absent-in-CE + observed-in-cloud" is independent of marketing and of the session alone. (Origin:
44
+ Akeneo — Reference Entities / DAM / Rules / Workflows observed in Serenity + grep-absent in Community Edition.)
45
+
37
46
  **Closed-feedback confidence cap.** When the `community` dimension finds **no first-party feedback
38
47
  loop** (no public issues / roadmap / changelog / forum — feedback funnelled to a gated channel), its
39
48
  user-pain / most-requested-feature claims are **inference-from-changelog only → capped at
@@ -87,7 +96,10 @@ prose, not via a separate `claims.yaml`.)
87
96
  a different, broader, differently-authed API than the published one: list ops the
88
97
  app uses that the public API omits, AND public ops the app never calls — both are
89
98
  findings. If there is NO published API, say so explicitly: "no published API — the
90
- app surface is the only surface" is itself the finding, not an empty section.)
99
+ app surface is the only surface" is itself the finding, not an empty section.
100
+ REQUIRES paired inputs (ingestion §6): the pre-nav in-page tap [session app-own
101
+ paths] + the unauth bundle/route-manifest [published paths]. Missing a lane → the
102
+ diff is un-feedable; say which lane is absent rather than implying overlap.)
91
103
  ## Auth & tenancy model (token type, where it lives, scope expression)
92
104
  ## API-path diff (adaptive, N-way over the runtime sources present) (the seam rule: bundle-declared vs
93
105
  session-observed vs wire-observed. Title it for the sources ACTUALLY run —
@@ -156,6 +156,21 @@ flags**. To keep them consumable instead of triplicated **N times** (a real run
156
156
  > public operations the app never calls, are both findings. The published surface is the integration
157
157
  > story; the runtime surface is the real architecture. When a published API exists, Evaluation emits
158
158
  > this split as a *named* output, not inline prose (evaluation template 3).
159
+ >
160
+ > **Paired inputs make the diff feedable (capture cue).** The split is only emittable if BOTH lanes were
161
+ > captured: when a target has **a published API AND an authed session**, the **pre-nav in-page fetch/XHR
162
+ > tap** (`session` — the app-own paths it actually calls) and the **unauth bundle/route-manifest**
163
+ > (`deployed-client-bundle` — the published paths) are **paired required inputs**. Install the tap *before*
164
+ > navigation (else on-load app calls are missed) and capture the manifest unauth; a session that only
165
+ > screenshots, or a bundle mine with no session, leaves the diff un-feedable. (Origin: Akeneo — 54
166
+ > session-observed app-own paths vs a 124-path unauth `/api/rest/v1` manifest, near-disjoint.)
167
+ >
168
+ > **Host-level dimensions cite, they don't append (seam allowlist).** The shared `api-path-catalog.md`
169
+ > `## source:` allowlist is **bundle / session / wire / distribution** only — the path-contributing
170
+ > runtime lanes. A host-level dimension (`infra-backend-fingerprint`) that wants to cross-reference the
171
+ > catalog does so **from its own `raw/`** (cite hosts/paths by reference), and does **not** append its own
172
+ > `## source:` section to the shared file. (Origin: Akeneo — infra appended a host-level note to the path
173
+ > catalog; benign but blurs the allowlist.)
159
174
 
160
175
  ---
161
176