ADR-002: Contributions write fragments; shared documents are generated views
Status Active · Version 2 · Filed 2026-08-03 · Influenced ADR-028 · DP-002 · DP-008
Context
A changelog and a narrative log are both append-mostly files that every substantial contribution touches at the bottom. Two branches that share nothing else still collide there, and so does every rebase onto a main that has moved. The conflicts carry no information — the changes don’t interact, they just both appended after the last thing.
That is contention, not carelessness, so “resolve them carefully” isn’t a fix. Each hand-resolution is another chance to silently drop somebody’s entry, and the failure is invisible: nobody notices a changelog line that isn’t there.
Decision
Each contribution owns a file nobody else writes; the shared document is a view, assembled on a cadence.
changelog.d/<branch-slug>.md— what an operator would notice.devlog.d/2026/08/03/211926.md— how it went, filed at its authoring timestamp withluria journal new(ADR-020). Optional; the devlog covers significant work, not every contribution.decisions/adr-NNN-<slug>.md— one decision, one file.- The decision index isn’t collected at all — it’s generated outright from frontmatter (ADR-004), which is strictly better than fragments because there is no step to forget.
Three details that look incidental and are not:
- Collection is not per-merge. A bot commit on every merge races in-flight rebases: a branch that rebased onto the pre-collection main gets a conflict in the file the whole scheme exists to keep conflict-free. Weekly, or on demand, means the assembled view is briefly behind — which is exactly the property that makes it safe.
- A stub fragment is legal. A file whose only content is an HTML comment collects to nothing. That keeps “every contribution files a fragment” enforceable by CI even when the honest answer is “nothing a reader would notice” — the alternative is a rule with a judgement call in it, which is a rule that erodes.
- Fragments are ordered by when they were committed, not by filename. Branch slugs sort arbitrarily; a narrative log reads chronologically.
Alternatives considered
- Hand-merge carefully. The status quo everywhere. It treats contention as a discipline problem, and the failure mode is silent.
- Collect on every merge. Keeps the view always current, and reintroduces the conflict it was built to remove — in a bot commit, where nobody is watching for it.
- Generate everything, no fragments. Right where the content is derivable — which is why the decision index is generated. Prose isn’t derivable, so changelog and devlog entries stay authored.
Consequences
- The answer to “which file do I edit?” is always a fragment.
- Generated and collected views can be linted against their sources, so drift is caught rather than discovered.
- One extra step at release time, and a view that is briefly stale by design.