# Changelog Entry

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.

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.

## Entry format

```
# {YYYY-MM-DD} · {surface} — {one-line outcome}

**Plan:** [history/plans/YYYY-MM-DD-slug.md](../plans/YYYY-MM-DD-slug.md)
**Commits:** {sha}, {sha}

- **Ask:** {what the user asked, compressed — taste and preference statements quoted verbatim}
- **Iterations:** {N} · rejected: {what was rejected and why} | none
- **Skills:** {skill}@{version} — survived | partially survived | overridden ({why, briefly}) | none used
- **Change:** {added/changed X, which does Y, because Z — behavior first, mechanism second. Plan-linked entries also carry the verification gate's results here: rows discharged, suite outcome, anything blocked}
- **Discovered:** {non-obvious fact learned by running the product — environment quirk, platform ceiling, seam behavior, dependency constraint} [source: {tag}] | none
- **Class:** {one or more keywords — suggestive vocabulary, not a closed enum; see Field rules}
- **Pin:** {enforced artifact written in this entry's commit: test / token / guardrail / schema} | none — candidate: {what should hold it}
```

`**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.

## Lifecycle

| State | Meaning |
| --- | --- |
| **Draft** | Created before its commit exists — typically the moment a plan reaches `Status: Complete`. Mutable; fields filled as far as the session can |
| **Complete** | Missing fields filled in from the diff and the session |
| **Frozen** | The moment it rides in a commit. Never edited, renumbered, or reconciled |

**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".

## Field rules

- **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.
- **`surface`** uses the repo's ownership vocabulary — the owning feature doc's topic or an `owns:` path stem — so entries are queryable per surface.
- **`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.
- **`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.
- **`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. **Each finding carries a `source:` tag from a closed list** — `generator` (a generated doc was wrong) · `generator-conflict` (two generated docs disagreed) · `rules-conflict` (a generated doc contradicted standing rules) · `runtime-discovery` (only running revealed it) · `environment` (tooling or harness). Closed deliberately, unlike `Class:` — the consumer is the doc generator's readback grep, not a human. A finding in a repo with no generated docs is almost always `runtime-discovery` or `environment`.
- **`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`.
- **`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.
- **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`.

## Granularity

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.

## The index

Every entry appends one row to `docs/history/CHANGELOG.md` — date, link, one-line summary — in the same pass that writes the entry.

## Exemptions (closed list)

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.
