Doc change management — the protocol¶
Audience: anyone editing files in
architecture/,guides/,proposals/, orreports/. Goal: every change is traceable, the docs always reflect what the code actually does, and a newcomer can follow the trail to understand both what the system does today and why it ended up that way.
This file is the rationale + how-to. The operative rules live in CLAUDE.md §"Doc change
protocol" and the per-section conventions in PrInstructions.md. If you're impatient, skip
to the checklist at the bottom.
The three doc types¶
We use three kinds of document, each with a job.
| Type | Where | Job |
|---|---|---|
| Living Spec | architecture/specs/<domain>.md |
Describes one product or system domain as it is today. There's one per domain (AMM pricing, auth flow, referral, ...). Rewritten in place when behavior changes — never branched into versions. |
| ADR (Architecture Decision Record) | architecture/decisions/NNNN-<slug>.md |
Captures one decision that shaped the system — what we chose, why, what we rejected. Append-only; once status: accepted, only status and superseded-by may change. |
| Per-commit walkthrough | pr-reports/<branch>-<sha>.html |
Auto-generated HTML, one per Claude-authored commit, written for a 1st-year intern. Captures the what of every commit. Spec + ADR captures the why and the current truth. See PrInstructions.md. |
The three are complementary:
What the system does today → Living Spec
Why we decided to do it that way → ADR
What this specific commit did → pr-reports walkthrough
What's been decided but not built → PENDING.md (index over ADRs with implementation-status: pending)
A reader who lands cold on the repo should be able to:
- Open
architecture/specs/amm-pricing.mdand learn how the AMM works today. - Follow the
decisions:list at the top of that spec to the ADRs and read why. - Open
pr-reports/index.htmland see every recent change with intern-friendly explanations. - Open
PENDING.mdand see every feature that's been designed but not yet shipped (the build backlog).
Implementation status — the two-lifecycle model¶
ADRs carry TWO independent lifecycle fields:
| Field | Tracks | Values |
|---|---|---|
status: |
The decision lifecycle | proposed → accepted → (superseded | rejected) |
implementation-status: |
The code lifecycle | pending → in-progress → implemented |
Why both? Because a decision can be made (status: accepted) long before the code is written (implementation-status: pending). Forcing them onto one axis hides the gap. Two axes make the gap visible and answerable.
The common case: design-first, code-later¶
For any meaningful redesign:
- First PR (docs-only): ADR authored with
status: accepted+implementation-status: pending. The ADR is rich enough to serve as the build guide for the eventual code PR. The ADR appears inPENDING.md. Specs that the ADR will affect are NOT rewritten yet — they still describe the live system. They may carry a small "pending redesign — see ADR-NNNN" banner. - Paired code PR (later, possibly weeks later): code change + spec rewrite + ADR
flipped to
implementation-status: implemented+ any superseded older ADRs updated. PENDING.md row moved to the "Recently shipped" section.
This pattern preserves the principle "spec = current truth" without losing the design intent — the intent lives in the ADR and surfaces via PENDING.md.
When to use each implementation-status value¶
- pending — design accepted, no code yet. Default for any new ADR proposing a future change. Listed in PENDING.md.
- in-progress — paired code PR is open, under review, or merging. Brief window.
- implemented — code shipped; ADR matches live behavior. Stable end-state.
PENDING.md sync requirement¶
If an ADR has implementation-status: pending (or in-progress), it MUST have a row in
PENDING.md. When the status flips to implemented, the row moves to
PENDING.md's "Recently shipped" section in the same PR. This is hand-maintained — small
enough to keep correct, easy to script later if it grows.
When to write what¶
Pure refactor, typo, dead-code removal — no docs change needed¶
Just commit. The pr-reports walkthrough captures the what. No spec or ADR.
Internal change with no public/behavioral effect — spec untouched¶
If you rewrite a function but it still does the same thing the spec describes, you don't need
to touch the spec. Update the code-refs: line ranges in the spec if they shifted by more
than ~20 lines.
Behavior change in a code path the spec describes — spec update + ADR¶
This is the most common reason to write an ADR. The flow is:
- Code change in the relevant
ftl-*repo, on afeat/<slug>orbug/<slug>branch. - Spec update — rewrite the affected section of
architecture/specs/<domain>.md. Bumplast-updated:to today. Adjustcode-refs:if files moved. - New ADR — copy
architecture/decisions/_TEMPLATE.mdto the next number. Fill inaffects-specs:andaffects-code:and the four required sections (Context, Decision, Consequences, Alternatives). - Supersession, if applicable — if your decision invalidates an earlier ADR, set
supersedes:on the new one and open the older one and set bothstatus: supersededandsuperseded-by:. - Index updates — add a row to
architecture/decisions/INDEX.md(newest first). Updatearchitecture/specs/INDEX.mdif a spec changed status.
If the code and docs live in different repos, the two PRs should reference each other in their descriptions and merge together.
Whole new domain — new spec + foundational ADR(s)¶
- Copy
architecture/specs/_TEMPLATE.mdto<domain>.mdand fill it in. - Write at least one ADR (
0001-<slug>for that domain — but globally numbered across all domains, not per-domain) capturing the foundational decision. - Add rows to both INDEX files.
How the upcoming AMM logic change will land¶
This is the worked example the system is designed for. When the user dictates an AMM change:
- New branch in
ftl-backend:feat/amm-<specific-change>. - Code edit (4 mirroring files — see
architecture/specs/amm-pricing.mdCode References). - Paired branch in
ftl-docswith the same name. On it: - Edit
architecture/specs/amm-pricing.md— rewrite the affected section, bumplast-updated:, fix any drifted code-refs. - Add
architecture/decisions/0004-<slug>.md. - Update
architecture/decisions/INDEX.md. - If the change invalidates ADR-0001's formula choice, also update 0001's frontmatter to
status: supersededandsuperseded-by: 0004, and setsupersedes: 0001on 0004. - Open both PRs. Reference each from the other.
- Merge together.
That's the full loop. Three files in ftl-docs, one focused commit in ftl-backend, fully
traceable from either direction.
Why this format and not ¶
| Alternative we considered | Why we passed |
|---|---|
| Wiki + freeform docs | No structure means no enforceability. Within a few months, half the docs are stale and you can't tell which half. |
| Per-PR changelog entries | Captures the what, not the why. Already covered by pr-reports/ walkthroughs. |
Versioned spec docs (amm-v1.md, amm-v2.md) |
The version most readers want is "what does it do RIGHT NOW". Versioning forces them to figure out which file is current. Living spec + dated ADRs gives both views without the lookup. |
| Issue tracker as decision log | Issues get archived, renamed, moved between projects. We want decisions to live in the code repo with the code they govern. |
Quick checklist (run through this before opening a docs PR)¶
- [ ] Branch named
feat/<slug>orbug/<slug>perCLAUDE.md§"Branch hygiene". - [ ] If the PR changes behavior described in any spec, the affected spec was updated.
- [ ] If the PR documents a decision, an ADR was added with all four sections filled in.
- [ ] New ADR's
implementation-status:is set (pendingif no code yet;implementedif this PR ships code that matches the ADR). - [ ] If
implementation-status: pending, the ADR has a row inPENDING.md. - [ ] If this PR flips an ADR from
pending→implemented, the PENDING.md row moves to "Recently shipped" in the same PR. - [ ] If superseding an older ADR: both files updated (
supersedes:on new,superseded-by:status: supersededon old). Only do this when the code that enacts the supersession is shipping in the same PR — otherwise the older ADR still describes live behavior.
- [ ]
architecture/decisions/INDEX.mdrow added/updated. - [ ]
architecture/specs/INDEX.mdrow updated if spec status changed. - [ ] Spec's
last-updated:reflects today's date. - [ ] Spec's
code-refs:paths still exist. - [ ] PR description includes
Author: @<github-handle>per the branch-hygiene rule. - [ ] If the matching code PR lives in another repo, both PRs reference each other.
If any box is unchecked, the PR isn't ready to merge.