@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
|
@@ -142,15 +142,18 @@ function buildIndex(projectDir) {
|
|
|
142
142
|
const keywords = asList(field(block, "keywords"));
|
|
143
143
|
indexed += 1;
|
|
144
144
|
const doc = path.relative(projectDir, file).split(path.sep).join("/");
|
|
145
|
+
// METADATA ONCE PER DOC, NOT ONCE PER GLOB — kept in step with lib/ownership.mjs buildIndex(),
|
|
146
|
+
// which the parity suite pins. Re-emitting the keyword array beside every glob made the index
|
|
147
|
+
// grow with the dependency graph rather than the doc count.
|
|
145
148
|
const kw = keywords.length ? `[${keywords.join(", ")}]` : "[]";
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
+
lines.push(
|
|
150
|
+
`${doc} · ${moduleLabel} · ${status}\n ${kw}\n` + owns.map((glob) => ` ${glob}`).join("\n")
|
|
151
|
+
);
|
|
149
152
|
}
|
|
150
153
|
if (lines.length === 0) return "";
|
|
151
154
|
lines.sort();
|
|
152
155
|
const header =
|
|
153
|
-
"# Ownership index (generated) —
|
|
156
|
+
"# Ownership index (generated) — owning feature doc · module · status, then the code regions it governs.\n" +
|
|
154
157
|
"# Match the file or topic you're about to touch, then read the owning doc before changing it.\n";
|
|
155
158
|
// A doc dropped by a parse failure is indistinguishable from one that owns nothing,
|
|
156
159
|
// so report the tally: seen vs indexed is the only signal a silent skip leaves.
|
|
@@ -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.
|
|
@@ -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
|
|
|
@@ -18,7 +18,7 @@ Strictly separated — never mix them:
|
|
|
18
18
|
|
|
19
19
|
**The operator layer**: `metadata/lessons/` — read `DIGEST.md` at session start alongside the routing files; it is **prior, not canon** (its reading-protocol block governs). Everything else under `lessons/` (append-only `log/`, `forecasts.md`) loads on demand only. The `lessons-maintenance` agent (instruction set: `metadata/lessons/distillation.md`) runs **only during user sessions** — spawn it in the background when the `metadata/ops/` cursor falls a session behind.
|
|
20
20
|
|
|
21
|
-
The rules are the method — portable, abstract, generic examples; nothing depends on any local topic. Live exemplars are reached through `metadata/TOPICS.md`. Workspace-local method notes go to `metadata/method-changelog.md`; the harness itself is versioned by `.claude/harness.json` and documented in the etna forge (`docs/
|
|
21
|
+
The rules are the method — portable, abstract, generic examples; nothing depends on any local topic. Live exemplars are reached through `metadata/TOPICS.md`. Workspace-local method notes go to `metadata/method-changelog.md`; the harness itself is versioned by `.claude/harness.json` and documented in the etna forge (`docs/harness/discussion/`).
|
|
22
22
|
|
|
23
23
|
## Delegation
|
|
24
24
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"harness": "discussion",
|
|
3
3
|
"name": "discussion",
|
|
4
|
-
"version": "0.6.
|
|
4
|
+
"version": "0.6.1",
|
|
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": "a3de25b70367"
|
|
14
14
|
}
|
|
@@ -29,7 +29,8 @@ Invoke the `maintenance` agent whenever the docs look like they need it — not
|
|
|
29
29
|
|
|
30
30
|
## Getting Started
|
|
31
31
|
|
|
32
|
-
- Read **[`docs/structure.md`](docs/structure.md)** — the documentation authority map
|
|
32
|
+
- Read **[`docs/structure.md`](docs/structure.md)** — the documentation authority map. The top level mirrors the source roots the forge ships from (`skills/`, `harness/`, `rules/`, `packages/`), plus `playbooks/` for the craft guides and `architecture/` for truth spanning two or more subjects. Don't restate it here.
|
|
33
|
+
- Read **[`docs/writing-style.md`](docs/writing-style.md)** before writing anything — the single style authority for this repo.
|
|
33
34
|
- Read **[`docs/memory/`](docs/memory/)** for agent memory files (one per agent).
|
|
34
35
|
- Prefer `docs/` over `README.md` — `docs/` is canonical for agents.
|
|
35
36
|
- The CLI and hooks are the only real code — detect the package manager from the lockfile (see `.claude/rules/general.md`) for anything under `packages/`.
|
|
@@ -61,7 +62,7 @@ Three peer modes plus a Completion step — enter wherever the user's thinking a
|
|
|
61
62
|
| **LLD** (low-level design) | new component/feature work | `lld-mode` agent + `documentation` skill | Plan |
|
|
62
63
|
| **Plan** | an LLD is approved | `documentation` skill → `docs/history/plans/YYYY-MM-DD-{slug}.md` | Completion |
|
|
63
64
|
|
|
64
|
-
> Brainstorm entry needs a **basis** — a reference document or a one-shot brain dump; drip-sized asks (a one-line fix) are too small and get redirected. A **pillar** is a recorded strategic principle from a past brainstorm: in-progress sessions under `docs/research/`, harvested ones under `docs/history/brainstorms/`, harvested doctrine under `docs/architecture/`. The LLD is the
|
|
65
|
+
> Brainstorm entry needs a **basis** — a reference document or a one-shot brain dump; drip-sized asks (a one-line fix) are too small and get redirected. A **pillar** is a recorded strategic principle from a past brainstorm: in-progress sessions under `docs/research/`, harvested ones under `docs/history/brainstorms/`, harvested doctrine under `docs/architecture/`. The LLD is the component's own doc — `docs/skills/{name}/`, `docs/harness/{name}/`, or `docs/packages/{name}.md` — design intent first, extended in place at Completion.
|
|
65
66
|
|
|
66
67
|
**On Plan Completion:**
|
|
67
68
|
|
|
@@ -79,14 +80,14 @@ These three mechanisms keep the repo self-updating: **ownership** routes an edit
|
|
|
79
80
|
|
|
80
81
|
### Ownership — route before editing
|
|
81
82
|
|
|
82
|
-
|
|
83
|
+
**Ownership is declared, not positional.** Any document under `docs/` carrying `owns:` frontmatter claims those code paths — path globs pointing at `skills/**`, `harness/**`, `packages/**`, … — plus an optional `module:` label, `keywords:`, and `status:`. The SessionStart hook scans the whole tree and builds the injected index from the union, so a component's own record claims its path directly and a doc's location is a browsing decision, never an ownership one. Where two docs overlap, the **narrower glob wins**. A module is tied to its components by the `owns:` globs of the docs carrying its `module:` label — not a folder, not a separate map. Indexes, chapters, and explainers carry no `owns:`, so a subject claims its path exactly once.
|
|
83
84
|
|
|
84
85
|
Before modifying a component in an unfamiliar area:
|
|
85
86
|
|
|
86
|
-
1. Consult the **injected ownership index** — the `glob → doc · module · keywords · status` map. Match the path or topic to the owning
|
|
87
|
+
1. Consult the **injected ownership index** — the `glob → doc · module · keywords · status` map. Match the path or topic to the owning doc and read it first. (No index in context ⇒ the repo isn't reconciled — see Maintenance.)
|
|
87
88
|
2. If a `docs/memory/` file exists for the area, read it for domain knowledge and failure modes.
|
|
88
89
|
|
|
89
|
-
The `lld-mode` agent checks for ownership conflicts during LLD research —
|
|
90
|
+
The `lld-mode` agent checks for ownership conflicts during LLD research — docs whose `owns:` globs overlap at equal specificity. Resolve them in the LLD before proceeding.
|
|
90
91
|
|
|
91
92
|
### Boundaries — check while changing
|
|
92
93
|
|
|
@@ -101,10 +102,11 @@ Invoke the `boundary` skill after a plan is approved and before its first implem
|
|
|
101
102
|
|
|
102
103
|
### Documentation — close the loop
|
|
103
104
|
|
|
104
|
-
- **
|
|
105
|
+
- **Everything written in this repo follows [`docs/writing-style.md`](docs/writing-style.md) — no exceptions.** It is the single style authority for both genres: instruction files (`CLAUDE.md`, rules, agents, skill prose) and documents. Read it before writing prose here, not after. Its load-bearing rule is the Two Natures — truth documents state the present and narrate no history; records are dated and never edited to match the present.
|
|
106
|
+
- **Every markdown document also goes through the `documentation` skill** for its *genre* — invoke it before creating or substantively editing any `.md` file and apply the matching template. The skill supplies structure; `writing-style.md` supplies the prose.
|
|
105
107
|
- **[override]** Keep `docs/` updated when a change alters documented behaviour — creating and updating docs is part of the work.
|
|
106
108
|
- After plan completion **[override]**: write the `docs/history/changelog/` entry as a **draft** immediately, while the context is fresh — no confirmation needed — and append its `docs/history/CHANGELOG.md` row; the commit fills what the draft left open and freezes it. Non-plan work needs no separate prompt: every non-exempt commit carries its own entry (the `changelog` rule).
|
|
107
|
-
- When moving or renaming a component: update the `owns:` globs of the
|
|
109
|
+
- When moving or renaming a component: update the `owns:` globs of the doc that owns it so the ownership index stays accurate. A new doc that owns code declares its paths in its own `owns:` frontmatter.
|
|
108
110
|
- `docs/structure.md` is the authority on what belongs where — read it before adding or moving a doc; one canonical source per topic, link don't copy. Only `CLAUDE.md`, `AGENTS.md`, and `README.md` live at the repo root.
|
|
109
111
|
|
|
110
112
|
> Agents and skills live under `.claude/agents/` and `.claude/skills/`. Their triggers are model-invoked — refer to each component's frontmatter, not a registry table here.
|
|
@@ -120,7 +122,7 @@ A commit marks the user's behavioral verification of the work, and the working s
|
|
|
120
122
|
- **A commit is the smallest unit an entry may describe**; above that the mapping is judgment. Work exceeding a draft's scope gets a *second* entry rather than stretching the first.
|
|
121
123
|
- **Distillation is the `retro` agent** — run on demand (before a brainstorm or LLD, before a new project, after a refinement arc), it converts accumulated entries into a typed punch list (doc content, doc structure, skill evolution, pins, harness rules), appends actionable items to the backlog, and proposes only — application runs through the normal documentation loop.
|
|
122
124
|
|
|
123
|
-
**One-shot migrations are a different genre.** Work that runs **once** against a live system — a harness rollout across consumer repos, a catalog-wide cutover, a data backfill — is a **migration runbook** at `docs/history/migrations/YYYY-MM-DD-{slug}.md` (template: the `documentation` skill's `templates/migration-runbook.md`), authored **before** execution and outcome-stamped after. A changelog entry says what changed in this repo; a runbook says what was executed against the world and how to verify or undo it. A repeatable procedure is neither — that
|
|
125
|
+
**One-shot migrations are a different genre.** Work that runs **once** against a live system — a harness rollout across consumer repos, a catalog-wide cutover, a data backfill — is a **migration runbook** at `docs/history/migrations/YYYY-MM-DD-{slug}.md` (template: the `documentation` skill's `templates/migration-runbook.md`), authored **before** execution and outcome-stamped after. A changelog entry says what changed in this repo; a runbook says what was executed against the world and how to verify or undo it. A repeatable procedure is neither — that belongs with the component it operates. When a runbook defers targets, it records **why** and the **trigger to re-evaluate them**, so the next run re-checks rather than inheriting the skip.
|
|
124
126
|
|
|
125
127
|
---
|
|
126
128
|
|
|
@@ -164,12 +166,10 @@ The single policy for sub-agent dispatch — when to fan out, at what tier, and
|
|
|
164
166
|
|
|
165
167
|
❌ prohibitions hold unless the user explicitly asks otherwise; ✅ and ⚠️ items are standing policy:
|
|
166
168
|
|
|
167
|
-
- ❌ **Tests** — etna
|
|
169
|
+
- ❌ **Tests** — etna authors markdown; the only suite is the CLI's, under `packages/cli/`. Never generate, update, or modify test files unless the user explicitly asks. (The `code` harness ships a gated-verification posture for the projects it governs — that is a shipped rule, not etna's own.)
|
|
168
170
|
- ❌ **Dependencies** — never upgrade frameworks, libraries, or dependencies.
|
|
169
|
-
- ❌ **Compatibility** — never maintain backward compatibility unless specified.
|
|
170
171
|
- ❌ **Branches & Worktrees [override]** — never self-create git branches or worktrees; commit straight to the checked-out branch. This replaces any built-in "branch first on the default branch" default. Exception: when the user asks for a pull request, create the branch the PR requires before committing its changes.
|
|
171
|
-
- ❌ **Protected Files** —
|
|
172
|
-
- ✅ **Browser Automation** — Claude in Chrome / CDP browser tools: use freely when useful, no need to ask first.
|
|
172
|
+
- ❌ **Protected Files** — never modify `AGENTS.md`.
|
|
173
173
|
- ✅ **Delegation** — when to fan out, tiers, and trust are § Delegation.
|
|
174
174
|
- ⚠️ **Plans** — created directly in `docs/history/plans/` (see Workflows). Once `Status: Complete` or `Abandoned`, frozen — never edited. If scope changes after completion, write a new dated plan linking back.
|
|
175
175
|
- ⚠️ **Tool Issues** — if any CLI tool, shell alias, or MCP tool behaves unexpectedly (syntax errors, silent failures, wrong defaults), report the exact tool, command, and error to the user so they can fix the underlying library.
|
|
@@ -178,15 +178,15 @@ The single policy for sub-agent dispatch — when to fan out, at what tier, and
|
|
|
178
178
|
|
|
179
179
|
## Authoring Conventions
|
|
180
180
|
|
|
181
|
-
|
|
181
|
+
Almost everything here is markdown — skills, agents, rules, harness policies, docs. **The prose style for all of it is [`docs/writing-style.md`](docs/writing-style.md)**; the guides below add what is specific to each artifact class. Follow the `kb` / `nomenclature` rules; markdown has no file-path-comment rule. Keep the `.claude/rules/*` reference docs frontmatter-free.
|
|
182
182
|
|
|
183
183
|
**Each artifact class has an authoring guide — read the one you are editing, before you edit it.** The forge is the only repo that authors these, so the guides live here and ship nowhere:
|
|
184
184
|
|
|
185
185
|
| Editing | Guide |
|
|
186
186
|
| --- | --- |
|
|
187
|
-
| A **rule** (`rules/*.md`) | [`docs/
|
|
188
|
-
| A **skill** (`skills/*/`) | [`docs/
|
|
189
|
-
| An **agent** (`agents/*.md`) | [`docs/
|
|
187
|
+
| A **rule** (`rules/*.md`) | [`docs/rules/Readme.md`](docs/rules/Readme.md) — the catalog, the conventions, and the whole-file audit |
|
|
188
|
+
| A **skill** (`skills/*/`) | [`docs/playbooks/skills/`](docs/playbooks/skills/Readme.md) — fit and scope through shipping and maintenance |
|
|
189
|
+
| An **agent** (`agents/*.md`) | [`docs/playbooks/agents.md`](docs/playbooks/agents.md) |
|
|
190
190
|
|
|
191
191
|
Authoring or updating an **agent** keeps both runtimes in sync: the `.md` is the single source, and its Codex `.codex.toml` twin is derived from it by the guide above, then checked with `node packages/cli/lib/codex/validate-codex-agents.mjs`.
|
|
192
192
|
|
|
@@ -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": "etna",
|
|
3
3
|
"name": "etna",
|
|
4
|
-
"version": "1.5.
|
|
4
|
+
"version": "1.5.16",
|
|
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": "f836486a6ca4"
|
|
14
14
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
// harness/etna/hooks/generate-ownership-index.mjs — SessionStart hook: scan docs
|
|
1
|
+
// harness/etna/hooks/generate-ownership-index.mjs — SessionStart hook: scan docs/**/*.md,
|
|
2
2
|
// extract the focal frontmatter (owns / module / keywords / status), and inject a compact
|
|
3
3
|
// code-path → owning-doc index via additionalContext. Fires on startup/resume/clear/compact so the
|
|
4
4
|
// map survives /clear and /compact and is regenerated fresh every time. Writes no file.
|
|
@@ -115,10 +115,16 @@ function asList(v) {
|
|
|
115
115
|
|
|
116
116
|
// Build the ownership index text from every feature doc's frontmatter.
|
|
117
117
|
function buildIndex(projectDir) {
|
|
118
|
-
|
|
119
|
-
//
|
|
118
|
+
// Ownership is DECLARED, not positional: any doc anywhere under docs/ that carries owns:
|
|
119
|
+
// claims those paths, so a component's record claims its own path instead of a stub doing it
|
|
120
|
+
// by proxy. docs/history/ is skipped — frozen plans and records quote old globs as provenance,
|
|
121
|
+
// and indexing them would resurrect retired ownership.
|
|
122
|
+
const docsDir = path.join(projectDir, "docs");
|
|
123
|
+
// *.bkp.* files are install-time backups awaiting the maintenance fold — a backed-up
|
|
120
124
|
// doc double-owning every path it names is the drift this filter prevents (parity: lib/ownership.mjs).
|
|
121
|
-
const files = listMarkdown(
|
|
125
|
+
const files = listMarkdown(docsDir)
|
|
126
|
+
.filter((f) => !f.includes(".bkp."))
|
|
127
|
+
.filter((f) => !f.split(path.sep).includes("history"));
|
|
122
128
|
const lines = [];
|
|
123
129
|
let deprecated = 0;
|
|
124
130
|
let indexed = 0;
|
|
@@ -142,15 +148,18 @@ function buildIndex(projectDir) {
|
|
|
142
148
|
const keywords = asList(field(block, "keywords"));
|
|
143
149
|
indexed += 1;
|
|
144
150
|
const doc = path.relative(projectDir, file).split(path.sep).join("/");
|
|
151
|
+
// METADATA ONCE PER DOC, NOT ONCE PER GLOB — kept in step with lib/ownership.mjs buildIndex(),
|
|
152
|
+
// which the parity suite pins. Re-emitting the keyword array beside every glob made the index
|
|
153
|
+
// grow with the dependency graph rather than the doc count.
|
|
145
154
|
const kw = keywords.length ? `[${keywords.join(", ")}]` : "[]";
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
155
|
+
lines.push(
|
|
156
|
+
`${doc} · ${moduleLabel} · ${status}\n ${kw}\n` + owns.map((glob) => ` ${glob}`).join("\n")
|
|
157
|
+
);
|
|
149
158
|
}
|
|
150
159
|
if (lines.length === 0) return "";
|
|
151
160
|
lines.sort();
|
|
152
161
|
const header =
|
|
153
|
-
"# Ownership index (generated) —
|
|
162
|
+
"# Ownership index (generated) — owning feature doc · module · status, then the code regions it governs.\n" +
|
|
154
163
|
"# Match the file or topic you're about to touch, then read the owning doc before changing it.\n";
|
|
155
164
|
// A doc dropped by a parse failure is indistinguishable from one that owns nothing,
|
|
156
165
|
// so report the tally: seen vs indexed is the only signal a silent skip leaves.
|
|
@@ -159,7 +168,7 @@ function buildIndex(projectDir) {
|
|
|
159
168
|
if (deprecated > 0) notes.push(`${deprecated} deprecated`);
|
|
160
169
|
if (skipped > 0) notes.push(`${skipped} with no owns:`);
|
|
161
170
|
const footer = notes.length
|
|
162
|
-
? `\n# (${indexed}/${files.length}
|
|
171
|
+
? `\n# (${indexed}/${files.length} doc(s) claim ownership - ${notes.join(", ")})`
|
|
163
172
|
: "";
|
|
164
173
|
return header + lines.join("\n") + footer;
|
|
165
174
|
}
|
|
@@ -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.
|