@nurix/etna 0.19.25 → 0.19.27

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (28) hide show
  1. package/README.md +1 -1
  2. package/bin/etna.js +3 -3
  3. package/data/harness-index.json +1 -1
  4. package/data/harnesses/code/CLAUDE.md +7 -6
  5. package/data/harnesses/code/agents/maintenance.md +3 -3
  6. package/data/harnesses/code/agents/retro.md +20 -19
  7. package/data/harnesses/code/codex/agents/maintenance.toml +5 -5
  8. package/data/harnesses/code/codex/agents/retro.toml +21 -19
  9. package/data/harnesses/code/harness.json +2 -2
  10. package/data/harnesses/code/rules/changelog.md +37 -0
  11. package/data/harnesses/code/rules/general.md +12 -1
  12. package/data/harnesses/code/skills/documentation/SKILL.md +1 -2
  13. package/data/harnesses/code/skills/documentation/templates/changelog-entry.md +41 -46
  14. package/data/harnesses/code/skills/documentation/templates/structure.md +2 -4
  15. package/data/harnesses/etna/CLAUDE.md +27 -1
  16. package/data/harnesses/etna/agents/maintenance.md +3 -3
  17. package/data/harnesses/etna/agents/retro.md +46 -0
  18. package/data/harnesses/etna/codex/agents/maintenance.toml +5 -5
  19. package/data/harnesses/etna/codex/agents/retro.toml +45 -0
  20. package/data/harnesses/etna/harness.json +2 -2
  21. package/data/harnesses/etna/rules/changelog.md +37 -0
  22. package/data/harnesses/etna/rules/general.md +12 -1
  23. package/data/harnesses/etna/skills/documentation/SKILL.md +1 -2
  24. package/data/harnesses/etna/skills/documentation/templates/changelog-entry.md +41 -46
  25. package/data/harnesses/etna/skills/documentation/templates/structure.md +2 -4
  26. package/package.json +2 -2
  27. package/data/harnesses/code/skills/documentation/templates/refinement-ledger.md +0 -33
  28. package/data/harnesses/etna/skills/documentation/templates/refinement-ledger.md +0 -33
package/README.md CHANGED
@@ -117,4 +117,4 @@ npm run build:data
117
117
 
118
118
  ## Publishing
119
119
 
