@nurix/etna 0.20.6 → 0.20.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/data/catalog/rules/testing.md +1 -0
- package/data/harness-index.json +1 -1
- package/data/harnesses/code/agents/lld-mode.md +3 -3
- package/data/harnesses/code/agents/maintenance.md +5 -4
- package/data/harnesses/code/codex/agents/lld-mode.toml +2 -2
- package/data/harnesses/code/codex/agents/maintenance.toml +3 -3
- package/data/harnesses/code/harness.json +2 -2
- package/data/harnesses/code/hooks/awareness.mjs +22 -3
- package/data/harnesses/code/hooks/lib/ownership.mjs +39 -4
- package/data/harnesses/code/rules/testing.md +1 -0
- package/data/harnesses/code/skills/brainstorm/README.md +1 -1
- package/data/harnesses/code/skills/brainstorm/references/doctrine.md +22 -0
- package/data/harnesses/code/skills/brainstorm/references/harvest.md +34 -0
- package/data/harnesses/code/skills/design/SKILL.md +1 -1
- package/data/harnesses/code/skills/design/components/index.md +1 -1
- package/data/harnesses/code/skills/documentation/SKILL.md +2 -2
- package/data/harnesses/code/skills/documentation/references/frontmatter.md +13 -6
- package/data/harnesses/code/skills/documentation/templates/plan.md +4 -1
- package/data/harnesses/code/skills/issue-bridge/SKILL.md +1 -1
- package/data/harnesses/code/skills/testing/SKILL.md +1 -1
- package/data/harnesses/delivery/agents/lld-mode.md +3 -3
- package/data/harnesses/delivery/agents/maintenance.md +5 -4
- package/data/harnesses/delivery/codex/agents/lld-mode.toml +2 -2
- package/data/harnesses/delivery/codex/agents/maintenance.toml +3 -3
- package/data/harnesses/delivery/harness.json +2 -2
- package/data/harnesses/delivery/hooks/generate-ownership-index.mjs +7 -4
- package/data/harnesses/delivery/skills/brainstorm/README.md +1 -1
- package/data/harnesses/delivery/skills/brainstorm/references/doctrine.md +22 -0
- package/data/harnesses/delivery/skills/brainstorm/references/harvest.md +34 -0
- package/data/harnesses/delivery/skills/documentation/SKILL.md +2 -2
- package/data/harnesses/delivery/skills/documentation/references/frontmatter.md +13 -6
- package/data/harnesses/delivery/skills/documentation/templates/plan.md +4 -1
- package/data/harnesses/discover/harness.json +1 -1
- package/data/harnesses/discussion/CLAUDE.md +1 -1
- package/data/harnesses/discussion/harness.json +2 -2
- package/data/harnesses/etna/CLAUDE.md +16 -16
- package/data/harnesses/etna/agents/lld-mode.md +3 -3
- package/data/harnesses/etna/agents/maintenance.md +5 -4
- package/data/harnesses/etna/codex/agents/lld-mode.toml +2 -2
- package/data/harnesses/etna/codex/agents/maintenance.toml +3 -3
- package/data/harnesses/etna/harness.json +2 -2
- package/data/harnesses/etna/hooks/generate-ownership-index.mjs +18 -9
- package/data/harnesses/etna/rules/testing.md +1 -0
- package/data/harnesses/etna/skills/brainstorm/README.md +1 -1
- package/data/harnesses/etna/skills/brainstorm/references/doctrine.md +22 -0
- package/data/harnesses/etna/skills/brainstorm/references/harvest.md +34 -0
- package/data/harnesses/etna/skills/documentation/SKILL.md +2 -2
- package/data/harnesses/etna/skills/documentation/references/frontmatter.md +13 -6
- package/data/harnesses/etna/skills/documentation/templates/plan.md +4 -1
- package/data/harnesses/hr/harness.json +1 -1
- package/data/harnesses/kb-agi/harness.json +1 -1
- package/lib/codex/README.md +1 -1
- package/lib/codex/validate-codex-agents.mjs +1 -1
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
CLI to bootstrap a project with a Nurix harness. Copies the harness's `CLAUDE.md`, skills, agents, rules, and hooks (plus scripts, if the harness ships any) into the project so they live with the code — version-controllable, editable per project, and visible without leaving the repo.
|
|
4
4
|
|
|
5
|
-
A second install path also exists and is fully supported: `/plugin install <plugin>@nurixlabs` from inside Claude Code, which installs the harness as a plugin from the `nurixlabs/skills` marketplace. The two paths are first-class equals — pick the one that matches how you want to manage the harness. See [`docs/
|
|
5
|
+
A second install path also exists and is fully supported: `/plugin install <plugin>@nurixlabs` from inside Claude Code, which installs the harness as a plugin from the `nurixlabs/skills` marketplace. The two paths are first-class equals — pick the one that matches how you want to manage the harness. See [`docs/playbooks/harness/Readme.md`](../../docs/playbooks/harness/Readme.md#the-install-model) for the comparison.
|
|
6
6
|
|
|
7
7
|
## Usage
|
|
8
8
|
|
|
@@ -37,6 +37,7 @@ Rules for the plan regime between the plan gate and the verification gate:
|
|
|
37
37
|
- **On a rendered surface, browser driving LEADS the gate — it is not its final rung.** The order inverted deliberately: the defects that reach users through an interface are geometric and compositional, and a simulated DOM computes no layout, so a suite that is entirely green says nothing about whether anything is where it should be. **Reach the browser Chrome-CDP-first and Playwright second** — CDP drives a real browser interactively and needs no script written in advance, which is what discovery requires; Playwright is the fallback where CDP is unavailable and the tool of record for whatever must run unattended afterwards. Cheap oracles run in the same pass and are what the drive's findings get pinned into; they are no longer a gate to pass before looking. A surface with nothing rendered — a CLI, a service, a library — drives its own real binary or wire instead, and this clause does not apply.
|
|
38
38
|
- **A judged drive discovers; a scripted assertion guards.** Only the first finds a defect nobody has seen — a script asserting a control's value passes over a control drawn on top of its own label. Scripts are written after a judged drive names the class of defect, never generated ahead of one, and **a red script is never regenerated** — regeneration re-derives the assertion from the surface as it currently is, which turns a defect into the asserted truth with everything green.
|
|
39
39
|
- **Report what happened, including failures.** A gate that reports green while a suite is red is worse than no gate; state the failing test and its output.
|
|
40
|
+
- **`cmd > log; echo "EXIT=$?"` reports the echo's status, never the command's** — a SIGTERM'd suite surfaces as "exit code 0", which is the worst direction for a gate to be wrong in. Read the real status from the log, or drop the trailing echo. Adjacent trap: a runner that never emits a summary is a dying **worker**, not a slow test — `--testTimeout` bounds neither, so bound the run and read the log.
|
|
40
41
|
- **Abandonment does not erase debt.** Before `Status: Abandoned` freezes a plan whose code was committed, convert its undischarged rows into backlog items; uncommitted code owes nothing.
|
|
41
42
|
|
|
42
43
|
## Frameworks by stack
|
package/data/harness-index.json
CHANGED
|
@@ -18,10 +18,10 @@ You do NOT write the LLD — you return structured research that the main agent
|
|
|
18
18
|
Map the documentation landscape — what exists, what is adjacent, how detailed the LLD should be, and what code paths are already owned:
|
|
19
19
|
|
|
20
20
|
1. Read `./docs/structure.md` to understand the documentation structure
|
|
21
|
-
2.
|
|
21
|
+
2. Locate the repo's feature-doc layer from `structure.md` — the standard shape is `./docs/features/`, but a repo may document components under their own subject folders. Read that layer's index if it has one; otherwise glob for docs carrying `owns:` frontmatter
|
|
22
22
|
3. If `./docs/memory/lld-mode.md` exists (or the legacy `./docs/memory/spec-mode.md`), read it for feature doc inventory, ownership conflict zones, and lessons from previous research
|
|
23
|
-
4. Read 1-2 existing feature LLDs
|
|
24
|
-
5. Consult the **injected ownership index** (the generated `glob → doc · module · keywords · status` map — the union of every feature doc's `owns:` frontmatter) to build the ownership map. It is the source of truth for what code paths are already owned. If the index isn't present in context, glob `docs/
|
|
23
|
+
4. Read 1-2 existing feature LLDs from that layer to calibrate format and depth
|
|
24
|
+
5. Consult the **injected ownership index** (the generated `glob → doc · module · keywords · status` map — the union of every feature doc's `owns:` frontmatter) to build the ownership map. It is the source of truth for what code paths are already owned. If the index isn't present in context, glob the docs tree (excluding `docs/history/`) and read the `owns:` frontmatter of every doc that declares it.
|
|
25
25
|
|
|
26
26
|
## What You Research
|
|
27
27
|
|
|
@@ -44,15 +44,15 @@ Decide the mode once, up front, from the version marker — then run.
|
|
|
44
44
|
|
|
45
45
|
## Part A — Coherence audit (always runs)
|
|
46
46
|
|
|
47
|
-
The ownership source of truth is the **union of every
|
|
47
|
+
The ownership source of truth is the **union of every doc's `owns:` frontmatter** — the same source the SessionStart ownership index derives from. There is no `docs/routing.md` and no precomputed file to regenerate; you rebuild the map by globbing the docs tree for docs that declare `owns:`.
|
|
48
48
|
|
|
49
49
|
### Step 1: Build the ownership map
|
|
50
50
|
|
|
51
51
|
1. Read `docs/structure.md` for the authority map.
|
|
52
|
-
2. Glob
|
|
52
|
+
2. Glob the docs tree for markdown carrying `owns:` frontmatter, ignoring `*.bkp.*` files (installer backups awaiting the fold) and anything under `docs/history/` (frozen records quote retired globs as provenance). **Ownership is declared, not positional** — the standard shape files these docs under `docs/features/`, but a repo may declare ownership on any doc, and the index reads them all. For each, parse the `owns:` globs and `module:` label.
|
|
53
53
|
3. Build a map: glob → owning doc + module. Narrower glob wins on overlap. **This IS the source of truth.**
|
|
54
54
|
|
|
55
|
-
**Architecture-first fallback.** If no
|
|
55
|
+
**Architecture-first fallback.** If no doc carries `owns:` yet (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 `owns:` map becomes primary the moment any feature doc declares ownership — this is a fallback, not a replacement.
|
|
56
56
|
|
|
57
57
|
### Step 2: Validate ownership
|
|
58
58
|
|
|
@@ -109,7 +109,7 @@ For each stale doc: update the doc directly when the drift is clear (renamed fun
|
|
|
109
109
|
|
|
110
110
|
For each feature doc you verified accurate or updated this pass, stamp `last-reviewed:` in its frontmatter with today's date (add the key if absent). Never write review dates into the body — it's frontmatter metadata only.
|
|
111
111
|
|
|
112
|
-
For unowned code
|
|
112
|
+
For an unowned code **region**, append: `- **[P2]** No feature doc owns \`{dir}/\` — discovered by maintenance` (`{dir}` = the actual unowned source directory). The target is **every region has an owner**, never every file: an individual shared file that several features import is expected to be unowned, because its authority is the contract it exposes rather than any one consumer. Report a directory that no doc's region covers; never mint a row for a shared file, and never propose closing a gap by adding a file glob to whichever doc happens to import it.
|
|
113
113
|
|
|
114
114
|
**Declined realignment.** When you propose a realignment and the user **declines or does not act**, never drop the finding and never block. Append it to `docs/history/backlog.md` as `- **[P0–P3]** <finding> — discovered by maintenance`, priority = the finding's own severity **on the same P0–P3 scale as code items** — never a segregated "compliance" section, never auto-relegated to the lowest tier. Record once: dedupe against existing entries; if already present, leave it.
|
|
115
115
|
|
|
@@ -238,6 +238,7 @@ Apply the **§ Strategy memory** retirement procedure to `docs/memory/maintenanc
|
|
|
238
238
|
- **A clean report is valid** — do not invent issues.
|
|
239
239
|
- **Declarative, idempotent.** Re-running baseline mode on a current repo reshapes nothing — a second pass is just the audit plus the module proposal. Converge to the current shape; never replay a version ladder; never reconstruct a past shape.
|
|
240
240
|
- **Brownfield extraction (operator-ruled 2026-08-19).** When baseline mode meets a repo with a real source tree and few or no feature docs, the module *proposal* is not enough — run the extraction pass: produce feature docs for the recognized modules (docs/features/, full frontmatter: `owns:` · `module:` · `keywords:` · `status:` · `last-reviewed:` · `type: feature` · `derivation: "extracted (baseline YYYY-MM-DD, codegraph + source read)"`), plus the architecture, tests, and operations layers. Use the `codegraph` skill where installed — localize through the index before reading; the docs record intent, the index answers facts. **Every extracted feature doc carries a `## History & Ownership` section** — top contributors with recency, churn posture, and bus-factor notes, dated "as of YYYY-MM-DD" (operator ruling: this section is mandatory in extraction output even though doc-lint flags dated narrative in truth docs; the findings are accepted for now, and a future harness version may retire the section in favor of live index pointers). `status:` is evidence-graded: `deprecated` only when history shows the area dead, never by guess. Scale by fan-out (one extraction lane per module, a completeness critic over the result) rather than one long cold read.
|
|
241
|
+
- **Diagrams ride the baseline (operator-ruled 2026-08-24).** Whenever baseline mode produces or converges the architecture layer, draw two ASCII diagrams from the real source, each in its own fenced code block: (1) an **architecture diagram** in the system-design/architecture doc — the actual processes, entry points, and wire surfaces as boxes, the calls/queues/files between them as labelled arrows; (2) a **DB ER diagram** wherever the repo declares a relational schema (DDL, migrations, an ORM schema) — one box per table listing its key columns, FK edges drawn to the table they reference, cardinality on the edge; it lands in the domain-model doc, or `docs/architecture/data-model.md` when none exists. Box-drawing characters (`┌─┐│└┘├┤`), width ≤ 100 columns. Derived only from what the code declares — a diagram never invents a component the source does not show, and a repo with no relational schema gets **no** ER diagram rather than an imagined one. Diagrams are truth-document sections: later baselines and audits converge them in place like any other section.
|
|
241
242
|
- **Tool tiers.** The SessionStart context names each manifest-declared tool with its tier; calibrate the run to it, never stall on it. **Present-fresh** (`Tool: codegraph 0.2.0`): use it — check `codegraph projects` for staleness, re-run `codegraph index` if HEAD has moved, then localize every question through the index before reading source. **Present-stale** (below the catalog minimum): still use it, but note the version gap and the upgrade command in the run report — a stale contract may lack answer shapes the skill assumes. **Absent** (`Tool: codegraph MISSING`): fall back to the cold method (Glob/Grep/read), state in the run report that the tool was absent and give the install command — degraded output is acceptable, silent degradation is not.
|
|
242
243
|
- **One sentinel.** `docs/structure.md` `harness-version` is the only baseline/version marker.
|
|
243
244
|
- **Modules are labels, layout-blind.** Seed from the code's bounded contexts; never from `pnpm-workspace.yaml`/workspace walls. Propose, don't force; acting is a `module:` tag, never a folder.
|
|
@@ -14,9 +14,9 @@ You do NOT write the LLD — you return structured research that the main agent
|
|
|
14
14
|
Map the documentation landscape — what exists, what is adjacent, how detailed the LLD should be, and what code paths are already owned:
|
|
15
15
|
|
|
16
16
|
1. Read `./docs/structure.md` to understand the documentation structure
|
|
17
|
-
2.
|
|
17
|
+
2. Locate the repo's feature-doc layer from `structure.md` — the standard shape is `./docs/features/`, but a repo may document components under their own subject folders. Read that layer's index if it has one; otherwise glob for docs carrying `owns:` frontmatter
|
|
18
18
|
3. If `./docs/memory/lld-mode.md` exists (or the legacy `./docs/memory/spec-mode.md`), read it for feature doc inventory, ownership conflict zones, and lessons from previous research
|
|
19
|
-
4. Read 1-2 existing feature LLDs
|
|
19
|
+
4. Read 1-2 existing feature LLDs from that layer to calibrate format and depth
|
|
20
20
|
5. Consult the **injected ownership index** (the generated `glob → doc · module · keywords · status` map — the union of every feature doc's `owns:` frontmatter) to build the ownership map. It is the source of truth for what code paths are already owned. If the index isn't present in context, glob `docs/features/**/*.md` and read each doc's `owns:` frontmatter directly.
|
|
21
21
|
|
|
22
22
|
## What You Research
|
|
@@ -42,15 +42,15 @@ Decide the mode once, up front, from the version marker — then run.
|
|
|
42
42
|
|
|
43
43
|
## Part A — Coherence audit (always runs)
|
|
44
44
|
|
|
45
|
-
The ownership source of truth is the **union of every
|
|
45
|
+
The ownership source of truth is the **union of every doc's `owns:` frontmatter** — the same source the SessionStart ownership index derives from. There is no `docs/routing.md` and no precomputed file to regenerate; you rebuild the map by globbing `docs/features/`.
|
|
46
46
|
|
|
47
47
|
### Step 1: Build the ownership map
|
|
48
48
|
|
|
49
49
|
1. Read `docs/structure.md` for the authority map.
|
|
50
|
-
2. Glob
|
|
50
|
+
2. Glob the docs tree for markdown carrying `owns:` frontmatter, ignoring `*.bkp.*` files and anything under `docs/history/`. **Ownership is declared, not positional** — the standard shape files these under `docs/features/`, but a repo may declare ownership on any doc. For each, parse the `owns:` globs and `module:` label.
|
|
51
51
|
3. Build a map: glob → owning doc + module. Narrower glob wins on overlap. **This IS the source of truth.**
|
|
52
52
|
|
|
53
|
-
**Architecture-first fallback.** If no
|
|
53
|
+
**Architecture-first fallback.** If no doc carries `owns:` yet (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 `owns:` map becomes primary the moment any feature doc declares ownership — this is a fallback, not a replacement.
|
|
54
54
|
|
|
55
55
|
### Step 2: Validate ownership
|
|
56
56
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"harness": "code",
|
|
3
3
|
"name": "code",
|
|
4
|
-
"version": "3.14.
|
|
4
|
+
"version": "3.14.6",
|
|
5
5
|
"files": [
|
|
6
6
|
".prettierignore",
|
|
7
7
|
".prettierrc.json",
|
|
@@ -25,5 +25,5 @@
|
|
|
25
25
|
}
|
|
26
26
|
],
|
|
27
27
|
"docsRoot": "docs",
|
|
28
|
-
"digest": "
|
|
28
|
+
"digest": "ec29198342ff"
|
|
29
29
|
}
|
|
@@ -15,6 +15,7 @@ import {
|
|
|
15
15
|
buildEdgeIndex,
|
|
16
16
|
scanFeatureDocs,
|
|
17
17
|
owningDocs,
|
|
18
|
+
owningDoc,
|
|
18
19
|
listRepoFiles,
|
|
19
20
|
deadGlobs,
|
|
20
21
|
globToRegExp,
|
|
@@ -273,8 +274,14 @@ function sessionStart(projectDir, payload = {}) {
|
|
|
273
274
|
// The doc→code index answers "which doc owns this file"; the edge index answers "which docs does
|
|
274
275
|
// this doc implicate" — both directions of the same graph, and neither is hand-maintained.
|
|
275
276
|
const edges = buildEdgeIndex(projectDir);
|
|
276
|
-
|
|
277
|
+
let context = [block, index, edges].filter(Boolean).join("\n\n");
|
|
277
278
|
if (!context) return;
|
|
279
|
+
// Announce the next growth cliff instead of leaving it to be discovered by an audit. The pipe
|
|
280
|
+
// buffer is 65,536 bytes; the harness's own always-loaded budget is far smaller than that.
|
|
281
|
+
const bytes = Buffer.byteLength(context, "utf8");
|
|
282
|
+
if (bytes > 60000) {
|
|
283
|
+
context = `# INDEX SIZE WARNING: this payload is ${bytes} bytes and is approaching the 65,536-byte pipe limit.\n${context}`;
|
|
284
|
+
}
|
|
278
285
|
process.stdout.write(
|
|
279
286
|
JSON.stringify({
|
|
280
287
|
hookSpecificOutput: { hookEventName: "SessionStart", additionalContext: context },
|
|
@@ -351,7 +358,15 @@ function detectorForFile(projectDir, rel, meta, rows) {
|
|
|
351
358
|
})
|
|
352
359
|
);
|
|
353
360
|
}
|
|
354
|
-
|
|
361
|
+
// ONE ROW FOR ONE OWNER. "Most specific wins" decides which doc a change implicates, so a file
|
|
362
|
+
// under both packages/x/** and packages/x/y/z/** implicates the narrower doc alone — raising a
|
|
363
|
+
// row per matching doc made the busiest shared files mint three or four blocking rows apiece,
|
|
364
|
+
// all but one of them noise a bookkeeper then had to drain.
|
|
365
|
+
const resolved = owningDoc(projectDir, rel);
|
|
366
|
+
// A tie is a real ambiguity — CI already treats equal specificity as a conflict — so on a tie
|
|
367
|
+
// every tied doc still gets its row rather than the tie being resolved by list order.
|
|
368
|
+
const implicated = resolved ? [resolved.doc, ...resolved.tied] : [];
|
|
369
|
+
for (const owner of implicated) {
|
|
355
370
|
rows.push(
|
|
356
371
|
formatAutoRow({
|
|
357
372
|
...meta,
|
|
@@ -550,5 +565,9 @@ try {
|
|
|
550
565
|
} catch (e) {
|
|
551
566
|
// Inform-only module: on any failure, inject nothing, write nothing, never block.
|
|
552
567
|
} finally {
|
|
553
|
-
process.exit(
|
|
568
|
+
// NEVER process.exit() HERE. Node does not flush pending async stdout writes on exit, so a payload
|
|
569
|
+
// larger than the 65,536-byte pipe buffer is severed mid-write and arrives as unparseable JSON —
|
|
570
|
+
// which reads downstream as "no index" rather than as an error. Setting the code lets the runtime
|
|
571
|
+
// drain the pipe and exit on its own.
|
|
572
|
+
process.exitCode = 0;
|
|
554
573
|
}
|
|
@@ -157,15 +157,21 @@ export function buildIndex(projectDir) {
|
|
|
157
157
|
deprecated += 1;
|
|
158
158
|
continue; // keep deprecated docs out of the routing lines
|
|
159
159
|
}
|
|
160
|
+
if (!entry.owns.length) continue;
|
|
161
|
+
// METADATA ONCE PER DOC, NOT ONCE PER GLOB. Re-emitting a doc's keyword array beside every one
|
|
162
|
+
// of its globs makes the index grow with the dependency graph rather than the doc count: on a
|
|
163
|
+
// 42-keyword doc owning 15 paths the same 42 facts were repeated 15 times, and keywords
|
|
164
|
+
// outweighed the glob paths — the only part that routes — by more than four to one.
|
|
160
165
|
const kw = entry.keywords.length ? `[${entry.keywords.join(", ")}]` : "[]";
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
166
|
+
lines.push(
|
|
167
|
+
`${entry.doc} · ${entry.module} · ${entry.status}\n ${kw}\n` +
|
|
168
|
+
entry.owns.map((glob) => ` ${glob}`).join("\n")
|
|
169
|
+
);
|
|
164
170
|
}
|
|
165
171
|
if (lines.length === 0) return "";
|
|
166
172
|
lines.sort();
|
|
167
173
|
const header =
|
|
168
|
-
"# Ownership index (generated) —
|
|
174
|
+
"# Ownership index (generated) — owning feature doc · module · status, then the code regions it governs.\n" +
|
|
169
175
|
"# Match the file or topic you're about to touch, then read the owning doc before changing it.\n";
|
|
170
176
|
const indexed = docs.length - deprecated;
|
|
171
177
|
const skipped = total - docs.length;
|
|
@@ -329,6 +335,35 @@ export function specificity(glob) {
|
|
|
329
335
|
return { literal, wildcard };
|
|
330
336
|
}
|
|
331
337
|
|
|
338
|
+
// The single owning doc for a path, applying the "most specific wins" ladder the harness has always
|
|
339
|
+
// stated in prose and never executed — `specificity()` was reachable only from `overlaps()`, which
|
|
340
|
+
// runs in CI. Returns { doc, glob, tied } where `tied` lists the other docs matching at the SAME
|
|
341
|
+
// specificity. A tie is never collapsed silently: an equal-specificity overlap is already a CI
|
|
342
|
+
// error, so it must stay loud here rather than be resolved by list order.
|
|
343
|
+
export function owningDoc(projectDir, relPath, docs) {
|
|
344
|
+
const matches = owningDocs(projectDir, relPath, docs);
|
|
345
|
+
if (matches.length <= 1) return matches.length ? { doc: matches[0], glob: null, tied: [] } : null;
|
|
346
|
+
const rel = String(relPath).split(path.sep).join("/");
|
|
347
|
+
const scored = [];
|
|
348
|
+
for (const entry of matches) {
|
|
349
|
+
// A doc may own a path through several globs; it competes on its most specific matching one.
|
|
350
|
+
let best = null;
|
|
351
|
+
for (const glob of entry.owns) {
|
|
352
|
+
if (!globToRegExp(glob).test(rel)) continue;
|
|
353
|
+
const s = specificity(glob);
|
|
354
|
+
if (!best || s.literal > best.s.literal || (s.literal === best.s.literal && s.wildcard < best.s.wildcard)) {
|
|
355
|
+
best = { glob, s };
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
if (best) scored.push({ entry, ...best });
|
|
359
|
+
}
|
|
360
|
+
if (!scored.length) return null;
|
|
361
|
+
scored.sort((a, b) => b.s.literal - a.s.literal || a.s.wildcard - b.s.wildcard);
|
|
362
|
+
const top = scored[0];
|
|
363
|
+
const tied = scored.filter((x) => x !== top && x.s.literal === top.s.literal && x.s.wildcard === top.s.wildcard);
|
|
364
|
+
return { doc: top.entry, glob: top.glob, tied: tied.map((x) => x.entry) };
|
|
365
|
+
}
|
|
366
|
+
|
|
332
367
|
// Cross-doc equal-specificity ownership conflicts: two globs from DIFFERENT feature docs that
|
|
333
368
|
// match a common file at the same specificity, so "most specific wins" cannot pick an owner and
|
|
334
369
|
// the path is doubly owned. Returns [{ a: {doc, glob}, b: {doc, glob}, example }] — one pass
|
|
@@ -37,6 +37,7 @@ Rules for the plan regime between the plan gate and the verification gate:
|
|
|
37
37
|
- **On a rendered surface, browser driving LEADS the gate — it is not its final rung.** The order inverted deliberately: the defects that reach users through an interface are geometric and compositional, and a simulated DOM computes no layout, so a suite that is entirely green says nothing about whether anything is where it should be. **Reach the browser Chrome-CDP-first and Playwright second** — CDP drives a real browser interactively and needs no script written in advance, which is what discovery requires; Playwright is the fallback where CDP is unavailable and the tool of record for whatever must run unattended afterwards. Cheap oracles run in the same pass and are what the drive's findings get pinned into; they are no longer a gate to pass before looking. A surface with nothing rendered — a CLI, a service, a library — drives its own real binary or wire instead, and this clause does not apply.
|
|
38
38
|
- **A judged drive discovers; a scripted assertion guards.** Only the first finds a defect nobody has seen — a script asserting a control's value passes over a control drawn on top of its own label. Scripts are written after a judged drive names the class of defect, never generated ahead of one, and **a red script is never regenerated** — regeneration re-derives the assertion from the surface as it currently is, which turns a defect into the asserted truth with everything green.
|
|
39
39
|
- **Report what happened, including failures.** A gate that reports green while a suite is red is worse than no gate; state the failing test and its output.
|
|
40
|
+
- **`cmd > log; echo "EXIT=$?"` reports the echo's status, never the command's** — a SIGTERM'd suite surfaces as "exit code 0", which is the worst direction for a gate to be wrong in. Read the real status from the log, or drop the trailing echo. Adjacent trap: a runner that never emits a summary is a dying **worker**, not a slow test — `--testTimeout` bounds neither, so bound the run and read the log.
|
|
40
41
|
- **Abandonment does not erase debt.** Before `Status: Abandoned` freezes a plan whose code was committed, convert its undischarged rows into backlog items; uncommitted code owes nothing.
|
|
41
42
|
|
|
42
43
|
## Frameworks by stack
|
|
@@ -6,7 +6,7 @@ correctly, the record stays readable at any pause, and the session ends with a h
|
|
|
6
6
|
complete that the session folder is useless — it moves to history and the user deletes or
|
|
7
7
|
commits it.
|
|
8
8
|
|
|
9
|
-
> Spec (single source of truth): `docs/
|
|
9
|
+
> Spec (single source of truth): `docs/skills/brainstorm/` in the etna repo. The etna
|
|
10
10
|
> copy of this skill (`skills/brainstorm/`) is canonical; the user-level path
|
|
11
11
|
> `~/.claude/skills/brainstorm/` is a symlink to it.
|
|
12
12
|
|
|
@@ -96,3 +96,25 @@ These bind every writer of the working surface — facilitator (ops), twin (ever
|
|
|
96
96
|
5. **Directional steering is not feature truth.** A harvested principle informs many decisions
|
|
97
97
|
and changes slowly; a feature fact belongs to its feature doc and changes at code speed. The
|
|
98
98
|
harvest links between the two layers, never duplicates prose across them.
|
|
99
|
+
|
|
100
|
+
## Field lessons — capture and converge
|
|
101
|
+
|
|
102
|
+
Measured on live sessions; each is the rule, distilled.
|
|
103
|
+
|
|
104
|
+
- **Separate user voice from facilitator re-derivation before ledgering** when both arrive in one
|
|
105
|
+
turn. Only the user's half is ledgerable; a re-derivation that quietly re-reads an existing
|
|
106
|
+
commitment into a new shape is caught as a fork with a named amendment to the affected `D#`,
|
|
107
|
+
never as an edit — a commitment recorded in the user's words is amended only by the user.
|
|
108
|
+
- **Stamp in UTC, always** — take the stamp from `date -u`, never from the runtime's injected
|
|
109
|
+
local date; the two disagree for part of every working day in some offsets, and a local-date
|
|
110
|
+
stamp runs the ledger a day ahead of capture.
|
|
111
|
+
- **Run the blindspot pass immediately after a converge burst, before the manifest gate.** When
|
|
112
|
+
several picks land in one sitting the strain migrates *between* them — collisions between
|
|
113
|
+
commitments taken within the same hour, found only by reading two together. The burst is the
|
|
114
|
+
cheapest moment to catch them and the last before they freeze.
|
|
115
|
+
- **When a pick answers three of a fork's four close-condition clauses, close it and file the
|
|
116
|
+
residue as a new fork in the same pass** — closing silently and leaving it open both lose
|
|
117
|
+
information; name the unanswered clause in the resolving entry and carry it under a new `F#`.
|
|
118
|
+
- **When a ledger entry's `Why` contains "already", verify it before the manifest.** A commitment
|
|
119
|
+
that declines to build something because it already exists rests on a fact, not a judgment, and
|
|
120
|
+
the stop gate is the last place that fact is checkable — after the folder moves it is not.
|
|
@@ -84,3 +84,37 @@ Then the offer, relayed by the facilitator: **delete the moved folder, or commit
|
|
|
84
84
|
decides; the design assumes deletion — nothing anywhere may depend on the folder surviving.
|
|
85
85
|
Committing is the explicit way to keep git-history forensics; an uncommitted folder deleted here
|
|
86
86
|
is gone, and that residual is accepted by design.
|
|
87
|
+
|
|
88
|
+
## Field lessons — apply
|
|
89
|
+
|
|
90
|
+
Measured on live harvests; each is the rule, distilled.
|
|
91
|
+
|
|
92
|
+
- **Run the move gate clean immediately before the move and treat that as the verdict** — the
|
|
93
|
+
gate's checks read `ops/`, which the move deletes, so a post-move re-run fails by construction.
|
|
94
|
+
Verify the post-move state by hand: `Status: harvested`, no `ops/`, both index rows,
|
|
95
|
+
`check-links` clean. And **distil the process record into `state.md` before the move** — the
|
|
96
|
+
sync log dies with `ops/`, and a ten-line dispatch summary is what separates a record that shows
|
|
97
|
+
its workings from one that asserts its commitments from nowhere.
|
|
98
|
+
- **Uncommitted harvest artifacts are deleted, not deprecated** — deprecate-in-place protects
|
|
99
|
+
readers holding a pointer, and a never-committed file has none; a tombstone for a
|
|
100
|
+
twenty-minute-old file is ceremony.
|
|
101
|
+
- **Audit the *other* decision records for impact at manifest time** — the manifest routes
|
|
102
|
+
through the docs the commitments name and will not think of the neighbours. The test is
|
|
103
|
+
commitment-level, not textual (grep finds nothing); read each AD's Decision and Open Questions
|
|
104
|
+
against the new commitments, and report the unimpacted verdicts with evidence too.
|
|
105
|
+
- **A manifest enumerates sites; the file you open contains more of them.** Fix every
|
|
106
|
+
same-doctrine site inside a file the manifest already opens — a self-contradicting document is
|
|
107
|
+
worse than a wider diff — but never wander into an unnamed file: that becomes a backlog row.
|
|
108
|
+
Say which you did, per row, in the application record.
|
|
109
|
+
- **Re-run the uselessness test when the destination *set* changes**, not only when content does —
|
|
110
|
+
a consolidation that moves referrers produces a document set no cold reader has graded. The
|
|
111
|
+
recurring find: a truth doc stating a decided-but-unbuilt mechanism in the present tense; the
|
|
112
|
+
fix is one clause naming the unbuilt prerequisite.
|
|
113
|
+
- **Retirement wording beats suppression.** doc-lint's heuristics block the honest retirement
|
|
114
|
+
sentence (`superseded by`, `no longer`); rephrase with no loss of meaning — "retired by
|
|
115
|
+
AD-00N", "is not the product's position", "lives in a package that is gone" — and reach for
|
|
116
|
+
`doc-lint-disable` only when the banned phrase is itself the claim.
|
|
117
|
+
- **Amending another session's draft: change the contradicting claim everywhere it is asserted,
|
|
118
|
+
and nothing else** — a claim stated in nine places and fixed in three leaves the doc worse; a
|
|
119
|
+
one-paragraph note saying what moved and what did not keeps the amendment legible to the doc's
|
|
120
|
+
author.
|
|
@@ -118,4 +118,4 @@ skills/design/
|
|
|
118
118
|
# elevation/ motion/ iconography.md · tells.csv · charts/ (census)
|
|
119
119
|
```
|
|
120
120
|
|
|
121
|
-
This folder is the shipped skill, byte-for-byte. The six taste dictionaries are served by the design MCP; their authored source lives in the etna design record (`docs/
|
|
121
|
+
This folder is the shipped skill, byte-for-byte. The six taste dictionaries are served by the design MCP; their authored source lives in the etna design record (`docs/skills/design/`), which a run never reads.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Component catalog — the fused index
|
|
2
2
|
|
|
3
|
-
> **Generated folder — never hand-edit.** Everything under `skills/design/components/` is emitted by the components-repo regen instruction set (`docs/
|
|
3
|
+
> **Generated folder — never hand-edit.** Everything under `skills/design/components/` is emitted by the components-repo regen instruction set (`docs/playbooks/skills/case-studies/components-regen-spec.md`, run against the `@nurix/components` library checkout). Regeneration may reshape any file beneath this one; the design skill's only seam with this folder is this index.
|
|
4
4
|
|
|
5
5
|
**Load contract.** This index loads in **both** positions of the project's `primitives` switch (`design.md`, `primitives: nurix | native`) — it is how the skill knows what chrome *exists* to compose with. The per-category deep references beside it ([inputs](inputs.md), [overlays](overlays.md), [collections](collections.md), [navigation](navigation.md), [layout](layout.md), [feedback](feedback.md), [charts](charts.md), [typography](typography.md), [media](media.md), [motion](motion.md), [hooks](hooks.md), [utils](utils.md), plus [setup](setup.md) for install/Tailwind wiring) load **only under `primitives: nurix`**, and only when that category is touched.
|
|
6
6
|
|
|
@@ -24,7 +24,7 @@ Document contracts and architecture, not implementation details. Show function s
|
|
|
24
24
|
|
|
25
25
|
The journey — dates, migrations, progress, supersessions — lives only in records (`docs/history/`); when reality changes, a truth document simply becomes correct. The full strip-list and the record-side rules: [`references/style-guide.md`](references/style-guide.md) § The Two Natures — Tense & History.
|
|
26
26
|
|
|
27
|
-
The mechanical subset of these rules is checked by [`scripts/doc-lint.mjs`](scripts/doc-lint.mjs) — run it over changed docs before finishing. Block-severity findings must be fixed; `<!-- doc-lint-disable: <id> -->` with a reason beside it is the escape hatch.
|
|
27
|
+
The mechanical subset of these rules is checked by [`scripts/doc-lint.mjs`](scripts/doc-lint.mjs) — run it over changed docs before finishing. Block-severity findings must be fixed; `<!-- doc-lint-disable: <id> -->` with a reason beside it is the escape hatch. Two invocation traps: the disable comment takes **bare rule ids only** — prose inside the comment silently breaks the parse, so put the reason in a second comment beside it — and the script grades truth-vs-record scope by matching `docs/(history|research|memory)/` against **the path string it is given**, so always hand it a repo-root-relative path; linting a record from inside its own folder grades it as a truth document.
|
|
28
28
|
|
|
29
29
|
---
|
|
30
30
|
|
|
@@ -85,7 +85,7 @@ The two guarantees are complementary and both break on mixing: a reader holding
|
|
|
85
85
|
| Derive/update a feature doc's `owns:` | [`references/frontmatter.md`](references/frontmatter.md) |
|
|
86
86
|
| Update existing doc | § Editing an existing doc (below) |
|
|
87
87
|
| Instruction file (`CLAUDE.md`, a rule, an agent, skill prose) | [`references/instruction-style.md`](references/instruction-style.md) — not these templates; every-load prose stays lean, and the present-tense rule still applies |
|
|
88
|
-
| Author or restructure a **skill** (fit, triggers, shape, anatomy, shipping) | The skill-authoring field guide — the `etna` repo (`nurixlabs/etna`), folder `docs/
|
|
88
|
+
| Author or restructure a **skill** (fit, triggers, shape, anatomy, shipping) | The skill-authoring field guide — the `etna` repo (`nurixlabs/etna`), folder `docs/playbooks/skills/`, chapters `00`–`10`. **No etna checkout available ⇒ ask the user for access to the etna repo, or proceed from first principles** with [`references/instruction-style.md`](references/instruction-style.md) governing the prose. This row is the only place the playbook is referenced |
|
|
89
89
|
| **No template matches** | [`references/untemplated.md`](references/untemplated.md) — shape decisions + the co-authoring workflow |
|
|
90
90
|
|
|
91
91
|
---
|
|
@@ -24,13 +24,20 @@ A feature doc's ownership frontmatter is `owns:` (required), `module:` (optional
|
|
|
24
24
|
|
|
25
25
|
**1. `owns:`** (the path scope)
|
|
26
26
|
|
|
27
|
-
|
|
27
|
+
`owns:` names the **regions whose truth this doc holds** — the directories where a change must be reconciled against this document before it ships. It is an authority claim a human makes, not an inventory of what the feature touches.
|
|
28
28
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
|
29
|
+
**A file the doc merely references is not a file the doc owns.** Reaching across a boundary into a shared module is a fact about the code, and it belongs to whoever owns that module's region. Transcribing those reach edges as `owns:` entries is how an index stops being a routing table and becomes a hand-maintained import graph: rows then track the dependency graph rather than the feature count, and the shared upstream file ends up filed under whichever downstream feature happened to name it first — a consumer recorded as the authority.
|
|
30
|
+
|
|
31
|
+
Prefer one region glob over many file globs. Ten paths say nothing about which is the entry point; one region says where the doc's writ runs.
|
|
32
|
+
|
|
33
|
+
| The doc governs | Glob |
|
|
34
|
+
| -------------------------------------------- | ------------------------------------ |
|
|
35
|
+
| A feature's own directory | `src/feature/**` |
|
|
36
|
+
| A feature split across two directories | One glob each |
|
|
37
|
+
| A single entry-point file, and nothing beside it | The exact file path |
|
|
38
|
+
| A shared file several features import | **Nothing — leave it unowned** |
|
|
39
|
+
|
|
40
|
+
**An unowned shared file is the system working, not a gap.** A shared module's authority is the contract it exposes, not any one consumer, so a library-references file or a common utility legitimately has no owning doc. Claiming it would make the index bigger and the routing less certain at once.
|
|
34
41
|
|
|
35
42
|
Glob each pattern against the codebase. At `status: active`, drop any that match nothing; at `status: draft`, projected globs may match nothing yet — confirm them against real code when the doc flips to `active`.
|
|
36
43
|
|
|
@@ -71,7 +71,10 @@ Why this work is happening *now*. Link to the spec for *what* we're building; th
|
|
|
71
71
|
<!-- Written by the `testing` skill (plan-gate mode) at the plan gate (after `boundary`). One row per
|
|
72
72
|
promised behavior: layer · target file · oracle · fixtures · an empty Outcome cell the
|
|
73
73
|
verification gate fills (satisfied / owes nothing / blocked → backlog). Amendable while the
|
|
74
|
-
plan is open. Do not hand-author.
|
|
74
|
+
plan is open. Do not hand-author. NEVER put a pipe in a ledger cell, escaped or not — the
|
|
75
|
+
compliance hook splits rows on `|` at a fixed column index with no unescaping, so a
|
|
76
|
+
markdown-legal `\|` shifts every later cell and the wall blocks a row that is in fact
|
|
77
|
+
discharged. Write "`install` or `update`", not "`install \| update`". -->
|
|
75
78
|
|
|
76
79
|
## Open Questions
|
|
77
80
|
|
|
@@ -38,7 +38,7 @@ Read the codegraph status from the session context (`Tool:` line). **Present-fre
|
|
|
38
38
|
|
|
39
39
|
## The dossier
|
|
40
40
|
|
|
41
|
-
Frontmatter: `tracker`, `issue`
|
|
41
|
+
Frontmatter: `type: triage`, `tracker`, `date`, `confidence`, and the subject key — `issue: {id: <n>, url: <url>}` with a **numeric** id for a tracker item, `issue: {id: local:<record-id>}` for a locally-authored record, `pr: {id: <n>}` when the dossier resolves a pull request. This shape is machine-read: the Apollo desktop's Issues panel joins dossiers to tracker rows on exactly this key, so a quoted number, a missing id, or a renamed key leaves the dossier orphaned — written but never surfaced beside its issue. Sections, in order: **Verdict** (1–3 sentences) · Classification · Owning docs (paths) · Root cause (cited, graded) · Blast radius · Suggested fix plan (feeds the plan → PR loop; you never implement) · Test surface · Duplicates & related · **Prior-thread corrections** (claims already on the tracker thread — bot answers, maintainer comments — that your evidence shows to be wrong, each with the citation that refutes it) · Open questions. A dossier is a dated working artifact — it never claims `owns:` globs and never masquerades as a feature doc.
|
|
42
42
|
|
|
43
43
|
## File — harness finding in, tracker issue out
|
|
44
44
|
|
|
@@ -156,7 +156,7 @@ When writing or discharging a ledger row, name the stratum, not just the altitud
|
|
|
156
156
|
|
|
157
157
|
Runs as the tail of every build pass — the session opens it the moment the unit's code is written, without asking (constraints — preconditions, verdict-inline, tier, honesty — are `.claude/rules/testing.md` § The gate). **Drive the real thing first, then pin what must not regress**: driving finds the defects that matter to a user, and shows which behaviors are worth the permanent cost of a test.
|
|
158
158
|
|
|
159
|
-
1. **Write the checklist** — derive or update `docs/tests/{feature}.md` from the ledger and the LLD's promises (the `documentation` skill's `templates/behavioral-checklist.md`; one `**Assert**` per observable). Derived before the driving it is the script; derived after, it is merely a report with nothing to trace tests back to.
|
|
159
|
+
1. **Write the checklist** — derive or update `docs/tests/{feature}.md` from the ledger and the LLD's promises (the `documentation` skill's `templates/behavioral-checklist.md`; one `**Assert**` per observable). Derived before the driving it is the script; derived after, it is merely a report with nothing to trace tests back to. `docs/tests/{feature}.md` pairs with `docs/features/{feature}.md` — writing a checklist whose feature doc does not exist is the tell that one is owed; check here, when the checklist is named.
|
|
160
160
|
|
|
161
161
|
**The gate owns these files, not just their first draft.** Whoever drives a checklist maintains it in the same pass — nothing else in the repo is watching, because a checklist owns no code and no `owns:` glob implicates it, so a surface can be rewritten under a checklist and every hook stays silent. Before driving, reconcile the file against the surface you are about to drive: **retire** sections whose behavior no longer exists (delete them — a checklist is a truth document, and the history lives in git), **add** sections for behavior shipped since the last run, and **repair every `Pinned:` trace**, because a trace naming a test that no longer exists is worse than no trace — it reports coverage that cannot fail. A section you cannot pin says `none yet` and names the test it owes. **Never soften an assertion to make the run green**: the checklist states what the feature promises, the run records what happened, and the backlog carries the difference.
|
|
162
162
|
2. **Drive the real surface, and on a rendered surface drive it visually FIRST.** The old order ran every cheap oracle before earning the right to look at the product; it inverted here because the defects that reach users on a rendered surface are the ones no simulated DOM can see. A slider thumb sitting on its own labels, a settings panel that grows the box someone types into: a suite of two hundred component tests is blind to both by construction, and the only oracle that caught them was judgement applied to real pixels.
|
|
@@ -18,10 +18,10 @@ You do NOT write the LLD — you return structured research that the main agent
|
|
|
18
18
|
Map the documentation landscape — what exists, what is adjacent, how detailed the LLD should be, and what code paths are already owned:
|
|
19
19
|
|
|
20
20
|
1. Read `./docs/structure.md` to understand the documentation structure
|
|
21
|
-
2.
|
|
21
|
+
2. Locate the repo's feature-doc layer from `structure.md` — the standard shape is `./docs/features/`, but a repo may document components under their own subject folders. Read that layer's index if it has one; otherwise glob for docs carrying `owns:` frontmatter
|
|
22
22
|
3. If `./docs/memory/lld-mode.md` exists (or the legacy `./docs/memory/spec-mode.md`), read it for feature doc inventory, ownership conflict zones, and lessons from previous research
|
|
23
|
-
4. Read 1-2 existing feature LLDs
|
|
24
|
-
5. Consult the **injected ownership index** (the generated `glob → doc · module · keywords · status` map — the union of every feature doc's `owns:` frontmatter) to build the ownership map. It is the source of truth for what code paths are already owned. If the index isn't present in context, glob `docs/
|
|
23
|
+
4. Read 1-2 existing feature LLDs from that layer to calibrate format and depth
|
|
24
|
+
5. Consult the **injected ownership index** (the generated `glob → doc · module · keywords · status` map — the union of every feature doc's `owns:` frontmatter) to build the ownership map. It is the source of truth for what code paths are already owned. If the index isn't present in context, glob the docs tree (excluding `docs/history/`) and read the `owns:` frontmatter of every doc that declares it.
|
|
25
25
|
|
|
26
26
|
## What You Research
|
|
27
27
|
|
|
@@ -44,15 +44,15 @@ Decide the mode once, up front, from the version marker — then run.
|
|
|
44
44
|
|
|
45
45
|
## Part A — Coherence audit (always runs)
|
|
46
46
|
|
|
47
|
-
The ownership source of truth is the **union of every
|
|
47
|
+
The ownership source of truth is the **union of every doc's `owns:` frontmatter** — the same source the SessionStart ownership index derives from. There is no `docs/routing.md` and no precomputed file to regenerate; you rebuild the map by globbing the docs tree for docs that declare `owns:`.
|
|
48
48
|
|
|
49
49
|
### Step 1: Build the ownership map
|
|
50
50
|
|
|
51
51
|
1. Read `docs/structure.md` for the authority map.
|
|
52
|
-
2. Glob
|
|
52
|
+
2. Glob the docs tree for markdown carrying `owns:` frontmatter, ignoring `*.bkp.*` files (installer backups awaiting the fold) and anything under `docs/history/` (frozen records quote retired globs as provenance). **Ownership is declared, not positional** — the standard shape files these docs under `docs/features/`, but a repo may declare ownership on any doc, and the index reads them all. For each, parse the `owns:` globs and `module:` label.
|
|
53
53
|
3. Build a map: glob → owning doc + module. Narrower glob wins on overlap. **This IS the source of truth.**
|
|
54
54
|
|
|
55
|
-
**Architecture-first fallback.** If no
|
|
55
|
+
**Architecture-first fallback.** If no doc carries `owns:` yet (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 `owns:` map becomes primary the moment any feature doc declares ownership — this is a fallback, not a replacement.
|
|
56
56
|
|
|
57
57
|
### Step 2: Validate ownership
|
|
58
58
|
|
|
@@ -109,7 +109,7 @@ For each stale doc: update the doc directly when the drift is clear (renamed fun
|
|
|
109
109
|
|
|
110
110
|
For each feature doc you verified accurate or updated this pass, stamp `last-reviewed:` in its frontmatter with today's date (add the key if absent). Never write review dates into the body — it's frontmatter metadata only.
|
|
111
111
|
|
|
112
|
-
For unowned code
|
|
112
|
+
For an unowned code **region**, append: `- **[P2]** No feature doc owns \`{dir}/\` — discovered by maintenance` (`{dir}` = the actual unowned source directory). The target is **every region has an owner**, never every file: an individual shared file that several features import is expected to be unowned, because its authority is the contract it exposes rather than any one consumer. Report a directory that no doc's region covers; never mint a row for a shared file, and never propose closing a gap by adding a file glob to whichever doc happens to import it.
|
|
113
113
|
|
|
114
114
|
**Declined realignment.** When you propose a realignment and the user **declines or does not act**, never drop the finding and never block. Append it to `docs/history/backlog.md` as `- **[P0–P3]** <finding> — discovered by maintenance`, priority = the finding's own severity **on the same P0–P3 scale as code items** — never a segregated "compliance" section, never auto-relegated to the lowest tier. Record once: dedupe against existing entries; if already present, leave it.
|
|
115
115
|
|
|
@@ -238,6 +238,7 @@ Apply the **§ Strategy memory** retirement procedure to `docs/memory/maintenanc
|
|
|
238
238
|
- **A clean report is valid** — do not invent issues.
|
|
239
239
|
- **Declarative, idempotent.** Re-running baseline mode on a current repo reshapes nothing — a second pass is just the audit plus the module proposal. Converge to the current shape; never replay a version ladder; never reconstruct a past shape.
|
|
240
240
|
- **Brownfield extraction (operator-ruled 2026-08-19).** When baseline mode meets a repo with a real source tree and few or no feature docs, the module *proposal* is not enough — run the extraction pass: produce feature docs for the recognized modules (docs/features/, full frontmatter: `owns:` · `module:` · `keywords:` · `status:` · `last-reviewed:` · `type: feature` · `derivation: "extracted (baseline YYYY-MM-DD, codegraph + source read)"`), plus the architecture, tests, and operations layers. Use the `codegraph` skill where installed — localize through the index before reading; the docs record intent, the index answers facts. **Every extracted feature doc carries a `## History & Ownership` section** — top contributors with recency, churn posture, and bus-factor notes, dated "as of YYYY-MM-DD" (operator ruling: this section is mandatory in extraction output even though doc-lint flags dated narrative in truth docs; the findings are accepted for now, and a future harness version may retire the section in favor of live index pointers). `status:` is evidence-graded: `deprecated` only when history shows the area dead, never by guess. Scale by fan-out (one extraction lane per module, a completeness critic over the result) rather than one long cold read.
|
|
241
|
+
- **Diagrams ride the baseline (operator-ruled 2026-08-24).** Whenever baseline mode produces or converges the architecture layer, draw two ASCII diagrams from the real source, each in its own fenced code block: (1) an **architecture diagram** in the system-design/architecture doc — the actual processes, entry points, and wire surfaces as boxes, the calls/queues/files between them as labelled arrows; (2) a **DB ER diagram** wherever the repo declares a relational schema (DDL, migrations, an ORM schema) — one box per table listing its key columns, FK edges drawn to the table they reference, cardinality on the edge; it lands in the domain-model doc, or `docs/architecture/data-model.md` when none exists. Box-drawing characters (`┌─┐│└┘├┤`), width ≤ 100 columns. Derived only from what the code declares — a diagram never invents a component the source does not show, and a repo with no relational schema gets **no** ER diagram rather than an imagined one. Diagrams are truth-document sections: later baselines and audits converge them in place like any other section.
|
|
241
242
|
- **Tool tiers.** The SessionStart context names each manifest-declared tool with its tier; calibrate the run to it, never stall on it. **Present-fresh** (`Tool: codegraph 0.2.0`): use it — check `codegraph projects` for staleness, re-run `codegraph index` if HEAD has moved, then localize every question through the index before reading source. **Present-stale** (below the catalog minimum): still use it, but note the version gap and the upgrade command in the run report — a stale contract may lack answer shapes the skill assumes. **Absent** (`Tool: codegraph MISSING`): fall back to the cold method (Glob/Grep/read), state in the run report that the tool was absent and give the install command — degraded output is acceptable, silent degradation is not.
|
|
242
243
|
- **One sentinel.** `docs/structure.md` `harness-version` is the only baseline/version marker.
|
|
243
244
|
- **Modules are labels, layout-blind.** Seed from the code's bounded contexts; never from `pnpm-workspace.yaml`/workspace walls. Propose, don't force; acting is a `module:` tag, never a folder.
|
|
@@ -14,9 +14,9 @@ You do NOT write the LLD — you return structured research that the main agent
|
|
|
14
14
|
Map the documentation landscape — what exists, what is adjacent, how detailed the LLD should be, and what code paths are already owned:
|
|
15
15
|
|
|
16
16
|
1. Read `./docs/structure.md` to understand the documentation structure
|
|
17
|
-
2.
|
|
17
|
+
2. Locate the repo's feature-doc layer from `structure.md` — the standard shape is `./docs/features/`, but a repo may document components under their own subject folders. Read that layer's index if it has one; otherwise glob for docs carrying `owns:` frontmatter
|
|
18
18
|
3. If `./docs/memory/lld-mode.md` exists (or the legacy `./docs/memory/spec-mode.md`), read it for feature doc inventory, ownership conflict zones, and lessons from previous research
|
|
19
|
-
4. Read 1-2 existing feature LLDs
|
|
19
|
+
4. Read 1-2 existing feature LLDs from that layer to calibrate format and depth
|
|
20
20
|
5. Consult the **injected ownership index** (the generated `glob → doc · module · keywords · status` map — the union of every feature doc's `owns:` frontmatter) to build the ownership map. It is the source of truth for what code paths are already owned. If the index isn't present in context, glob `docs/features/**/*.md` and read each doc's `owns:` frontmatter directly.
|
|
21
21
|
|
|
22
22
|
## What You Research
|
|
@@ -42,15 +42,15 @@ Decide the mode once, up front, from the version marker — then run.
|
|
|
42
42
|
|
|
43
43
|
## Part A — Coherence audit (always runs)
|
|
44
44
|
|
|
45
|
-
The ownership source of truth is the **union of every
|
|
45
|
+
The ownership source of truth is the **union of every doc's `owns:` frontmatter** — the same source the SessionStart ownership index derives from. There is no `docs/routing.md` and no precomputed file to regenerate; you rebuild the map by globbing `docs/features/`.
|
|
46
46
|
|
|
47
47
|
### Step 1: Build the ownership map
|
|
48
48
|
|
|
49
49
|
1. Read `docs/structure.md` for the authority map.
|
|
50
|
-
2. Glob
|
|
50
|
+
2. Glob the docs tree for markdown carrying `owns:` frontmatter, ignoring `*.bkp.*` files and anything under `docs/history/`. **Ownership is declared, not positional** — the standard shape files these under `docs/features/`, but a repo may declare ownership on any doc. For each, parse the `owns:` globs and `module:` label.
|
|
51
51
|
3. Build a map: glob → owning doc + module. Narrower glob wins on overlap. **This IS the source of truth.**
|
|
52
52
|
|
|
53
|
-
**Architecture-first fallback.** If no
|
|
53
|
+
**Architecture-first fallback.** If no doc carries `owns:` yet (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 `owns:` map becomes primary the moment any feature doc declares ownership — this is a fallback, not a replacement.
|
|
54
54
|
|
|
55
55
|
### Step 2: Validate ownership
|
|
56
56
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"harness": "delivery",
|
|
3
3
|
"name": "delivery",
|
|
4
|
-
"version": "0.2.
|
|
4
|
+
"version": "0.2.27",
|
|
5
5
|
"files": [
|
|
6
6
|
".prettierignore",
|
|
7
7
|
".prettierrc.json",
|
|
@@ -10,5 +10,5 @@
|
|
|
10
10
|
"seeds": [],
|
|
11
11
|
"tools": [],
|
|
12
12
|
"docsRoot": "docs",
|
|
13
|
-
"digest": "
|
|
13
|
+
"digest": "b36abb3f2f60"
|
|
14
14
|
}
|