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 with luria 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:

  1. 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.
  2. 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.
  3. 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.