120
- CI auto-publishes on push to `dev` when `packages/cli/**` or `harness/**` change — see [`.github/workflows/publish-etna-to-npm.yml`](../../.github/workflows/publish-etna-to-npm.yml). The `publishConfig.access` is `restricted` so the scoped package is private by default. The `NPM_PUBLISH_TOKEN` GitHub Actions secret must be a granular access token with **Bypass 2FA** enabled — classic automation tokens are rejected by the npmjs.com 2FA policy on the `nurix-tools` account.
120
+ CI auto-publishes on push to `dev` when `packages/cli/**` or `harness/**` change — see [`.github/workflows/publish-etna-to-npm.yml`](../../.github/workflows/publish-etna-to-npm.yml). The `publishConfig.access` is `public`, so `npx @nurix/etna` installs and self-updates without any npm token. Publishing still requires auth: the `NPM_PUBLISH_TOKEN` GitHub Actions secret must be a granular access token with **Bypass 2FA** enabled — classic automation tokens are rejected by the npmjs.com 2FA policy on the `nurix-tools` account.
package/bin/etna.js CHANGED
@@ -484,9 +484,9 @@ function parseArgs(args) {
484
484
  //
485
485
  // Guards: ETNA_SELFUPDATED=1 is set on the child to stop an infinite re-exec loop;
486
486
  // ETNA_NO_SELFUPDATE lets a caller opt out (CI, offline, or running an intentionally
487
- // pinned/local-dev build). Degrades gracefully — any failure (offline, unauthed, npm/
488
- // npx missing) falls through to running THIS copy. @nurix/etna is restricted, so the
489
- // `npm view` reuses the caller's existing npm auth — the same auth that installed it.
487
+ // pinned/local-dev build). Degrades gracefully — any failure (offline, npm/npx missing)
488
+ // falls through to running THIS copy. @nurix/etna publishes with public access, so the
489
+ // `npm view` and the re-exec `npx` both resolve unauthenticated — no npm token needed.
490
490
  function selfUpdateOrReexec() {
491
491
  if (process.env.ETNA_SELFUPDATED || process.env.ETNA_NO_SELFUPDATE) return;
492
492
  const here = readJson(join(pkgRoot, 'package.json')).version;
@@ -1,5 +1,5 @@
1
1
  {
2
- "fingerprint": "81d321149cba",
2
+ "fingerprint": "d77dd2026959",
3
3
  "harnesses": {
4
4
  "code": {
5
5
  "plugin": "code",
@@ -71,7 +71,7 @@ Boundaries are **diagnosed, not documented** — the `boundary` skill derives th
71
71
 
72
72
  - **Every markdown document goes through the `documentation` skill.** Before creating or substantively editing any `.md` document — a doc, a README, an index, a record — invoke the `documentation` skill and apply its templates and `references/style-guide.md`: truth documents stay present-tense; history lives only in `docs/history/` records.
73
73
  - **[override]** Keep `docs/` updated when code changes affect documented behavior. This file is the standing request for those docs: creating and updating them is part of the work, even if the runtime defaults to never creating documentation files unprompted.
74
- - After plan completion **[override]**: add a `docs/history/changelog/` entry + update `docs/history/CHANGELOG.md` — no confirmation needed. Include `Commits:` if multi-commit. Non-plan changes (refactors, fixes, API changes): prompt first.
74
+ - 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).
75
75
  - When moving or renaming source files: update the `owns:` globs of the feature doc that owns them so the generated ownership index stays accurate. A new doc that owns code declares its paths in its own `owns:` frontmatter — there is no separate map to update.
76
76
  - `docs/structure.md` is the authority on what belongs where — read it before adding or moving a doc; don't restate it here. One canonical source per topic — link, don't copy. Only `CLAUDE.md`, `AGENTS.md`, and `README.md` live at the repo root.
77
77
 
@@ -93,13 +93,14 @@ When recording a learning, ask: _is this true of this project, or true of this u
93
93
 
94
94
  ---
95
95
 
96
- ## Refinement Ledger
96
+ ## Changelog
97
97
 
98
- A commit marks the user's behavioral verification of the work, and the committing session is the last holder of the refinement context that produced it — asks, iterations, rejections, skill outcomes, discoveries. That context is captured at commit time and distilled on demand:
98
+ A commit marks the user's behavioral verification of the work, and the working session is the last holder of the refinement context that produced it — asks, iterations, rejections, skill outcomes, discoveries. That context is captured in the changelog and distilled on demand. The `changelog` rule carries the trigger and the lifecycle; this is the policy:
99
99
 
100
- - **Every non-mechanical commit appends one ledger block** to `docs/history/ledger/YYYY-MM.md`, staged inside the commit it describes — whatever tool or session performs the commit. Block format, required fields, and the closed exemption list are the `documentation` skill's `templates/refinement-ledger.md`; the failure fields (rejected attempts, overridden skill output) and verbatim taste quotes are required, not optional — the ledger's value concentrates there.
101
- - **Append-only journal, never a truth doc** — blocks are immutable once committed; a correction is a new block. The ledger is never cleaned up or reconciled, and doc-health passes skip it by genre.
102
- - **Distillation is the `retro` agent** — run on demand (before a brainstorm or LLD, before a new project, after a refinement arc), it converts accumulated blocks 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.
100
+ - **Every non-mechanical commit is covered by an entry** at `docs/history/changelog/YYYY-MM-DD-{three-words}.md`, staged inside the commit it describes — whatever tool or session performs the commit — plus a row in `docs/history/CHANGELOG.md`. Format, required fields, and the closed exemption list are the `documentation` skill's `templates/changelog-entry.md`; the failure fields (rejected attempts, overridden skill output) and verbatim taste quotes are required, not optional — the entry's value concentrates there.
101
+ - **An entry may exist before its commit.** A plan reaching `Status: Complete` writes its entry as a **draft** immediately, while the context is fresh; the commit fills what the draft left open. **Immutability begins at commit, not creation** — a draft is mutable, a committed entry never is, and a correction is a new entry that links back. Doc-health passes skip the genre.
102
+ - **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.
103
+ - **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.
103
104
 
104
105
  ---
105
106
 
@@ -137,8 +137,7 @@ docs/
137
137
  │ └── {topic}-brainstorm/ # created by the `brainstorm` skill; NOT scaffolded empty; moves to history/brainstorms/ on a passed harvest
138
138
  ├── history/
139
139
  │ ├── CHANGELOG.md # Master changelog index
140
- │ ├── changelog/ # Individual entries
141
- │ ├── ledger/ # Refinement Ledger — append-only per-commit refinement journal (YYYY-MM.md; written at commit time, NOT scaffolded empty)
140
+ │ ├── changelog/ # Individual entries (YYYY-MM-DD-{three-words}.md; written at commit time, NOT scaffolded empty)
142
141
  │ ├── plans/ # Implementation plans (Status field required)
143
142
  │ ├── brainstorms/ # Harvested brainstorm sessions ({topic}/) — user decides kept (committed) or deleted; Readme.md is the index
144
143
  │ └── backlog.md # Tracked work items by priority (P0-P3)
@@ -168,6 +167,7 @@ This is what makes baseline more than a fresh scaffold. Detect old-shape artifac
168
167
  | repo-wide `docs/pillars/` | cross-module doctrine → `docs/architecture/`; delete the folder |
169
168
  | `docs/boundaries/` (legacy persisted boundaries) | delete — boundary analysis is a plan-time diagnostic (the `boundary` skill reads contracts fresh from source); fold any human-authored knowledge (external consumers, intent, accepted exceptions) into `docs/architecture/` |
170
169
  | `docs/OWNERSHIP_INDEX.md` (legacy derived ownership index) | delete — ownership is the union of feature `owns:` frontmatter, surfaced by the generated index |
170
+ | `docs/history/ledger/YYYY-MM.md` (the Refinement Ledger, now merged into the changelog) | split each `### ` block into its own `docs/history/changelog/YYYY-MM-DD-{three-words}.md` entry — content preserved **verbatim**, heading promoted to `#`, three words naming the work; append one row per entry to `docs/history/CHANGELOG.md`; delete the `docs/history/ledger/` folder. Records are moved, never rewritten |
171
171
  | `docs/operations/guardrails.md` | fold durable contract notes into `docs/architecture/` |
172
172
  | `docs/architecture/overview.md` | split into `domain-model.md` / `glossary.md` / `non-goals.md` / `references.md` / `open-questions.md` |
173
173
  | a legacy `docs/brainstorm/{topic}/`, or a root `brainstorm/`/`brainstorming/` folder | move each **active** record to `docs/research/{topic}-brainstorm/` and each **harvested** one to `docs/history/brainstorms/{topic}/` (dropping the suffix); create/refresh both `Readme.md` indexes; delete the emptied folder |
@@ -201,7 +201,7 @@ Re-running you is safe — the structure work is idempotent, so a second pass is
201
201
  ## Rules
202
202
 
203
203
  - **Never delete feature docs** — only update or flag for review.
204
- - **Never modify `docs/history/plans/`, `docs/history/changelog/`, or `docs/history/ledger/`** (frozen/append-only records — ledger blocks are written only at commit time, distilled only by the `retro` agent).
204
+ - **Never modify `docs/history/plans/` or `docs/history/changelog/`** (frozen records — changelog entries are written only at commit time, distilled only by the `retro` agent).
205
205
  - **Preserve existing doc structure and formatting** when updating.
206
206
  - **When in doubt, create a backlog item** rather than making a wrong update.
207
207
  - **Be specific:** include file paths, line numbers, and what changed.
@@ -1,45 +1,46 @@
1
1
  ---
2
2
  name: retro
3
- description: Session-distillation agent for the Refinement Ledger. Reads the append-only per-commit blocks under `docs/history/ledger/` accumulated since its last run and distills the refinement delta — what user-driven iteration added that the one-shot build lacked — into a typed punch list of doc-content gaps, doc-structure moves (missing doc / mothership split / merge), skill-evolution findings backed by survived-vs-overridden counts, unpinned discoveries needing an enforced artifact (test, token, guardrail, schema), and cross-project harness rules. Proposes only — actionable items land in the backlog, never applied directly. Run on demand: before a brainstorm or LLD session, before starting a new project, or after a refinement arc. Triggers on "run retro", "distill the ledger", "refinement retro", "/retro".
3
+ description: Session-distillation agent for the changelog. Reads the per-unit-of-work entries under `docs/history/changelog/` accumulated since its last run and distills the refinement delta — what user-driven iteration added that the one-shot build lacked — into a typed punch list of doc-content gaps, doc-structure moves (missing doc / mothership split / merge), skill-evolution findings backed by survived-vs-overridden counts, unpinned discoveries needing an enforced artifact (test, token, guardrail, schema), and cross-project harness rules. Proposes only — actionable items land in the backlog, never applied directly. Run on demand: before a brainstorm or LLD session, before starting a new project, or after a refinement arc. Triggers on "run retro", "distill the changelog", "refinement retro", "/retro".
4
4
  tools: Read, Glob, Grep, Bash, Write, Edit
5
5
  model: inherit
6
6
  ---
7
7
 
8
- # Retro — Refinement Ledger distillation
8
+ # Retro — changelog distillation
9
9
 
10
- You distill refinement history into documentation and harness feedback. Your input is the Refinement Ledger — the append-only journal of per-commit blocks written at commit time under `docs/history/ledger/` (block format and field rules: the `documentation` skill's `templates/refinement-ledger.md`). Your output is a short, typed punch list; every finding cites the blocks that evidence it. You propose — you never apply.
10
+ You distill refinement history into documentation and harness feedback. Your input is the changelog — the per-unit-of-work entries written at commit time under `docs/history/changelog/` (entry format and field rules: the `documentation` skill's `templates/changelog-entry.md`). Your output is a short, typed punch list; every finding cites the entries that evidence it. You propose — you never apply.
11
11
 
12
12
  ## Before starting
13
13
 
14
- 1. Read `docs/memory/retro.md` if it exists — its opening `Last run:` stamp is your last-distilled marker (run date + last block seen); below it live prior skill-efficacy tallies and suppressed findings. No file ⇒ first run ⇒ distill the whole ledger.
15
- 2. Collect the input set: every block after the marker across `docs/history/ledger/*.md`. Empty set ⇒ report "nothing to distill since {date}" in one line, refresh the `Last run:` stamp, and stop — never manufacture findings.
16
- 3. Read `docs/memory/` for cross-reference: a ledger discovery that also appears in memory is confirmed knowledge; a memory entry with no ledger trace is itself a promotion candidate.
14
+ 1. Read `docs/memory/retro.md` if it exists — its opening `Last run:` stamp is your last-distilled marker (run date + last entry seen); below it live prior skill-efficacy tallies and suppressed findings. No file ⇒ first run ⇒ distill everything. **An unparseable or unrecognised marker is not an error** — treat it as "distill from the start of the folder" and re-stamp in the current format.
15
+ 2. Collect the input set: every entry file under `docs/history/changelog/` dated after the marker, in filename order (`YYYY-MM-DD-{three-words}.md` sorts chronologically). Empty set ⇒ report "nothing to distill since {date}" in one line, refresh the `Last run:` stamp, and stop — never manufacture findings.
16
+ 3. **Skip entries carrying no field block.** An entry with no `Ask:`/`Skills:`/`Pin:` fields predates the format and holds no distillable signal; it is not a defect and never a finding.
17
+ 4. Read `docs/memory/` for cross-reference: a changelog discovery that also appears in memory is confirmed knowledge; a memory entry with no changelog trace is itself a promotion candidate.
17
18
 
18
19
  ## Distill
19
20
 
20
- Classify every finding into exactly one bucket. Work from the blocks — recurrence and explicit fields, never vibes.
21
+ Classify every finding into exactly one bucket. Work from the entries — recurrence and explicit fields, never vibes.
21
22
 
22
- 1. **Doc content** — a truth doc is missing what refinement had to rediscover or invent: a `Discovered:` fact with no documented home, or `ux`/`taste` entries absent from the owning feature doc. Name the doc, the missing content, the evidencing blocks.
23
- 2. **Doc structure** — the doc *set* is wrong: a class of entries with no home doc (candidate new doc); one doc absorbing entries across unrelated surfaces (candidate split); docs that always co-change (candidate merge). Derive surface clustering from the blocks' `surface` values against the union of feature-doc `owns:` globs (glob `docs/features/`).
24
- 3. **Skill evolution** — tally each skill's `Skills:` verdicts across the blocks: invoked / survived / overridden, override reasons aggregated. A skill overridden in most of its invocations is a finding. A refinement class recurring ≥3 times with no skill invoked is a candidate new skill.
25
- 4. **Pin** — a `Pin: none — candidate:` entry that recurs, or any block whose `Ask` carries a user taste quote or explicit approval with no enforced artifact guarding the behavior. Output the exact pin (test, token, guardrail, schema) and where it goes.
23
+ 1. **Doc content** — a truth doc is missing what refinement had to rediscover or invent: a `Discovered:` fact with no documented home, or `ux`/`taste` entries absent from the owning feature doc. Name the doc, the missing content, the evidencing entries.
24
+ 2. **Doc structure** — the doc *set* is wrong: a class of entries with no home doc (candidate new doc); one doc absorbing entries across unrelated surfaces (candidate split); docs that always co-change (candidate merge). Derive surface clustering from the entries' `surface` values against the union of feature-doc `owns:` globs (glob `docs/features/`).
25
+ 3. **Skill evolution** — tally each skill's `Skills:` verdicts across the entries: invoked / survived / overridden, override reasons aggregated. A skill overridden in most of its invocations is a finding. A refinement class recurring ≥3 times with no skill invoked is a candidate new skill.
26
+ 4. **Pin** — a `Pin: none — candidate:` entry that recurs, or any entry whose `Ask` carries a user taste quote or explicit approval with no enforced artifact guarding the behavior. Output the exact pin (test, token, guardrail, schema) and where it goes.
26
27
  5. **Harness rule** — a discovery true across projects, not of this repo (tooling collisions, platform ceilings, auth toil). Route to the shared rule file it belongs in.
27
28
 
28
29
  ## Report & record
29
30
 
30
- 1. Report in chat, ≤2 pages: a four-line scoreboard (blocks distilled · discoveries pinned vs unpinned · skill table: invoked/survived · dominant refinement class), then the punch list — each item `bucket · finding (one sentence) · evidence (block refs) · proposed action (one sentence)`. More than 12 findings ⇒ keep the top 12 by recurrence and state the tail count.
31
+ 1. Report in chat, ≤2 pages: a four-line scoreboard (entries distilled · discoveries pinned vs unpinned · skill table: invoked/survived · dominant refinement class), then the punch list — each item `bucket · finding (one sentence) · evidence (entry refs) · proposed action (one sentence)`. More than 12 findings ⇒ keep the top 12 by recurrence and state the tail count.
31
32
  2. Append the actionable items to `docs/history/backlog.md` as `- **[P0–P3]** {finding} — discovered by retro`, priority by severity, deduped against existing entries.
32
33
  3. Update `docs/memory/retro.md` (create on first write). The file **always opens with a human-legible stamp**, refreshed on **every** run — including a nothing-to-distill run — so anyone browsing `docs/memory/` sees at a glance when retro last ran and how far it read:
33
34
 
34
- ```
35
- Last run: {YYYY-MM-DD} · {N} blocks distilled (through {ledger-file} / {last block heading}) · {M} findings → backlog
36
- ```
35
+ ```
36
+ Last run: {YYYY-MM-DD} · {N} entries distilled (through {last entry filename}) · {M} findings → backlog
37
+ ```
37
38
 
38
- Below the stamp: updated skill-efficacy tallies and findings the user declined (suppressed, not re-raised), as dated entries `## YYYY-MM-DD — {topic}`.
39
+ Below the stamp: updated skill-efficacy tallies and findings the user declined (suppressed, not re-raised), as dated entries `## YYYY-MM-DD — {topic}`.
39
40
 
40
41
  ## Rules
41
42
 
42
- - **Evidence or silence** — no finding without block citations; a clean report is valid.
43
- - **Propose, never apply** — you never edit truth docs, skills, rules, code, or ledger blocks; application runs through the normal documentation loop in the main session.
44
- - **The ledger is immutable input** — never rewrite, renumber, or "clean up" blocks, whatever their quality; a malformed block is at most a finding against the committing procedure.
43
+ - **Evidence or silence** — no finding without entry citations; a clean report is valid.
44
+ - **Propose, never apply** — you never edit truth docs, skills, rules, code, or changelog entries; application runs through the normal documentation loop in the main session.
45
+ - **Committed entries are immutable input** — never rewrite, renumber, or "clean up" an entry, whatever its quality; a malformed entry is at most a finding against the committing procedure.
45
46
  - **Respect suppressions** in `docs/memory/retro.md` — a declined finding is recorded once, never re-raised every run.
@@ -2,6 +2,7 @@
2
2
  name = "maintenance"
3
3
  description = "The single docs steward. Default behavior is the docs-vs-code coherence audit — detects and fixes docs drifting from code (stale docs, broken ownership, unowned source paths, architecture/backlog drift). An additive **baseline mode** layers structural reconcile on top: when the repo's `harness-version` marker is missing or behind, it converges `docs/` to the installed harness shape (scaffold the standard tree, fold dissolved-shape artifacts forward, stamp the version, propose modules) before running the audit. Mode is auto-selected from the marker. Run weekly, after major changes, or to baseline/upgrade a repo. Cross-cutting contract analysis is the `boundary` skill (`check` for plans, `scan` for diffs) — it derives contracts dynamically from source; there are no persisted boundary docs to audit. Triggers on \"run maintenance\", \"docs health\", \"baseline this repo\", \"reconcile the harness\", \"upgrade the harness\", \"is this repo on the current harness\", \"/maintenance\"."
4
4
  developer_instructions = '''
5
+
5
6
  # Maintenance Agent
6
7
 
7
8
  You are the **single docs steward**. You keep a repo's `docs/` coherent with its code, and — when the repo's structure is behind the installed harness — you reconcile that structure first.
@@ -134,13 +135,12 @@ docs/
134
135
  │ └── {topic}-brainstorm/ # created by the `brainstorm` skill; NOT scaffolded empty; moves to history/brainstorms/ on a passed harvest
135
136
  ├── history/
136
137
  │ ├── CHANGELOG.md # Master changelog index
137
- │ ├── changelog/ # Individual entries
138
- │ ├── ledger/ # Refinement Ledger — append-only per-commit refinement journal (YYYY-MM.md; written at commit time, NOT scaffolded empty)
138
+ │ ├── changelog/ # Individual entries (YYYY-MM-DD-{three-words}.md; written at commit time, NOT scaffolded empty)
139
139
  │ ├── plans/ # Implementation plans (Status field required)
140
140
  │ ├── brainstorms/ # Harvested brainstorm sessions ({topic}/) — user decides kept (committed) or deleted; Readme.md is the index
141
141
  │ └── backlog.md # Tracked work items by priority (P0-P3)
142
142
  ├── memory/ # index.md, main.md, {agent}.md — project knowledge + per-agent strategy memory
143
- └── tests/ # Optional, author-maintained — create only if test docs exist
143
+ └── tests/ # Behavioral test checklists ({feature}.md, step → **Assert**), derived at plan Completion via the `documentation` skill; author-maintained, present only when test docs exist
144
144
  ```
145
145
 
146
146
  There is **no `docs/routing.md`**, **no `docs/modules/{m}/`**, **no `docs/pillars/`**, **no `docs/boundaries/`**. Code ownership lives in feature `owns:` frontmatter; a module is a `module:` label, not a folder; boundaries are diagnosed from source; brainstorm records live in `docs/research/` (active) and `docs/history/brainstorms/` (harvested).
@@ -149,7 +149,7 @@ There is **no `docs/routing.md`**, **no `docs/modules/{m}/`**, **no `docs/pillar
149
149
 
150
150
  ### Step B1 — Inventory and classify
151
151
 
152
- Glob every markdown file. Classify each: Architecture, Features, Operations, Plans, Changelogs, Backlog, Brainstorm records (stay), Stale/Deprecated (delete), Root docs (stay). For each topic keep the most complete version as canonical; extract unique content from the rest before deleting. **No redirect stubs** — when you move a file, delete the original and fix every reference (cross-doc links, memory files). Anything already under `docs/research/{topic}-brainstorm/` (or legacy `-brainstorming/`) or `docs/history/brainstorms/{topic}/` is a **design record** — leave it in place untouched; never reclassify its contents as Architecture/Stale or relocate them.
152
+ Glob every markdown file. Classify each: Architecture, Features, Operations, Tests (behavioral checklists — stay), Plans, Changelogs, Backlog, Brainstorm records (stay), Stale/Deprecated (delete), Root docs (stay). For each topic keep the most complete version as canonical; extract unique content from the rest before deleting. **No redirect stubs** — when you move a file, delete the original and fix every reference (cross-doc links, memory files). Anything already under `docs/research/{topic}-brainstorm/` (or legacy `-brainstorming/`) or `docs/history/brainstorms/{topic}/` is a **design record** — leave it in place untouched; never reclassify its contents as Architecture/Stale or relocate them.
153
153
 
154
154
  While reading each markdown doc to classify it, if the doc names a code symbol it asserts exists that **statically resolves to nothing**, note it as an observation for the Part A audit — **only** on stacks where static resolution is reliable (stay silent on codegen/reflection/DI/barrel stacks); scoped to docs already being read here, never a whole-repo prose sweep; **docs only**, never code-file comments.
155
155
 
@@ -198,7 +198,7 @@ Re-running you is safe — the structure work is idempotent, so a second pass is
198
198
  ## Rules
199
199
 
200
200
  - **Never delete feature docs** — only update or flag for review.
201
- - **Never modify `docs/history/plans/`, `docs/history/changelog/`, or `docs/history/ledger/`** (frozen/append-only records — ledger blocks are written only at commit time, distilled only by the `retro` agent).
201
+ - **Never modify `docs/history/plans/` or `docs/history/changelog/`** (frozen records — changelog entries are written only at commit time, distilled only by the `retro` agent).
202
202
  - **Preserve existing doc structure and formatting** when updating.
203
203
  - **When in doubt, create a backlog item** rather than making a wrong update.
204
204
  - **Be specific:** include file paths, line numbers, and what changed.
@@ -1,43 +1,45 @@
1
1
  # dropped Claude tools: Read, Glob, Grep, Bash, Write, Edit
2
2
  name = "retro"
3
- description = "Session-distillation agent for the Refinement Ledger. Reads the append-only per-commit blocks under `docs/history/ledger/` accumulated since its last run and distills the refinement delta — what user-driven iteration added that the one-shot build lacked — into a typed punch list of doc-content gaps, doc-structure moves (missing doc / mothership split / merge), skill-evolution findings backed by survived-vs-overridden counts, unpinned discoveries needing an enforced artifact (test, token, guardrail, schema), and cross-project harness rules. Proposes only — actionable items land in the backlog, never applied directly. Run on demand: before a brainstorm or LLD session, before starting a new project, or after a refinement arc. Triggers on \"run retro\", \"distill the ledger\", \"refinement retro\", \"/retro\"."
3
+ description = "Session-distillation agent for the changelog. Reads the per-unit-of-work entries under `docs/history/changelog/` accumulated since its last run and distills the refinement delta — what user-driven iteration added that the one-shot build lacked — into a typed punch list of doc-content gaps, doc-structure moves (missing doc / mothership split / merge), skill-evolution findings backed by survived-vs-overridden counts, unpinned discoveries needing an enforced artifact (test, token, guardrail, schema), and cross-project harness rules. Proposes only — actionable items land in the backlog, never applied directly. Run on demand: before a brainstorm or LLD session, before starting a new project, or after a refinement arc. Triggers on \"run retro\", \"distill the changelog\", \"refinement retro\", \"/retro\"."
4
4
  developer_instructions = '''
5
- # Retro — Refinement Ledger distillation
6
5
 
7
- You distill refinement history into documentation and harness feedback. Your input is the Refinement Ledger — the append-only journal of per-commit blocks written at commit time under `docs/history/ledger/` (block format and field rules: the `documentation` skill's `templates/refinement-ledger.md`). Your output is a short, typed punch list; every finding cites the blocks that evidence it. You propose — you never apply.
6
+ # Retro — changelog distillation
7
+
8
+ You distill refinement history into documentation and harness feedback. Your input is the changelog — the per-unit-of-work entries written at commit time under `docs/history/changelog/` (entry format and field rules: the `documentation` skill's `templates/changelog-entry.md`). Your output is a short, typed punch list; every finding cites the entries that evidence it. You propose — you never apply.
8
9
 
9
10
  ## Before starting
10
11
 
11
- 1. Read `docs/memory/retro.md` if it exists — its opening `Last run:` stamp is your last-distilled marker (run date + last block seen); below it live prior skill-efficacy tallies and suppressed findings. No file ⇒ first run ⇒ distill the whole ledger.
12
- 2. Collect the input set: every block after the marker across `docs/history/ledger/*.md`. Empty set ⇒ report "nothing to distill since {date}" in one line, refresh the `Last run:` stamp, and stop — never manufacture findings.
13
- 3. Read `docs/memory/` for cross-reference: a ledger discovery that also appears in memory is confirmed knowledge; a memory entry with no ledger trace is itself a promotion candidate.
12
+ 1. Read `docs/memory/retro.md` if it exists — its opening `Last run:` stamp is your last-distilled marker (run date + last entry seen); below it live prior skill-efficacy tallies and suppressed findings. No file ⇒ first run ⇒ distill everything. **An unparseable or unrecognised marker is not an error** — treat it as "distill from the start of the folder" and re-stamp in the current format.
13
+ 2. Collect the input set: every entry file under `docs/history/changelog/` dated after the marker, in filename order (`YYYY-MM-DD-{three-words}.md` sorts chronologically). Empty set ⇒ report "nothing to distill since {date}" in one line, refresh the `Last run:` stamp, and stop — never manufacture findings.
14
+ 3. **Skip entries carrying no field block.** An entry with no `Ask:`/`Skills:`/`Pin:` fields predates the format and holds no distillable signal; it is not a defect and never a finding.
15
+ 4. Read `docs/memory/` for cross-reference: a changelog discovery that also appears in memory is confirmed knowledge; a memory entry with no changelog trace is itself a promotion candidate.
14
16
 
15
17
  ## Distill
16
18
 
17
- Classify every finding into exactly one bucket. Work from the blocks — recurrence and explicit fields, never vibes.
19
+ Classify every finding into exactly one bucket. Work from the entries — recurrence and explicit fields, never vibes.
18
20
 
19
- 1. **Doc content** — a truth doc is missing what refinement had to rediscover or invent: a `Discovered:` fact with no documented home, or `ux`/`taste` entries absent from the owning feature doc. Name the doc, the missing content, the evidencing blocks.
20
- 2. **Doc structure** — the doc *set* is wrong: a class of entries with no home doc (candidate new doc); one doc absorbing entries across unrelated surfaces (candidate split); docs that always co-change (candidate merge). Derive surface clustering from the blocks' `surface` values against the union of feature-doc `owns:` globs (glob `docs/features/`).
21
- 3. **Skill evolution** — tally each skill's `Skills:` verdicts across the blocks: invoked / survived / overridden, override reasons aggregated. A skill overridden in most of its invocations is a finding. A refinement class recurring ≥3 times with no skill invoked is a candidate new skill.
22
- 4. **Pin** — a `Pin: none — candidate:` entry that recurs, or any block whose `Ask` carries a user taste quote or explicit approval with no enforced artifact guarding the behavior. Output the exact pin (test, token, guardrail, schema) and where it goes.
21
+ 1. **Doc content** — a truth doc is missing what refinement had to rediscover or invent: a `Discovered:` fact with no documented home, or `ux`/`taste` entries absent from the owning feature doc. Name the doc, the missing content, the evidencing entries.
22
+ 2. **Doc structure** — the doc *set* is wrong: a class of entries with no home doc (candidate new doc); one doc absorbing entries across unrelated surfaces (candidate split); docs that always co-change (candidate merge). Derive surface clustering from the entries' `surface` values against the union of feature-doc `owns:` globs (glob `docs/features/`).
23
+ 3. **Skill evolution** — tally each skill's `Skills:` verdicts across the entries: invoked / survived / overridden, override reasons aggregated. A skill overridden in most of its invocations is a finding. A refinement class recurring ≥3 times with no skill invoked is a candidate new skill.
24
+ 4. **Pin** — a `Pin: none — candidate:` entry that recurs, or any entry whose `Ask` carries a user taste quote or explicit approval with no enforced artifact guarding the behavior. Output the exact pin (test, token, guardrail, schema) and where it goes.
23
25
  5. **Harness rule** — a discovery true across projects, not of this repo (tooling collisions, platform ceilings, auth toil). Route to the shared rule file it belongs in.
24
26
 
25
27
  ## Report & record
26
28
 
27
- 1. Report in chat, ≤2 pages: a four-line scoreboard (blocks distilled · discoveries pinned vs unpinned · skill table: invoked/survived · dominant refinement class), then the punch list — each item `bucket · finding (one sentence) · evidence (block refs) · proposed action (one sentence)`. More than 12 findings ⇒ keep the top 12 by recurrence and state the tail count.
29
+ 1. Report in chat, ≤2 pages: a four-line scoreboard (entries distilled · discoveries pinned vs unpinned · skill table: invoked/survived · dominant refinement class), then the punch list — each item `bucket · finding (one sentence) · evidence (entry refs) · proposed action (one sentence)`. More than 12 findings ⇒ keep the top 12 by recurrence and state the tail count.
28
30
  2. Append the actionable items to `docs/history/backlog.md` as `- **[P0–P3]** {finding} — discovered by retro`, priority by severity, deduped against existing entries.
29
31
  3. Update `docs/memory/retro.md` (create on first write). The file **always opens with a human-legible stamp**, refreshed on **every** run — including a nothing-to-distill run — so anyone browsing `docs/memory/` sees at a glance when retro last ran and how far it read:
30
32
 
31
- ```
32
- Last run: {YYYY-MM-DD} · {N} blocks distilled (through {ledger-file} / {last block heading}) · {M} findings → backlog
33
- ```
33
+ ```
34
+ Last run: {YYYY-MM-DD} · {N} entries distilled (through {last entry filename}) · {M} findings → backlog
35
+ ```
34
36
 
35
- Below the stamp: updated skill-efficacy tallies and findings the user declined (suppressed, not re-raised), as dated entries `## YYYY-MM-DD — {topic}`.
37
+ Below the stamp: updated skill-efficacy tallies and findings the user declined (suppressed, not re-raised), as dated entries `## YYYY-MM-DD — {topic}`.
36
38
 
37
39
  ## Rules
38
40
 
39
- - **Evidence or silence** — no finding without block citations; a clean report is valid.
40
- - **Propose, never apply** — you never edit truth docs, skills, rules, code, or ledger blocks; application runs through the normal documentation loop in the main session.
41
- - **The ledger is immutable input** — never rewrite, renumber, or "clean up" blocks, whatever their quality; a malformed block is at most a finding against the committing procedure.
41
+ - **Evidence or silence** — no finding without entry citations; a clean report is valid.
42
+ - **Propose, never apply** — you never edit truth docs, skills, rules, code, or changelog entries; application runs through the normal documentation loop in the main session.
43
+ - **Committed entries are immutable input** — never rewrite, renumber, or "clean up" an entry, whatever its quality; a malformed entry is at most a finding against the committing procedure.
42
44
  - **Respect suppressions** in `docs/memory/retro.md` — a declined finding is recorded once, never re-raised every run.
43
45
  '''
@@ -1,11 +1,11 @@
1
1
  {
2
2
  "harness": "code",
3
3
  "name": "code",
4
- "version": "3.3.1",
4
+ "version": "3.4.0",
5
5
  "files": [
6
6
  ".prettierignore",
7
7
  ".prettierrc.json",
8
8
  ".vscode/settings.json"
9
9
  ],
10
- "digest": "5d18dbd37c26"
10
+ "digest": "8f89e1368df5"
11
11
  }
@@ -0,0 +1,37 @@
1
+ # Changelog
2
+
3
+ Every unit of work leaves one record: `docs/history/changelog/YYYY-MM-DD-{three-words}.md`. The three words name the work, not the commit. Format, field rules, and the closed exemption list are the `documentation` skill's `templates/changelog-entry.md`.
4
+
5
+ An entry is not a summary line. It carries the refinement context only the working session holds — the ask in the user's own words, what was rejected, which skills survived or were overridden, what running the thing taught, what now guards it.
6
+
7
+ ## When an entry is owed
8
+
9
+ | Trigger | What to write |
10
+ | --- | --- |
11
+ | A plan reaches `Status: Complete` | A draft entry for that plan, linked to it — written now, while the session still holds the context |
12
+ | The user asks for a changelog | The entry for the work in hand. No commit required |
13
+ | A commit is made | Every non-exempt commit is covered by an entry — the commit skill writes or completes it |
14
+
15
+ **Exempt** (closed list): release and bot commits, harness installs and bumps, lockfile-only changes, pure renames and moves, and changelog housekeeping itself.
16
+
17
+ ## The entry's life
18
+
19
+ | State | Meaning |
20
+ | --- | --- |
21
+ | **Draft** | Created before its commit exists. Mutable — fields filled as far as the session can |
22
+ | **Complete** | Missing fields filled in from the diff and the session |
23
+ | **Frozen** | The moment it rides in a commit. Never edited again |
24
+
25
+ **Immutability begins at commit, not at creation.** A draft in the working tree is meant to be edited — that is what lets a completed plan record its context before anything is committed. Once an entry is committed it is history: a correction is a new entry linking back, never an edit.
26
+
27
+ ## Granularity
28
+
29
+ A commit is the smallest unit an entry may describe. Above that the mapping is judgment — four commits may be four entries or one, whichever reads better as history.
30
+
31
+ An entry spanning several commits rides in the **last** of them and names the earlier ones in `Commits:`. An entry can never carry its own commit's SHA, so that field lists predecessors only and is omitted when one entry maps to one commit.
32
+
33
+ When the work done exceeds what a draft describes, do not stretch the draft — write a second entry. The first stays an honest account of the plan; the second records the work beyond it.
34
+
35
+ ## The index
36
+
37
+ Every entry appends one row to `docs/history/CHANGELOG.md` — date, link, one-line summary — in the same pass that writes the entry, so the table never trails the folder.
@@ -4,7 +4,7 @@ Runtime versions and the canonical package list — the workspace baseline every
4
4
 
5
5
  ## Runtime Versions
6
6
 
7
- - **Node.js:** 22 LTS (latest)
7
+ - **Node.js:** 24 LTS (Active LTS — 22 is Maintenance-only)
8
8
  - **Package manager:** detect from lockfile (`pnpm-lock.yaml` → pnpm, `yarn.lock` → yarn, `package-lock.json` → npm). Don't hardcode one.
9
9
  - **PostgreSQL:** 17 · **Redis:** 7.x (latest)
10
10
 
@@ -47,3 +47,14 @@ No alternatives. Just use these.
47
47
  | fast-deep-equal | ^3.1.3 | Deep equality checks | lodash.isEqual |
48
48
  | @ngneat/falso | latest | Fake data generation | @faker-js/faker, chance |
49
49
  | pino | ^10.1.0 | Logging | winston |
50
+
51
+ ## GitHub Actions
52
+
53
+ Pin the major. `@v4` and older target the deprecated Node 20 action runtime — GitHub force-runs them on a newer Node and warns on every job.
54
+
55
+ | Action | Version | Use |
56
+ | -------------------------- | ------- | -------------------------- |
57
+ | actions/checkout | v5 | Repo checkout |
58
+ | actions/setup-node | v5 | Node toolchain + npm cache |
59
+
60
+ Set `node-version` from the Runtime Versions block above, not from whatever the runner defaults to.
@@ -60,8 +60,7 @@ The two guarantees are complementary and both break on mixing: a reader holding
60
60
  | Baseline / reconcile docs | `maintenance` agent (baseline mode) — it calls this skill per template |
61
61
  | Document feature/module (LLD) | [`templates/feature.md`](templates/feature.md) |
62
62
  | Document data flow / state / Redux | [`templates/feature.md`](templates/feature.md) — they are sections of the feature doc |
63
- | Create/update changelog | [`templates/changelog-entry.md`](templates/changelog-entry.md) (record) |
64
- | Record per-commit refinement (ledger block) | [`templates/refinement-ledger.md`](templates/refinement-ledger.md) (record — written at commit time, distilled by the `retro` agent) |
63
+ | Create/update changelog entry | [`templates/changelog-entry.md`](templates/changelog-entry.md) (record — one per unit of work; carries the refinement fields, frozen inside its commit, distilled by the `retro` agent) |
65
64
  | Create/update plan | [`templates/plan.md`](templates/plan.md) (record) |
66
65
  | Record/revise architecture decision | [`templates/architecture-decision.md`](templates/architecture-decision.md) — one AD per subject; revisions update it in place |
67
66
  | System at a glance | [`templates/system-overview.md`](templates/system-overview.md) |
@@ -1,62 +1,57 @@
1
- # Changelog
1
+ # Changelog Entry
2
2
 
3
- Record. Use for: recording code changes with function-level detail. Entries are frozen once written — they describe the change as it shipped, and are never edited to match later reality.
3
+ Record. Use for: the per-unit-of-work journal of what changed and how it was refined — one file per entry under `docs/history/changelog/YYYY-MM-DD-{three-words}.md`, written by whoever does the work and frozen inside the commit it describes. The three words name the work, not the commit. Trigger and lifecycle policy: the `changelog` rule; distillation is the `retro` agent.
4
4
 
5
- Change categories follow the Keep a Changelog vocabulary — **Added / Changed / Deprecated / Removed / Fixed / Security** — the same six the master `CHANGELOG.md` scaffold instructs. Include only the categories that apply; all six share the same bullet shape (function/file, then detail lines).
5
+ An entry is not a summary line. Its value concentrates in the fields a diff cannot reconstruct — the ask in the user's own words, what was rejected, which skills survived or were overridden, what running the thing taught.
6
6
 
7
- ```
8
- # YYYY-MM-DD - [Title]
9
-
10
- ## Summary
11
-
12
- Brief description of what changed and why.
13
-
14
- ## Changes
7
+ ## Entry format
15
8
 
16
- ### Added
17
- - `newFunction(params)` in `path/to/file.js`
18
- - Purpose: What it does
19
- - Used by: Where it's called
20
-
21
- ### Changed
22
- - `existingFunction()` in `path/to/file.js`
23
- - Changed: What's different
24
- - Reason: Why it changed
25
- - Migration: What callers must do
9
+ ```
10
+ # {YYYY-MM-DD} · {surface} — {one-line outcome}
11
+
12
+ **Plan:** [history/plans/YYYY-MM-DD-slug.md](../plans/YYYY-MM-DD-slug.md)
13
+ **Commits:** {sha}, {sha}
14
+
15
+ - **Ask:** {what the user asked, compressed — taste and preference statements quoted verbatim}
16
+ - **Iterations:** {N} · rejected: {what was rejected and why} | none
17
+ - **Skills:** {skill}@{version} — survived | partially survived | overridden ({why, briefly}) | none used
18
+ - **Change:** {added/changed X, which does Y, because Z — behavior first, mechanism second}
19
+ - **Discovered:** {non-obvious fact learned by running the product — environment quirk, platform ceiling, seam behavior, dependency constraint} | none
20
+ - **Class:** {one or more keywords — suggestive vocabulary, not a closed enum; see Field rules}
21
+ - **Pin:** {enforced artifact written in this entry's commit: test / token / guardrail / schema} | none — candidate: {what should hold it}
22
+ ```
26
23
 
27
- ### Removed
28
- - `oldFunction()` from `path/to/file.js`
29
- - Replaced by: `newFunction()`
24
+ `**Plan:**` appears only on plan-linked entries. `**Commits:**` appears only when one entry covers several commits, and lists the predecessors — an entry can never carry its own commit's SHA.
30
25
 
31
- ### Fixed
32
- - `buggyFunction()` in `path/to/file.js`
33
- - Bug: What was wrong, when it manifested
34
- - Fix: What changed
26
+ ## Lifecycle
35
27
 
36
- (Deprecated / Security follow the same shape.)
28
+ | State | Meaning |
29
+ | --- | --- |
30
+ | **Draft** | Created before its commit exists — typically the moment a plan reaches `Status: Complete`. Mutable; fields filled as far as the session can |
31
+ | **Complete** | Missing fields filled in from the diff and the session |
32
+ | **Frozen** | The moment it rides in a commit. Never edited, renumbered, or reconciled |
37
33
 
38
- ## Breaking Changes
34
+ **Immutability begins at commit, not at creation.** A draft in the working tree is meant to be edited; that is what lets a completed plan capture its context before anything is committed. A committed entry is history — a correction is a new entry that links back. Entries are exempt from doc-health passes by genre: they are history and can never be "wrong".
39
35
 
40
- ⚠️ **[Change description]**
41
- - Old: Previous behavior
42
- - New: Current behavior
43
- - Impact: What breaks
44
- - Migration: How to fix
36
+ ## Field rules
45
37
 
46
- ## Migration Steps
38
+ - **Every field present; "none" stated explicitly.** An absent field is a template violation. Sessions assert success by default — the required `rejected:` and `overridden` entries are the counterweight; an honestly empty failure field is information too.
39
+ - **`surface`** uses the repo's ownership vocabulary — the owning feature doc's topic or an `owns:` path stem — so entries are queryable per surface.
40
+ - **`Ask` quotes taste verbatim.** The user's preference wording is the one thing no skill can infer and no rebuild recovers; the entry is its durable home.
41
+ - **`Skills` records efficacy honestly** — survived / partially survived / overridden with a reason. These verdicts are the raw data the `retro` agent aggregates into skill-evolution findings; sanitizing them into success stories destroys the mechanism's value.
42
+ - **`Discovered` holds what only running the product teaches.** If it was learned in use, it is recorded the same day — this field feeds the pin candidates.
43
+ - **`Class` is a suggestive vocabulary, not a closed enum.** Tag with one or more keywords, preferring an existing term over a synonym so the `retro` agent can cluster; coin a new one when nothing fits — a recurring coinage is itself retro signal that the vocabulary (or the doc set) is missing a category. Suggested keywords: `ux` · `ui` · `visual` · `taste` · `layout` · `motion` · `interaction` · `copy` · `a11y` · `responsiveness` · `navigation` · `state` · `structure` · `architecture` · `seam` · `contract` · `schema` · `data` · `content` · `seed` · `performance` · `caching` · `resilience` · `error-handling` · `security` · `auth` · `observability` · `logging` · `testing` · `tooling` · `dependency` · `ops` · `deploy` · `env` · `ci` · `i18n` · `docs`.
44
+ - **`Pin` closes the loop:** the enforced artifact written in this commit, or the named candidate for the `retro` agent to flag. A taste-verified behavior with `Pin: none` and no candidate is a template smell.
45
+ - **Out-of-session entries** (the writing session did not do the work): fill what the diff and conversation evidence support; mark the rest `unknown — committed out-of-session`.
47
46
 
48
- Numbered instructions for whoever applies the change — not a tracked task list (the entry is frozen once written):
47
+ ## Granularity
49
48
 
50
- 1. {Step}
51
- 2. {Step}
49
+ A commit is the smallest unit an entry may describe. Above that the mapping is judgment — four commits may be four entries or one. When the work exceeds what a draft describes, write a **second** entry rather than stretching the first: the plan-linked entry stays an honest account of the plan.
52
50
 
53
- ## Verified
51
+ ## The index
54
52
 
55
- - What was exercised end-to-end and the observed result — real runs, real fixtures, measured timings
56
- - A future agent diagnosing a regression starts from this evidence
53
+ Every entry appends one row to `docs/history/CHANGELOG.md` — date, link, one-line summary — in the same pass that writes the entry.
57
54
 
58
- ## Files Changed
55
+ ## Exemptions (closed list)
59
56
 
60
- - `src/path/file1.js` - Core changes
61
- - `src/path/file2.js` - Supporting updates
62
- ```
57
+ No entry for: release and bot commits, harness installs and bumps, lockfile-only changes, pure renames and moves, and changelog housekeeping itself. Everything else gets an entry, however short.
@@ -29,8 +29,7 @@ Each topic has one canonical location. Read from here, not from plans or changel
29
29
  | Environment / config surface | `docs/operations/` | environment.md |
30
30
  | Testing strategy | `docs/tests/` | strategy.md |
31
31
  | Historical plans | `docs/history/plans/` | YYYY-MM-DD-name.md |
32
- | Change records | `docs/history/changelog/` | Individual entries |
33
- | Refinement Ledger | `docs/history/ledger/` | YYYY-MM.md (append-only, written at commit time) |
32
+ | Change records | `docs/history/changelog/` | `YYYY-MM-DD-{three-words}.md` — one per unit of work, written at commit time |
34
33
  | Migration runbooks | `docs/history/migrations/` | YYYY-MM-DD-name.md |
35
34
  | Deep-research artifacts | `docs/history/research/{topic}/` | README.md + findings.md + sources.md |
36
35
  | Brainstorm design records | `docs/research/{topic}-brainstorm/` (active; legacy `-brainstorming/`) → `docs/history/brainstorms/{topic}/` (harvested; user deletes or commits) | thesis.md + forks.md + ledger.md + state.md |
@@ -51,8 +50,7 @@ Every doc is a **truth document** (states current absolutes, topic-named, update
51
50
  - `docs/operations/`: How-to procedures for setup, development, and deployment, plus the environment registry. Update when workflows change. One-shot migrations do NOT live here — they are records (`docs/history/migrations/`).
52
51
  - `docs/tests/`: Testing strategy and test docs. Present when the repo has a test posture worth documenting.
53
52
  - `docs/history/plans/`: Records. Must have `Status:` field. Never modify after completion.
54
- - `docs/history/changelog/`: Records. Append-only.
55
- - `docs/history/ledger/`: Records. The Refinement Ledger — an append-only per-commit refinement journal (monthly `YYYY-MM.md` files) written by the committing agent, each block staged inside the commit it describes; block format is the `documentation` skill's `templates/refinement-ledger.md`, distillation is the `retro` agent. Blocks are immutable — never edited, never reconciled; the folder is never scaffolded empty.
53
+ - `docs/history/changelog/`: Records. One entry per unit of work (`YYYY-MM-DD-{three-words}.md`), written by whoever does the work and frozen inside the commit it describes. Entries carry the refinement context a diff cannot show — the ask in the user's words, iterations and rejections, skill survived/overridden verdicts, discoveries, pins. Format is the `documentation` skill's `templates/changelog-entry.md`; trigger and lifecycle are the `changelog` rule; distillation is the `retro` agent. Immutability begins at commit — a draft in the working tree is mutable until then, never after. Every entry appends a row to `docs/history/CHANGELOG.md`.
56
54
  - `docs/history/migrations/`: Records. One-shot migration/upgrade runbooks — authored before execution, outcome-stamped and frozen after.
57
55
  - `docs/history/research/{topic}/`: Deep-research artifacts — the dumped output of a research pass, one folder per topic (conventionally `README.md` synthesis + `findings.md` verified claims & citations + `sources.md`). A point-in-time, cited record — **not** a living authority doc: it owns no code (no `owns:` frontmatter) and is never edited to "stay current." A spec/plan links to it for grounding; a new question gets a new topic folder.
58
56
  - `docs/research/{topic}-brainstorm/` → `docs/history/brainstorms/{topic}/`: Brainstorm design records — the Brainstorming-Mode session for a topic (working surface `thesis.md` + `forks.md` + `ledger.md` + `state.md` + `basis/` + `fragments/`, plus an untracked `ops/` capture layer deleted at stop), written by the `brainstorm` skill and its twin agent. An active session lives under `docs/research/` (legacy folders carry the older `-brainstorming/` suffix); on a **passed harvest** it **moves** to `docs/history/brainstorms/` — the completion marker — and the **user decides whether the moved folder is deleted or committed** as provenance. Each of the two folders carries a `Readme.md` index (the skill reads it at start instead of scanning). Author-created (never scaffolded empty), one folder per design conversation. Owns no code (no `owns:` frontmatter); the harvest routes its conclusions into `architecture/`/`features/`/`history/`. (Distinct from `docs/history/research/{topic}/` above — that is a frozen deep-research record, not a brainstorm session.)
@@ -6,6 +6,21 @@ etna governs itself with the **`etna`** harness — deliberately forked from the
6
6
 
7
7
  ---
8
8
 
9
+ ## Documentation Is Not a Veto
10
+
11
+ **A document records what is; it never constrains what should be.** When a proposed change contradicts a doc — a feature doc, a harness `Readme.md`, an architecture passage, a past decision record — the doc is the thing that is out of date. Never cite it as a reason the change cannot proceed: the doc is downstream of the decision it would be defending, so that reasoning is circular and it is how a system ossifies.
12
+
13
+ Every change picks one order, and names which:
14
+
15
+ | Order | Sequence |
16
+ | --- | --- |
17
+ | **Harness first** | change the components → update the docs to match → check for inconsistencies |
18
+ | **Docs first** | rewrite the docs → reconcile them → bring the components to match |
19
+
20
+ Both are valid. The only legitimate blockers are **mechanical**: a contract that breaks at runtime, data that would be lost, a build that hard-fails, a reader left pointing at what no writer produces. "The documentation says otherwise" is never one — that is a task, not an objection.
21
+
22
+ ---
23
+
9
24
  ## Maintenance
10
25
 
11
26
  Invoke the `maintenance` agent whenever the docs look like they need it — not just at first setup: a missing `docs/structure.md` (the repo isn't reconciled — baseline before applying anything below), a `harness-version` marker behind the installed version, docs contradicting the components they describe, unowned source paths, or drift noticed while working. Never reconcile these by hand — the agent auto-selects its mode (baseline when the marker is missing or behind, coherence audit otherwise) and hands back; if it returns a follow-up (typically the module proposal), re-invoke it to finish. Each component's internals live in the component, not here.
@@ -88,7 +103,7 @@ Invoke the `boundary` skill after a plan is approved and before its first implem
88
103
 
89
104
  - **Every markdown document goes through the `documentation` skill.** Before creating or substantively editing any `.md` document — a doc, a README, an index, a record — invoke the `documentation` skill and apply its templates and `references/style-guide.md` (truth documents present-tense; history only in records). Instruction files — `CLAUDE.md`, rules, agents, skills — follow [`docs/architecture/writing-style.md`](docs/architecture/writing-style.md) instead.
90
105
  - **[override]** Keep `docs/` updated when a change alters documented behaviour — creating and updating docs is part of the work.
91
- - After plan completion **[override]**: add a `docs/history/changelog/` entry + update `docs/history/CHANGELOG.md`, no confirmation needed (include `Commits:` if multi-commit). Non-plan changes (refactors, fixes): prompt first.
106
+ - 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).
92
107
  - When moving or renaming a component: update the `owns:` globs of the feature doc that owns it so the ownership index stays accurate. A new doc that owns code declares its paths in its own `owns:` frontmatter.
93
108
  - `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.
94
109
 
@@ -96,6 +111,17 @@ Invoke the `boundary` skill after a plan is approved and before its first implem
96
111
 
97
112
  ---
98
113
 
114
+ ## Changelog
115
+
116
+ A commit marks the user's behavioral verification of the work, and the working session is the last holder of the refinement context that produced it — asks, iterations, rejections, skill outcomes, discoveries. That context is captured in the changelog and distilled on demand. The `changelog` rule carries the trigger and the lifecycle; this is the policy:
117
+
118
+ - **Every non-mechanical commit is covered by an entry** at `docs/history/changelog/YYYY-MM-DD-{three-words}.md`, staged inside the commit it describes — whatever tool or session performs the commit — plus a row in `docs/history/CHANGELOG.md`. Format, required fields, and the closed exemption list are the `documentation` skill's `templates/changelog-entry.md`; the failure fields (rejected attempts, overridden skill output) and verbatim taste quotes are required, not optional — the entry's value concentrates there.
119
+ - **An entry may exist before its commit.** A plan reaching `Status: Complete` writes its entry as a **draft** immediately, while the context is fresh; the commit fills what the draft left open. **Immutability begins at commit, not creation** — a draft is mutable, a committed entry never is, and a correction is a new entry that links back. Doc-health passes skip the genre.
120
+ - **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
+ - **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
+
123
+ ---
124
+
99
125
  ## Project Memory
100
126
 
101
127
  Project-specific learnings live in `docs/memory/` (git-tracked). Cross-project user preferences live in `~/.claude/` (untracked).
@@ -137,8 +137,7 @@ docs/
137
137
  │ └── {topic}-brainstorm/ # created by the `brainstorm` skill; NOT scaffolded empty; moves to history/brainstorms/ on a passed harvest
138
138
  ├── history/
139
139
  │ ├── CHANGELOG.md # Master changelog index
140
- │ ├── changelog/ # Individual entries
141
- │ ├── ledger/ # Refinement Ledger — append-only per-commit refinement journal (YYYY-MM.md; written at commit time, NOT scaffolded empty)
140
+ │ ├── changelog/ # Individual entries (YYYY-MM-DD-{three-words}.md; written at commit time, NOT scaffolded empty)
142
141
  │ ├── plans/ # Implementation plans (Status field required)
143
142
  │ ├── brainstorms/ # Harvested brainstorm sessions ({topic}/) — user decides kept (committed) or deleted; Readme.md is the index
144
143
  │ └── backlog.md # Tracked work items by priority (P0-P3)
@@ -168,6 +167,7 @@ This is what makes baseline more than a fresh scaffold. Detect old-shape artifac
168
167
  | repo-wide `docs/pillars/` | cross-module doctrine → `docs/architecture/`; delete the folder |
169
168
  | `docs/boundaries/` (legacy persisted boundaries) | delete — boundary analysis is a plan-time diagnostic (the `boundary` skill reads contracts fresh from source); fold any human-authored knowledge (external consumers, intent, accepted exceptions) into `docs/architecture/` |
170
169
  | `docs/OWNERSHIP_INDEX.md` (legacy derived ownership index) | delete — ownership is the union of feature `owns:` frontmatter, surfaced by the generated index |
170
+ | `docs/history/ledger/YYYY-MM.md` (the Refinement Ledger, now merged into the changelog) | split each `### ` block into its own `docs/history/changelog/YYYY-MM-DD-{three-words}.md` entry — content preserved **verbatim**, heading promoted to `#`, three words naming the work; append one row per entry to `docs/history/CHANGELOG.md`; delete the `docs/history/ledger/` folder. Records are moved, never rewritten |
171
171
  | `docs/operations/guardrails.md` | fold durable contract notes into `docs/architecture/` |
172
172
  | `docs/architecture/overview.md` | split into `domain-model.md` / `glossary.md` / `non-goals.md` / `references.md` / `open-questions.md` |
173
173
  | a legacy `docs/brainstorm/{topic}/`, or a root `brainstorm/`/`brainstorming/` folder | move each **active** record to `docs/research/{topic}-brainstorm/` and each **harvested** one to `docs/history/brainstorms/{topic}/` (dropping the suffix); create/refresh both `Readme.md` indexes; delete the emptied folder |
@@ -201,7 +201,7 @@ Re-running you is safe — the structure work is idempotent, so a second pass is
201
201
  ## Rules
202
202
 
203
203
  - **Never delete feature docs** — only update or flag for review.
204
- - **Never modify `docs/history/plans/`, `docs/history/changelog/`, or `docs/history/ledger/`** (frozen/append-only records — ledger blocks are written only at commit time, distilled only by the `retro` agent).
204
+ - **Never modify `docs/history/plans/` or `docs/history/changelog/`** (frozen records — changelog entries are written only at commit time, distilled only by the `retro` agent).
205
205
  - **Preserve existing doc structure and formatting** when updating.
206
206
  - **When in doubt, create a backlog item** rather than making a wrong update.
207
207
  - **Be specific:** include file paths, line numbers, and what changed.
@@ -0,0 +1,46 @@
1
+ ---
2
+ name: retro
3
+ description: Session-distillation agent for the changelog. Reads the per-unit-of-work entries under `docs/history/changelog/` accumulated since its last run and distills the refinement delta — what user-driven iteration added that the one-shot build lacked — into a typed punch list of doc-content gaps, doc-structure moves (missing doc / mothership split / merge), skill-evolution findings backed by survived-vs-overridden counts, unpinned discoveries needing an enforced artifact (test, token, guardrail, schema), and cross-project harness rules. Proposes only — actionable items land in the backlog, never applied directly. Run on demand: before a brainstorm or LLD session, before starting a new project, or after a refinement arc. Triggers on "run retro", "distill the changelog", "refinement retro", "/retro".
4
+ tools: Read, Glob, Grep, Bash, Write, Edit
5
+ model: inherit
6
+ ---
7
+
8
+ # Retro — changelog distillation
9
+
10
+ You distill refinement history into documentation and harness feedback. Your input is the changelog — the per-unit-of-work entries written at commit time under `docs/history/changelog/` (entry format and field rules: the `documentation` skill's `templates/changelog-entry.md`). Your output is a short, typed punch list; every finding cites the entries that evidence it. You propose — you never apply.
11
+
12
+ ## Before starting
13
+
14
+ 1. Read `docs/memory/retro.md` if it exists — its opening `Last run:` stamp is your last-distilled marker (run date + last entry seen); below it live prior skill-efficacy tallies and suppressed findings. No file ⇒ first run ⇒ distill everything. **An unparseable or unrecognised marker is not an error** — treat it as "distill from the start of the folder" and re-stamp in the current format.
15
+ 2. Collect the input set: every entry file under `docs/history/changelog/` dated after the marker, in filename order (`YYYY-MM-DD-{three-words}.md` sorts chronologically). Empty set ⇒ report "nothing to distill since {date}" in one line, refresh the `Last run:` stamp, and stop — never manufacture findings.
16
+ 3. **Skip entries carrying no field block.** An entry with no `Ask:`/`Skills:`/`Pin:` fields predates the format and holds no distillable signal; it is not a defect and never a finding.
17
+ 4. Read `docs/memory/` for cross-reference: a changelog discovery that also appears in memory is confirmed knowledge; a memory entry with no changelog trace is itself a promotion candidate.
18
+
19
+ ## Distill
20
+
21
+ Classify every finding into exactly one bucket. Work from the entries — recurrence and explicit fields, never vibes.
22
+
23
+ 1. **Doc content** — a truth doc is missing what refinement had to rediscover or invent: a `Discovered:` fact with no documented home, or `ux`/`taste` entries absent from the owning feature doc. Name the doc, the missing content, the evidencing entries.
24
+ 2. **Doc structure** — the doc *set* is wrong: a class of entries with no home doc (candidate new doc); one doc absorbing entries across unrelated surfaces (candidate split); docs that always co-change (candidate merge). Derive surface clustering from the entries' `surface` values against the union of feature-doc `owns:` globs (glob `docs/features/`).
25
+ 3. **Skill evolution** — tally each skill's `Skills:` verdicts across the entries: invoked / survived / overridden, override reasons aggregated. A skill overridden in most of its invocations is a finding. A refinement class recurring ≥3 times with no skill invoked is a candidate new skill.
26
+ 4. **Pin** — a `Pin: none — candidate:` entry that recurs, or any entry whose `Ask` carries a user taste quote or explicit approval with no enforced artifact guarding the behavior. Output the exact pin (test, token, guardrail, schema) and where it goes.
27
+ 5. **Harness rule** — a discovery true across projects, not of this repo (tooling collisions, platform ceilings, auth toil). Route to the shared rule file it belongs in.
28
+
29
+ ## Report & record
30
+
31
+ 1. Report in chat, ≤2 pages: a four-line scoreboard (entries distilled · discoveries pinned vs unpinned · skill table: invoked/survived · dominant refinement class), then the punch list — each item `bucket · finding (one sentence) · evidence (entry refs) · proposed action (one sentence)`. More than 12 findings ⇒ keep the top 12 by recurrence and state the tail count.
32
+ 2. Append the actionable items to `docs/history/backlog.md` as `- **[P0–P3]** {finding} — discovered by retro`, priority by severity, deduped against existing entries.
33
+ 3. Update `docs/memory/retro.md` (create on first write). The file **always opens with a human-legible stamp**, refreshed on **every** run — including a nothing-to-distill run — so anyone browsing `docs/memory/` sees at a glance when retro last ran and how far it read:
34
+
35
+ ```
36
+ Last run: {YYYY-MM-DD} · {N} entries distilled (through {last entry filename}) · {M} findings → backlog
37
+ ```
38
+
39
+ Below the stamp: updated skill-efficacy tallies and findings the user declined (suppressed, not re-raised), as dated entries `## YYYY-MM-DD — {topic}`.
40
+
41
+ ## Rules
42
+
43
+ - **Evidence or silence** — no finding without entry citations; a clean report is valid.
44
+ - **Propose, never apply** — you never edit truth docs, skills, rules, code, or changelog entries; application runs through the normal documentation loop in the main session.
45
+ - **Committed entries are immutable input** — never rewrite, renumber, or "clean up" an entry, whatever its quality; a malformed entry is at most a finding against the committing procedure.
46
+ - **Respect suppressions** in `docs/memory/retro.md` — a declined finding is recorded once, never re-raised every run.
@@ -2,6 +2,7 @@
2
2
  name = "maintenance"
3
3
  description = "The single docs steward. Default behavior is the docs-vs-code coherence audit — detects and fixes docs drifting from code (stale docs, broken ownership, unowned source paths, architecture/backlog drift). An additive **baseline mode** layers structural reconcile on top: when the repo's `harness-version` marker is missing or behind, it converges `docs/` to the installed harness shape (scaffold the standard tree, fold dissolved-shape artifacts forward, stamp the version, propose modules) before running the audit. Mode is auto-selected from the marker. Run weekly, after major changes, or to baseline/upgrade a repo. Cross-cutting contract analysis is the `boundary` skill (`check` for plans, `scan` for diffs) — it derives contracts dynamically from source; there are no persisted boundary docs to audit. Triggers on \"run maintenance\", \"docs health\", \"baseline this repo\", \"reconcile the harness\", \"upgrade the harness\", \"is this repo on the current harness\", \"/maintenance\"."
4
4
  developer_instructions = '''
5
+
5
6
  # Maintenance Agent
6
7
 
7
8
  You are the **single docs steward**. You keep a repo's `docs/` coherent with its code, and — when the repo's structure is behind the installed harness — you reconcile that structure first.
@@ -134,13 +135,12 @@ docs/
134
135
  │ └── {topic}-brainstorm/ # created by the `brainstorm` skill; NOT scaffolded empty; moves to history/brainstorms/ on a passed harvest
135
136
  ├── history/
136
137
  │ ├── CHANGELOG.md # Master changelog index
137
- │ ├── changelog/ # Individual entries
138
- │ ├── ledger/ # Refinement Ledger — append-only per-commit refinement journal (YYYY-MM.md; written at commit time, NOT scaffolded empty)
138
+ │ ├── changelog/ # Individual entries (YYYY-MM-DD-{three-words}.md; written at commit time, NOT scaffolded empty)
139
139
  │ ├── plans/ # Implementation plans (Status field required)
140
140
  │ ├── brainstorms/ # Harvested brainstorm sessions ({topic}/) — user decides kept (committed) or deleted; Readme.md is the index
141
141
  │ └── backlog.md # Tracked work items by priority (P0-P3)
142
142
  ├── memory/ # index.md, main.md, {agent}.md — project knowledge + per-agent strategy memory
143
- └── tests/ # Optional, author-maintained — create only if test docs exist
143
+ └── tests/ # Behavioral test checklists ({feature}.md, step → **Assert**), derived at plan Completion via the `documentation` skill; author-maintained, present only when test docs exist
144
144
  ```
145
145
 
146
146
  There is **no `docs/routing.md`**, **no `docs/modules/{m}/`**, **no `docs/pillars/`**, **no `docs/boundaries/`**. Code ownership lives in feature `owns:` frontmatter; a module is a `module:` label, not a folder; boundaries are diagnosed from source; brainstorm records live in `docs/research/` (active) and `docs/history/brainstorms/` (harvested).
@@ -149,7 +149,7 @@ There is **no `docs/routing.md`**, **no `docs/modules/{m}/`**, **no `docs/pillar
149
149
 
150
150
  ### Step B1 — Inventory and classify
151
151
 
152
- Glob every markdown file. Classify each: Architecture, Features, Operations, Plans, Changelogs, Backlog, Brainstorm records (stay), Stale/Deprecated (delete), Root docs (stay). For each topic keep the most complete version as canonical; extract unique content from the rest before deleting. **No redirect stubs** — when you move a file, delete the original and fix every reference (cross-doc links, memory files). Anything already under `docs/research/{topic}-brainstorm/` (or legacy `-brainstorming/`) or `docs/history/brainstorms/{topic}/` is a **design record** — leave it in place untouched; never reclassify its contents as Architecture/Stale or relocate them.
152
+ Glob every markdown file. Classify each: Architecture, Features, Operations, Tests (behavioral checklists — stay), Plans, Changelogs, Backlog, Brainstorm records (stay), Stale/Deprecated (delete), Root docs (stay). For each topic keep the most complete version as canonical; extract unique content from the rest before deleting. **No redirect stubs** — when you move a file, delete the original and fix every reference (cross-doc links, memory files). Anything already under `docs/research/{topic}-brainstorm/` (or legacy `-brainstorming/`) or `docs/history/brainstorms/{topic}/` is a **design record** — leave it in place untouched; never reclassify its contents as Architecture/Stale or relocate them.
153
153
 
154
154
  While reading each markdown doc to classify it, if the doc names a code symbol it asserts exists that **statically resolves to nothing**, note it as an observation for the Part A audit — **only** on stacks where static resolution is reliable (stay silent on codegen/reflection/DI/barrel stacks); scoped to docs already being read here, never a whole-repo prose sweep; **docs only**, never code-file comments.
155
155
 
@@ -198,7 +198,7 @@ Re-running you is safe — the structure work is idempotent, so a second pass is
198
198
  ## Rules
199
199
 
200
200
  - **Never delete feature docs** — only update or flag for review.
201
- - **Never modify `docs/history/plans/`, `docs/history/changelog/`, or `docs/history/ledger/`** (frozen/append-only records — ledger blocks are written only at commit time, distilled only by the `retro` agent).
201
+ - **Never modify `docs/history/plans/` or `docs/history/changelog/`** (frozen records — changelog entries are written only at commit time, distilled only by the `retro` agent).
202
202
  - **Preserve existing doc structure and formatting** when updating.
203
203
  - **When in doubt, create a backlog item** rather than making a wrong update.
204
204
  - **Be specific:** include file paths, line numbers, and what changed.
@@ -0,0 +1,45 @@
1
+ # dropped Claude tools: Read, Glob, Grep, Bash, Write, Edit
2
+ name = "retro"
3
+ description = "Session-distillation agent for the changelog. Reads the per-unit-of-work entries under `docs/history/changelog/` accumulated since its last run and distills the refinement delta — what user-driven iteration added that the one-shot build lacked — into a typed punch list of doc-content gaps, doc-structure moves (missing doc / mothership split / merge), skill-evolution findings backed by survived-vs-overridden counts, unpinned discoveries needing an enforced artifact (test, token, guardrail, schema), and cross-project harness rules. Proposes only — actionable items land in the backlog, never applied directly. Run on demand: before a brainstorm or LLD session, before starting a new project, or after a refinement arc. Triggers on \"run retro\", \"distill the changelog\", \"refinement retro\", \"/retro\"."
4
+ developer_instructions = '''
5
+
6
+ # Retro — changelog distillation
7
+
8
+ You distill refinement history into documentation and harness feedback. Your input is the changelog — the per-unit-of-work entries written at commit time under `docs/history/changelog/` (entry format and field rules: the `documentation` skill's `templates/changelog-entry.md`). Your output is a short, typed punch list; every finding cites the entries that evidence it. You propose — you never apply.
9
+
10
+ ## Before starting
11
+
12
+ 1. Read `docs/memory/retro.md` if it exists — its opening `Last run:` stamp is your last-distilled marker (run date + last entry seen); below it live prior skill-efficacy tallies and suppressed findings. No file ⇒ first run ⇒ distill everything. **An unparseable or unrecognised marker is not an error** — treat it as "distill from the start of the folder" and re-stamp in the current format.
13
+ 2. Collect the input set: every entry file under `docs/history/changelog/` dated after the marker, in filename order (`YYYY-MM-DD-{three-words}.md` sorts chronologically). Empty set ⇒ report "nothing to distill since {date}" in one line, refresh the `Last run:` stamp, and stop — never manufacture findings.
14
+ 3. **Skip entries carrying no field block.** An entry with no `Ask:`/`Skills:`/`Pin:` fields predates the format and holds no distillable signal; it is not a defect and never a finding.
15
+ 4. Read `docs/memory/` for cross-reference: a changelog discovery that also appears in memory is confirmed knowledge; a memory entry with no changelog trace is itself a promotion candidate.
16
+
17
+ ## Distill
18
+
19
+ Classify every finding into exactly one bucket. Work from the entries — recurrence and explicit fields, never vibes.
20
+
21
+ 1. **Doc content** — a truth doc is missing what refinement had to rediscover or invent: a `Discovered:` fact with no documented home, or `ux`/`taste` entries absent from the owning feature doc. Name the doc, the missing content, the evidencing entries.
22
+ 2. **Doc structure** — the doc *set* is wrong: a class of entries with no home doc (candidate new doc); one doc absorbing entries across unrelated surfaces (candidate split); docs that always co-change (candidate merge). Derive surface clustering from the entries' `surface` values against the union of feature-doc `owns:` globs (glob `docs/features/`).
23
+ 3. **Skill evolution** — tally each skill's `Skills:` verdicts across the entries: invoked / survived / overridden, override reasons aggregated. A skill overridden in most of its invocations is a finding. A refinement class recurring ≥3 times with no skill invoked is a candidate new skill.
24
+ 4. **Pin** — a `Pin: none — candidate:` entry that recurs, or any entry whose `Ask` carries a user taste quote or explicit approval with no enforced artifact guarding the behavior. Output the exact pin (test, token, guardrail, schema) and where it goes.
25
+ 5. **Harness rule** — a discovery true across projects, not of this repo (tooling collisions, platform ceilings, auth toil). Route to the shared rule file it belongs in.
26
+
27
+ ## Report & record
28
+
29
+ 1. Report in chat, ≤2 pages: a four-line scoreboard (entries distilled · discoveries pinned vs unpinned · skill table: invoked/survived · dominant refinement class), then the punch list — each item `bucket · finding (one sentence) · evidence (entry refs) · proposed action (one sentence)`. More than 12 findings ⇒ keep the top 12 by recurrence and state the tail count.
30
+ 2. Append the actionable items to `docs/history/backlog.md` as `- **[P0–P3]** {finding} — discovered by retro`, priority by severity, deduped against existing entries.
31
+ 3. Update `docs/memory/retro.md` (create on first write). The file **always opens with a human-legible stamp**, refreshed on **every** run — including a nothing-to-distill run — so anyone browsing `docs/memory/` sees at a glance when retro last ran and how far it read:
32
+
33
+ ```
34
+ Last run: {YYYY-MM-DD} · {N} entries distilled (through {last entry filename}) · {M} findings → backlog
35
+ ```
36
+
37
+ Below the stamp: updated skill-efficacy tallies and findings the user declined (suppressed, not re-raised), as dated entries `## YYYY-MM-DD — {topic}`.
38
+
39
+ ## Rules
40
+
41
+ - **Evidence or silence** — no finding without entry citations; a clean report is valid.
42
+ - **Propose, never apply** — you never edit truth docs, skills, rules, code, or changelog entries; application runs through the normal documentation loop in the main session.
43
+ - **Committed entries are immutable input** — never rewrite, renumber, or "clean up" an entry, whatever its quality; a malformed entry is at most a finding against the committing procedure.
44
+ - **Respect suppressions** in `docs/memory/retro.md` — a declined finding is recorded once, never re-raised every run.
45
+ '''
@@ -1,11 +1,11 @@
1
1
  {
2
2
  "harness": "etna",
3
3
  "name": "etna",
4
- "version": "1.1.14",
4
+ "version": "1.2.0",
5
5
  "files": [
6
6
  ".prettierignore",
7
7
  ".prettierrc.json",
8
8
  ".vscode/settings.json"
9
9
  ],
10
- "digest": "4a59f957bd58"
10
+ "digest": "69795cd9c915"
11
11
  }
@@ -0,0 +1,37 @@
1
+ # Changelog
2
+
3
+ Every unit of work leaves one record: `docs/history/changelog/YYYY-MM-DD-{three-words}.md`. The three words name the work, not the commit. Format, field rules, and the closed exemption list are the `documentation` skill's `templates/changelog-entry.md`.
4
+
5
+ An entry is not a summary line. It carries the refinement context only the working session holds — the ask in the user's own words, what was rejected, which skills survived or were overridden, what running the thing taught, what now guards it.
6
+
7
+ ## When an entry is owed
8
+
9
+ | Trigger | What to write |
10
+ | --- | --- |
11
+ | A plan reaches `Status: Complete` | A draft entry for that plan, linked to it — written now, while the session still holds the context |
12
+ | The user asks for a changelog | The entry for the work in hand. No commit required |
13
+ | A commit is made | Every non-exempt commit is covered by an entry — the commit skill writes or completes it |
14
+
15
+ **Exempt** (closed list): release and bot commits, harness installs and bumps, lockfile-only changes, pure renames and moves, and changelog housekeeping itself.
16
+
17
+ ## The entry's life
18
+
19
+ | State | Meaning |
20
+ | --- | --- |
21
+ | **Draft** | Created before its commit exists. Mutable — fields filled as far as the session can |
22
+ | **Complete** | Missing fields filled in from the diff and the session |
23
+ | **Frozen** | The moment it rides in a commit. Never edited again |
24
+
25
+ **Immutability begins at commit, not at creation.** A draft in the working tree is meant to be edited — that is what lets a completed plan record its context before anything is committed. Once an entry is committed it is history: a correction is a new entry linking back, never an edit.
26
+
27
+ ## Granularity
28
+
29
+ A commit is the smallest unit an entry may describe. Above that the mapping is judgment — four commits may be four entries or one, whichever reads better as history.
30
+
31
+ An entry spanning several commits rides in the **last** of them and names the earlier ones in `Commits:`. An entry can never carry its own commit's SHA, so that field lists predecessors only and is omitted when one entry maps to one commit.
32
+
33
+ When the work done exceeds what a draft describes, do not stretch the draft — write a second entry. The first stays an honest account of the plan; the second records the work beyond it.
34
+
35
+ ## The index
36
+
37
+ Every entry appends one row to `docs/history/CHANGELOG.md` — date, link, one-line summary — in the same pass that writes the entry, so the table never trails the folder.
@@ -4,7 +4,7 @@ Runtime versions and the canonical package list — the workspace baseline every
4
4
 
5
5
  ## Runtime Versions
6
6
 
7
- - **Node.js:** 22 LTS (latest)
7
+ - **Node.js:** 24 LTS (Active LTS — 22 is Maintenance-only)
8
8
  - **Package manager:** detect from lockfile (`pnpm-lock.yaml` → pnpm, `yarn.lock` → yarn, `package-lock.json` → npm). Don't hardcode one.
9
9
  - **PostgreSQL:** 17 · **Redis:** 7.x (latest)
10
10
 
@@ -47,3 +47,14 @@ No alternatives. Just use these.
47
47
  | fast-deep-equal | ^3.1.3 | Deep equality checks | lodash.isEqual |
48
48
  | @ngneat/falso | latest | Fake data generation | @faker-js/faker, chance |
49
49
  | pino | ^10.1.0 | Logging | winston |
50
+
51
+ ## GitHub Actions
52
+
53
+ Pin the major. `@v4` and older target the deprecated Node 20 action runtime — GitHub force-runs them on a newer Node and warns on every job.
54
+
55
+ | Action | Version | Use |
56
+ | -------------------------- | ------- | -------------------------- |
57
+ | actions/checkout | v5 | Repo checkout |
58
+ | actions/setup-node | v5 | Node toolchain + npm cache |
59
+
60
+ Set `node-version` from the Runtime Versions block above, not from whatever the runner defaults to.
@@ -60,8 +60,7 @@ The two guarantees are complementary and both break on mixing: a reader holding
60
60
  | Baseline / reconcile docs | `maintenance` agent (baseline mode) — it calls this skill per template |
61
61
  | Document feature/module (LLD) | [`templates/feature.md`](templates/feature.md) |
62
62
  | Document data flow / state / Redux | [`templates/feature.md`](templates/feature.md) — they are sections of the feature doc |
63
- | Create/update changelog | [`templates/changelog-entry.md`](templates/changelog-entry.md) (record) |
64
- | Record per-commit refinement (ledger block) | [`templates/refinement-ledger.md`](templates/refinement-ledger.md) (record — written at commit time, distilled by the `retro` agent) |
63
+ | Create/update changelog entry | [`templates/changelog-entry.md`](templates/changelog-entry.md) (record — one per unit of work; carries the refinement fields, frozen inside its commit, distilled by the `retro` agent) |
65
64
  | Create/update plan | [`templates/plan.md`](templates/plan.md) (record) |
66
65
  | Record/revise architecture decision | [`templates/architecture-decision.md`](templates/architecture-decision.md) — one AD per subject; revisions update it in place |
67
66
  | System at a glance | [`templates/system-overview.md`](templates/system-overview.md) |
@@ -1,62 +1,57 @@
1
- # Changelog
1
+ # Changelog Entry
2
2
 
3
- Record. Use for: recording code changes with function-level detail. Entries are frozen once written — they describe the change as it shipped, and are never edited to match later reality.
3
+ Record. Use for: the per-unit-of-work journal of what changed and how it was refined — one file per entry under `docs/history/changelog/YYYY-MM-DD-{three-words}.md`, written by whoever does the work and frozen inside the commit it describes. The three words name the work, not the commit. Trigger and lifecycle policy: the `changelog` rule; distillation is the `retro` agent.
4
4
 
5
- Change categories follow the Keep a Changelog vocabulary — **Added / Changed / Deprecated / Removed / Fixed / Security** — the same six the master `CHANGELOG.md` scaffold instructs. Include only the categories that apply; all six share the same bullet shape (function/file, then detail lines).
5
+ An entry is not a summary line. Its value concentrates in the fields a diff cannot reconstruct — the ask in the user's own words, what was rejected, which skills survived or were overridden, what running the thing taught.
6
6
 
7
- ```
8
- # YYYY-MM-DD - [Title]
9
-
10
- ## Summary
11
-
12
- Brief description of what changed and why.
13
-
14
- ## Changes
7
+ ## Entry format
15
8
 
16
- ### Added
17
- - `newFunction(params)` in `path/to/file.js`
18
- - Purpose: What it does
19
- - Used by: Where it's called
20
-
21
- ### Changed
22
- - `existingFunction()` in `path/to/file.js`
23
- - Changed: What's different
24
- - Reason: Why it changed
25
- - Migration: What callers must do
9
+ ```
10
+ # {YYYY-MM-DD} · {surface} — {one-line outcome}
11
+
12
+ **Plan:** [history/plans/YYYY-MM-DD-slug.md](../plans/YYYY-MM-DD-slug.md)
13
+ **Commits:** {sha}, {sha}
14
+
15
+ - **Ask:** {what the user asked, compressed — taste and preference statements quoted verbatim}
16
+ - **Iterations:** {N} · rejected: {what was rejected and why} | none
17
+ - **Skills:** {skill}@{version} — survived | partially survived | overridden ({why, briefly}) | none used
18
+ - **Change:** {added/changed X, which does Y, because Z — behavior first, mechanism second}
19
+ - **Discovered:** {non-obvious fact learned by running the product — environment quirk, platform ceiling, seam behavior, dependency constraint} | none
20
+ - **Class:** {one or more keywords — suggestive vocabulary, not a closed enum; see Field rules}
21
+ - **Pin:** {enforced artifact written in this entry's commit: test / token / guardrail / schema} | none — candidate: {what should hold it}
22
+ ```
26
23
 
27
- ### Removed
28
- - `oldFunction()` from `path/to/file.js`
29
- - Replaced by: `newFunction()`
24
+ `**Plan:**` appears only on plan-linked entries. `**Commits:**` appears only when one entry covers several commits, and lists the predecessors — an entry can never carry its own commit's SHA.
30
25
 
31
- ### Fixed
32
- - `buggyFunction()` in `path/to/file.js`
33
- - Bug: What was wrong, when it manifested
34
- - Fix: What changed
26
+ ## Lifecycle
35
27
 
36
- (Deprecated / Security follow the same shape.)
28
+ | State | Meaning |
29
+ | --- | --- |
30
+ | **Draft** | Created before its commit exists — typically the moment a plan reaches `Status: Complete`. Mutable; fields filled as far as the session can |
31
+ | **Complete** | Missing fields filled in from the diff and the session |
32
+ | **Frozen** | The moment it rides in a commit. Never edited, renumbered, or reconciled |
37
33
 
38
- ## Breaking Changes
34
+ **Immutability begins at commit, not at creation.** A draft in the working tree is meant to be edited; that is what lets a completed plan capture its context before anything is committed. A committed entry is history — a correction is a new entry that links back. Entries are exempt from doc-health passes by genre: they are history and can never be "wrong".
39
35
 
40
- ⚠️ **[Change description]**
41
- - Old: Previous behavior
42
- - New: Current behavior
43
- - Impact: What breaks
44
- - Migration: How to fix
36
+ ## Field rules
45
37
 
46
- ## Migration Steps
38
+ - **Every field present; "none" stated explicitly.** An absent field is a template violation. Sessions assert success by default — the required `rejected:` and `overridden` entries are the counterweight; an honestly empty failure field is information too.
39
+ - **`surface`** uses the repo's ownership vocabulary — the owning feature doc's topic or an `owns:` path stem — so entries are queryable per surface.
40
+ - **`Ask` quotes taste verbatim.** The user's preference wording is the one thing no skill can infer and no rebuild recovers; the entry is its durable home.
41
+ - **`Skills` records efficacy honestly** — survived / partially survived / overridden with a reason. These verdicts are the raw data the `retro` agent aggregates into skill-evolution findings; sanitizing them into success stories destroys the mechanism's value.
42
+ - **`Discovered` holds what only running the product teaches.** If it was learned in use, it is recorded the same day — this field feeds the pin candidates.
43
+ - **`Class` is a suggestive vocabulary, not a closed enum.** Tag with one or more keywords, preferring an existing term over a synonym so the `retro` agent can cluster; coin a new one when nothing fits — a recurring coinage is itself retro signal that the vocabulary (or the doc set) is missing a category. Suggested keywords: `ux` · `ui` · `visual` · `taste` · `layout` · `motion` · `interaction` · `copy` · `a11y` · `responsiveness` · `navigation` · `state` · `structure` · `architecture` · `seam` · `contract` · `schema` · `data` · `content` · `seed` · `performance` · `caching` · `resilience` · `error-handling` · `security` · `auth` · `observability` · `logging` · `testing` · `tooling` · `dependency` · `ops` · `deploy` · `env` · `ci` · `i18n` · `docs`.
44
+ - **`Pin` closes the loop:** the enforced artifact written in this commit, or the named candidate for the `retro` agent to flag. A taste-verified behavior with `Pin: none` and no candidate is a template smell.
45
+ - **Out-of-session entries** (the writing session did not do the work): fill what the diff and conversation evidence support; mark the rest `unknown — committed out-of-session`.
47
46
 
48
- Numbered instructions for whoever applies the change — not a tracked task list (the entry is frozen once written):
47
+ ## Granularity
49
48
 
50
- 1. {Step}
51
- 2. {Step}
49
+ A commit is the smallest unit an entry may describe. Above that the mapping is judgment — four commits may be four entries or one. When the work exceeds what a draft describes, write a **second** entry rather than stretching the first: the plan-linked entry stays an honest account of the plan.
52
50
 
53
- ## Verified
51
+ ## The index
54
52
 
55
- - What was exercised end-to-end and the observed result — real runs, real fixtures, measured timings
56
- - A future agent diagnosing a regression starts from this evidence
53
+ Every entry appends one row to `docs/history/CHANGELOG.md` — date, link, one-line summary — in the same pass that writes the entry.
57
54
 
58
- ## Files Changed
55
+ ## Exemptions (closed list)
59
56
 
60
- - `src/path/file1.js` - Core changes
61
- - `src/path/file2.js` - Supporting updates
62
- ```
57
+ No entry for: release and bot commits, harness installs and bumps, lockfile-only changes, pure renames and moves, and changelog housekeeping itself. Everything else gets an entry, however short.
@@ -29,8 +29,7 @@ Each topic has one canonical location. Read from here, not from plans or changel
29
29
  | Environment / config surface | `docs/operations/` | environment.md |
30
30
  | Testing strategy | `docs/tests/` | strategy.md |
31
31
  | Historical plans | `docs/history/plans/` | YYYY-MM-DD-name.md |
32
- | Change records | `docs/history/changelog/` | Individual entries |
33
- | Refinement Ledger | `docs/history/ledger/` | YYYY-MM.md (append-only, written at commit time) |
32
+ | Change records | `docs/history/changelog/` | `YYYY-MM-DD-{three-words}.md` — one per unit of work, written at commit time |
34
33
  | Migration runbooks | `docs/history/migrations/` | YYYY-MM-DD-name.md |
35
34
  | Deep-research artifacts | `docs/history/research/{topic}/` | README.md + findings.md + sources.md |
36
35
  | Brainstorm design records | `docs/research/{topic}-brainstorm/` (active; legacy `-brainstorming/`) → `docs/history/brainstorms/{topic}/` (harvested; user deletes or commits) | thesis.md + forks.md + ledger.md + state.md |
@@ -51,8 +50,7 @@ Every doc is a **truth document** (states current absolutes, topic-named, update
51
50
  - `docs/operations/`: How-to procedures for setup, development, and deployment, plus the environment registry. Update when workflows change. One-shot migrations do NOT live here — they are records (`docs/history/migrations/`).
52
51
  - `docs/tests/`: Testing strategy and test docs. Present when the repo has a test posture worth documenting.
53
52
  - `docs/history/plans/`: Records. Must have `Status:` field. Never modify after completion.
54
- - `docs/history/changelog/`: Records. Append-only.
55
- - `docs/history/ledger/`: Records. The Refinement Ledger — an append-only per-commit refinement journal (monthly `YYYY-MM.md` files) written by the committing agent, each block staged inside the commit it describes; block format is the `documentation` skill's `templates/refinement-ledger.md`, distillation is the `retro` agent. Blocks are immutable — never edited, never reconciled; the folder is never scaffolded empty.
53
+ - `docs/history/changelog/`: Records. One entry per unit of work (`YYYY-MM-DD-{three-words}.md`), written by whoever does the work and frozen inside the commit it describes. Entries carry the refinement context a diff cannot show — the ask in the user's words, iterations and rejections, skill survived/overridden verdicts, discoveries, pins. Format is the `documentation` skill's `templates/changelog-entry.md`; trigger and lifecycle are the `changelog` rule; distillation is the `retro` agent. Immutability begins at commit — a draft in the working tree is mutable until then, never after. Every entry appends a row to `docs/history/CHANGELOG.md`.
56
54
  - `docs/history/migrations/`: Records. One-shot migration/upgrade runbooks — authored before execution, outcome-stamped and frozen after.
57
55
  - `docs/history/research/{topic}/`: Deep-research artifacts — the dumped output of a research pass, one folder per topic (conventionally `README.md` synthesis + `findings.md` verified claims & citations + `sources.md`). A point-in-time, cited record — **not** a living authority doc: it owns no code (no `owns:` frontmatter) and is never edited to "stay current." A spec/plan links to it for grounding; a new question gets a new topic folder.
58
56
  - `docs/research/{topic}-brainstorm/` → `docs/history/brainstorms/{topic}/`: Brainstorm design records — the Brainstorming-Mode session for a topic (working surface `thesis.md` + `forks.md` + `ledger.md` + `state.md` + `basis/` + `fragments/`, plus an untracked `ops/` capture layer deleted at stop), written by the `brainstorm` skill and its twin agent. An active session lives under `docs/research/` (legacy folders carry the older `-brainstorming/` suffix); on a **passed harvest** it **moves** to `docs/history/brainstorms/` — the completion marker — and the **user decides whether the moved folder is deleted or committed** as provenance. Each of the two folders carries a `Readme.md` index (the skill reads it at start instead of scanning). Author-created (never scaffolded empty), one folder per design conversation. Owns no code (no `owns:` frontmatter); the harvest routes its conclusions into `architecture/`/`features/`/`history/`. (Distinct from `docs/history/research/{topic}/` above — that is a frozen deep-research record, not a brainstorm session.)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nurix/etna",
3
- "version": "0.19.25",
3
+ "version": "0.19.27",
4
4
  "description": "Bootstrap a project with a Nurix harness — copies the harness's CLAUDE.md, skills, agents, rules, and hooks directly into the project from a bundled payload (no marketplace fetch, no network).",
5
5
  "type": "module",
6
6
  "bin": {
@@ -31,7 +31,7 @@
31
31
  "homepage": "https://github.com/nurixlabs/etna/tree/dev/packages/cli",
32
32
  "license": "UNLICENSED",
33
33
  "publishConfig": {
34
- "access": "restricted"
34
+ "access": "public"
35
35
  },
36
36
  "keywords": [
37
37
  "claude",
@@ -1,33 +0,0 @@
1
- # Refinement Ledger
2
-
3
- Record. Use for: the append-only per-commit journal of session refinement — one block per non-mechanical commit, written by the committing agent at commit time and staged **inside the commit it describes**. Blocks are immutable once committed: never edited, renumbered, or reconciled; a correction is a new block referencing the old. The ledger is exempt from doc-health passes by genre — it is history and can never be "wrong".
4
-
5
- Monthly files: `docs/history/ledger/YYYY-MM.md`, created on first block — the folder is never scaffolded empty. Distillation is the `retro` agent's job; this template owns only the capture format.
6
-
7
- ## Block format
8
-
9
- ```
10
- ### {YYYY-MM-DD} · {surface} — {one-line outcome}
11
- - **Ask:** {what the user asked, compressed — taste and preference statements quoted verbatim}
12
- - **Iterations:** {N} · rejected: {what was rejected and why} | none
13
- - **Skills:** {skill}@{version} — survived | partially survived | overridden ({why, briefly}) | none used
14
- - **Change:** {added/changed X, which does Y, because Z — behavior first, mechanism second}
15
- - **Discovered:** {non-obvious fact learned by running the product — environment quirk, platform ceiling, seam behavior, dependency constraint} | none
16
- - **Class:** {one or more keywords — suggestive vocabulary, not a closed enum; see Field rules}
17
- - **Pin:** {enforced artifact written in this commit: test / token / guardrail / schema} | none — candidate: {what should hold it}
18
- ```
19
-
20
- ## Field rules
21
-
22
- - **Every field present; "none" stated explicitly.** An absent field is a template violation. Sessions assert success by default — the required `rejected:` and `overridden` entries are the counterweight; an honestly empty failure field is information too.
23
- - **`surface`** uses the repo's ownership vocabulary — the owning feature doc's topic or an `owns:` path stem — so the ledger is queryable per surface.
24
- - **`Ask` quotes taste verbatim.** The user's preference wording is the one thing no skill can infer and no rebuild recovers; the ledger is its durable home.
25
- - **`Skills` records efficacy honestly** — survived / partially survived / overridden with a reason. These verdicts are the raw data the `retro` agent aggregates into skill-evolution findings; sanitizing them into success stories destroys the mechanism's value.
26
- - **`Discovered` holds what only running the product teaches.** If it was learned in use, it is recorded here the same day — this field feeds the pin candidates.
27
- - **`Class` is a suggestive vocabulary, not a closed enum.** Tag with one or more keywords, preferring an existing term over a synonym so the `retro` agent can cluster; coin a new one when nothing fits — a recurring coinage is itself retro signal that the vocabulary (or the doc set) is missing a category. Suggested keywords: `ux` · `ui` · `visual` · `taste` · `layout` · `motion` · `interaction` · `copy` · `a11y` · `responsiveness` · `navigation` · `state` · `structure` · `architecture` · `seam` · `contract` · `schema` · `data` · `content` · `seed` · `performance` · `caching` · `resilience` · `error-handling` · `security` · `auth` · `observability` · `logging` · `testing` · `tooling` · `dependency` · `ops` · `deploy` · `env` · `ci` · `i18n` · `docs`.
28
- - **`Pin` closes the loop:** the enforced artifact written in this commit, or the named candidate for the `retro` agent to flag. A taste-verified behavior with `Pin: none` and no candidate is a template smell.
29
- - **Out-of-session commits** (the committing session did not do the work): fill what the diff and conversation evidence support; mark the rest `unknown — committed out-of-session`.
30
-
31
- ## Exemptions (closed list)
32
-
33
- No block for: release/bot commits, harness installs and bumps, lockfile-only changes, pure renames/moves, and ledger housekeeping itself. Everything else gets a block, however short.
@@ -1,33 +0,0 @@
1
- # Refinement Ledger
2
-
3
- Record. Use for: the append-only per-commit journal of session refinement — one block per non-mechanical commit, written by the committing agent at commit time and staged **inside the commit it describes**. Blocks are immutable once committed: never edited, renumbered, or reconciled; a correction is a new block referencing the old. The ledger is exempt from doc-health passes by genre — it is history and can never be "wrong".
4
-
5
- Monthly files: `docs/history/ledger/YYYY-MM.md`, created on first block — the folder is never scaffolded empty. Distillation is the `retro` agent's job; this template owns only the capture format.
6
-
7
- ## Block format
8
-
9
- ```
10
- ### {YYYY-MM-DD} · {surface} — {one-line outcome}
11
- - **Ask:** {what the user asked, compressed — taste and preference statements quoted verbatim}
12
- - **Iterations:** {N} · rejected: {what was rejected and why} | none
13
- - **Skills:** {skill}@{version} — survived | partially survived | overridden ({why, briefly}) | none used
14
- - **Change:** {added/changed X, which does Y, because Z — behavior first, mechanism second}
15
- - **Discovered:** {non-obvious fact learned by running the product — environment quirk, platform ceiling, seam behavior, dependency constraint} | none
16
- - **Class:** {one or more keywords — suggestive vocabulary, not a closed enum; see Field rules}
17
- - **Pin:** {enforced artifact written in this commit: test / token / guardrail / schema} | none — candidate: {what should hold it}
18
- ```
19
-
20
- ## Field rules
21
-
22
- - **Every field present; "none" stated explicitly.** An absent field is a template violation. Sessions assert success by default — the required `rejected:` and `overridden` entries are the counterweight; an honestly empty failure field is information too.
23
- - **`surface`** uses the repo's ownership vocabulary — the owning feature doc's topic or an `owns:` path stem — so the ledger is queryable per surface.
24
- - **`Ask` quotes taste verbatim.** The user's preference wording is the one thing no skill can infer and no rebuild recovers; the ledger is its durable home.
25
- - **`Skills` records efficacy honestly** — survived / partially survived / overridden with a reason. These verdicts are the raw data the `retro` agent aggregates into skill-evolution findings; sanitizing them into success stories destroys the mechanism's value.
26
- - **`Discovered` holds what only running the product teaches.** If it was learned in use, it is recorded here the same day — this field feeds the pin candidates.
27
- - **`Class` is a suggestive vocabulary, not a closed enum.** Tag with one or more keywords, preferring an existing term over a synonym so the `retro` agent can cluster; coin a new one when nothing fits — a recurring coinage is itself retro signal that the vocabulary (or the doc set) is missing a category. Suggested keywords: `ux` · `ui` · `visual` · `taste` · `layout` · `motion` · `interaction` · `copy` · `a11y` · `responsiveness` · `navigation` · `state` · `structure` · `architecture` · `seam` · `contract` · `schema` · `data` · `content` · `seed` · `performance` · `caching` · `resilience` · `error-handling` · `security` · `auth` · `observability` · `logging` · `testing` · `tooling` · `dependency` · `ops` · `deploy` · `env` · `ci` · `i18n` · `docs`.
28
- - **`Pin` closes the loop:** the enforced artifact written in this commit, or the named candidate for the `retro` agent to flag. A taste-verified behavior with `Pin: none` and no candidate is a template smell.
29
- - **Out-of-session commits** (the committing session did not do the work): fill what the diff and conversation evidence support; mark the rest `unknown — committed out-of-session`.
30
-
31
- ## Exemptions (closed list)
32
-
33
- No block for: release/bot commits, harness installs and bumps, lockfile-only changes, pure renames/moves, and ledger housekeeping itself. Everything else gets a block, however short.