Lesson 03 / 15
Repository Documents
The readme, the contribution guide, and the architecture decision record start at the same version and collapse at separate speeds: all three lose their first claim at version two, but the first two halve by version three while the decision record halves at version twelve, and ten of its twelve stale claims are silent.
Contents
The previous two lessons measured the four types around the product: tutorial, how-to, explanation, and reference, all texts describing what the product does. Other documents also sit inside a repository, and their readers are not the product’s reader. Someone looking at the repository for the first time is not asking about the product, they are asking what this repository is; someone who wants to contribute is not asking about the product, they are asking how this place is organized; someone looking for a decision’s reason is asking about neither the product nor the organization, but a judgment made in the past.
This lesson puts three repository documents through the same measure: the readme, the contribution guide, and the architecture decision record. The question is still the same — which surface does each document bind to, and how much does it hold up — but this time the answer turns into maintenance priority, because the three documents do not deserve the same attention.
Three Documents, Three Reader Roles
The readme is the repository’s door and faces the widest reader set. The questions it answers come in order: what is this, who benefits, how is it installed, how do I get a first result, where is the detail. The fifth question matters: the readme’s job is not to explain, it is to direct. Neither a tutorial nor a reference fits inside it; when one is forced in, the mixing cost the previous lesson measured is born. This is repository documents’ most common form of decay: over time a readme turns into the entire documentation set, because adding every new piece of information there is the shortest path. The result is a pile of claims collected in a single file, rotting at separate speeds; which section went wrong when can no longer be read.
The contribution guide faces a narrow reader: someone about to touch the code. The questions it answers are how to set up the development environment, how to run the tests, how to name a branch, how submitted work will be received. How a written expectation shortens review rounds was measured in the Code Review and Team Process course and is not repeated here; in this lesson the contribution guide is counted not as a process tool but as a text that needs maintenance.
The architecture decision record faces the narrowest reader and answers a single question: why was this decided this way? The record’s structure — context, decision, consequences — and how an architectural decision gets documented are the subject of the Architecture Decisions and Documentation course and are not repeated here. In this lesson the decision record is measured only by which surfaces it binds to and its lifespan.
# the skeleton of the invented repository's three documents
# example text, not executed
readme What is Measurement Station (concept)
Setup, first run (flow)
`station start` options (signature)
Package name, directory names, links (name)
contribution guide Why this layout (concept)
Setting up the environment, testing, submitting (flow)
Test command's options (signature)
Branch naming convention, tag names (name)
architecture decision record Context, decision, consequences (concept)
The interface the decision binds (signature)
Component names (name)
What They Are Bound To
The skeleton shows the three documents’ mix directly, and the three do not resemble each other.
The readme binds to all four surfaces at once. Inside it, a setup flow, a command signature, a product name, and a reasoning sentence all sit together. This makes the readme the repository’s most mixed document; it is also the hardest to maintain for this reason, because the number of events that can break it is the highest.
The contribution guide is flow-heavy: most of what it writes is a sequence. Like any text narrating steps, it collapses when the steps themselves change. Its second weight is name — branch naming convention, tag names, directory names. The name surface changes slowly, but when it does, nothing the contribution guide says throws an error; a newcomer opens a wrongly named branch and only learns this if someone tells them.
The architecture decision record binds almost entirely to concept. A decision’s context and consequence do not change because the code changes; they change only when the decision itself is revisited. In exchange, the decision record has nothing runnable in it: a decision record does not run, so it makes no noise when it goes wrong either.
The Cheapness of Pointing
The readme’s fifth question — where is the detail — is not as innocent as the first four, because its answer is in the writer’s hands. The same information can be placed two ways: by narrating it or by pointing at it.
Take the setup section as an example. Dumping every option into the readme means carrying a pile of signature claims there; signature changes once every two versions. If the same section is passed with a single pointer — “all options are in the reference” — what is carried drops to a single name claim, and name changes once every five versions, two and a half times slower than signature. No information is lost, it is just written once, and the readme binds to it.
This has a cost too: link targets also go stale, and when a link breaks, the reader finds nothing. But the two defects are not equal. A broken link is a defect the reader notices; a wrongly listed option is a defect the reader does not notice. Writing the readme to point rather than narrate turns a silent defect into a loud one — the same trade-off will come up a few more times throughout the course.
The Superseded Record
The architecture decision record has a trait invisible in the measurement. The other two documents get corrected when they go wrong; the decision record does not get corrected when it goes wrong, it gets superseded. The record itself stays as it is, and a new record declares it invalid.
This does not remove the measure, but it changes what the result means. If a record’s concept claims are wrong for today’s system, that record is stale — the table says this with 0/10 at version twelve. But if the record is read as history, its claims are still true for the system as it was at the time they were given. A single field carries the difference: the record’s status. If the status is written, the reader knows whether the text they are looking at describes today or the past; if it is not written, they read a ten-year-old reasoning as if it were current.
This is the one correction form seen throughout the course that does not change the text: one way to silence silent staleness is not to fix the claim, but to write down its scope. Saying which version a sentence is true for takes it out of wrongness and moves it into history.
The measurement’s assumptions:
- DT18 — The setup has three repository documents: readme, contribution guide, and architecture decision record. Other documents a repository might have are outside this measurement.
- DT19 — Surfaces and their frequencies are the same as the previous lessons’: signature every 2, flow every 3, name every 5, concept every 12 versions. These four numbers are not changed.
- DT20 — A document’s surface mix comes from how it is written and is as shown in the skeleton; the mix is held constant throughout the measurement.
- DT21 — The readme carries 12, the contribution guide 12, the architecture decision record 10 claims. The first two documents carrying equal claim counts is deliberate: so the difference does not come from length.
- DT22 — The share of claims embedded in a runnable example is 0.50 in the readme, 0.40 in the contribution guide, 0.00 in the architecture decision record. A claim bound to concept cannot be embedded.
- DT23 — A claim is stale if the surface it is bound to has changed at least once by the measured version, and no one corrects it.
- DT24 — First-loss version is the version at which a document produces its first stale claim. Half-life version is the first version at which the share of claims still true drops below 0.5.
- DT25 — The measurement builds versions 0, 2, 3, 5, 6, and 12; these versions were chosen to line up with the surface frequencies’ thresholds.
- DT26 — The set’s resolution is 1/12, 1/12, and 1/10 per document; differences below one claim cannot be defended with this set.
Measurement
"""Repository documents: each document's surface mix and lifespan. Part 1 - the three documents' surface mix and embedded claim count. Part 2 - true/stale/silent across versions, first-loss version, and half-life version. """ FREQUENCY = {"signature": 2, "flow": 3, "name": 5, "concept": 12} VERSIONS = (0, 2, 3, 5, 6, 12) # Three repository documents: surface mix in reading order. DOCUMENTS = { "readme": {"concept": 2, "flow": 4, "signature": 3, "name": 3}, "contribution guide": {"concept": 1, "flow": 6, "signature": 2, "name": 3}, "architecture decision record": {"concept": 7, "flow": 0, "signature": 1, "name": 2}, } # Share of claims embedded in a runnable example. EMBEDDED = {"readme": 0.50, "contribution guide": 0.40, "architecture decision record": 0.00} def claims(): entries, no = [], 0 for document, mix in DOCUMENTS.items(): embedded_target = 0 for surface, count in mix.items(): for _ in range(count): no += 1 embedded_target += EMBEDDED[document] embedded = embedded_target >= 1 and surface != "concept" if embedded: embedded_target -= 1 entries.append({"no": no, "document": document, "surface": surface, "embedded": embedded}) return entries def stale(i, version): return version // FREQUENCY[i["surface"]] >= 1 def measure(document, version, entries): group = [i for i in entries if i["document"] == document] gone_stale = [i for i in group if stale(i, version)] silent = [i for i in gone_stale if not i["embedded"]] return len(group), len(group) - len(gone_stale), len(gone_stale), len(silent) L = claims() print(f"documents {len(DOCUMENTS)} | claims {len(L)} | " f"embedded in example {sum(i['embedded'] for i in L)}") print() print(f"{'document':<28s} {'claims':>6s} {'concept':>7s} {'flow':>5s} {'signature':>9s} " f"{'name':>4s} {'embedded':>8s}") for b in DOCUMENTS: g = [i for i in L if i["document"] == b] print(f"{b:<28s} {len(g):6d} " + " ".join(f"{sum(1 for i in g if i['surface'] == y):>{w}d}" for y, w in zip(("concept", "flow", "signature", "name"), (7, 5, 9, 4))) + f" {sum(i['embedded'] for i in g):8d}") print() print(f"{'version':>7s} " + " ".join(f"{b:>28s}" for b in DOCUMENTS)) print(f"{'':7s} " + " ".join(f"{'true/stale/silent':>28s}" for _ in DOCUMENTS)) for s in VERSIONS: print(f"{s:7d} " + " ".join( f"{'{}/{}/{}'.format(*measure(b, s, L)[1:]):>28s}" for b in DOCUMENTS)) print() print(f"{'document':<28s} {'first loss':>10s} {'half-life':>10s} " f"{'true at v12':>12s} {'silent':>6s}") for b in DOCUMENTS: total = measure(b, 0, L)[0] first = next(s for s in range(1, 13) if measure(b, s, L)[2] > 0) half = next((s for s in range(1, 13) if measure(b, s, L)[1] / total < 0.5), 0) _, true, _, silent = measure(b, 12, L) print(f"{b:<28s} {first:10d} {half:10d} {f'{true}/{total}':>12s} " f"{silent:6d}")
documents 3 | claims 34 | embedded in example 10
document claims concept flow signature name embedded
readme 12 2 4 3 3 6
contribution guide 12 1 6 2 3 4
architecture decision record 10 7 0 1 2 0
version readme contribution guide architecture decision record
true/stale/silent true/stale/silent true/stale/silent
0 12/0/0 12/0/0 10/0/0
2 9/3/2 10/2/1 9/1/1
3 5/7/3 4/8/5 9/1/1
5 2/10/4 1/11/7 7/3/3
6 2/10/4 1/11/7 7/3/3
12 0/12/6 0/12/8 0/10/10
document first loss half-life true at v12 silent
readme 2 3 0/12 6
contribution guide 2 3 0/12 8
architecture decision record 2 12 0/10 10
Reading the Lifespans
The bottom table’s first column closes off a trap: first-loss version is 2 in all three documents. All three contain at least one signature claim, so all three give their first loss at the same moment. The moment a document “starts aging” distinguishes nothing; every document starts aging at the same time.
What distinguishes them is the slope. Half-life version is 3 for the readme, 3 for the contribution guide, 12 for the architecture decision record. The first two lose half of themselves within three versions, while the decision record still stands at 9/10 at that same point. The fourfold gap comes not from writing quality but from the mix: 7 of the decision record’s claims are bound to concept, and concept changes only once every twelve versions.
The version-five row is the table’s best summary. There, the readme gives 2/10/4, the contribution guide 1/11/7, the decision record 7/3/3. Three documents, written the same day in the same repository; five versions later, one still has seven of ten standing, the others one in twelve. If the maintenance budget is split evenly, two-thirds of it is wasted — maintenance assigned to the decision record does four times less work than the same maintenance assigned to the readme.
The silent column flips this trade-off around. By version twelve, all three documents are entirely stale; but 6 of the readme’s 12 stale claims are silent, 8 of the contribution guide’s 12, and 10 of the decision record’s 10 are all silent. The longest-lived document is the one whose decay is least heard. When the readme’s setup section breaks, every new reader sees it instantly; no one sees that the decision record is now invalid, because the decision record is never run — and a new decision gets made resting on it.
The version-three row also gives one last detail: the contribution guide’s special case. There the readme gives 5/7/3, the contribution guide 4/8/5. The flow surface changed exactly once and took six of the guide’s claims with it at once; the guide collapsed faster than the readme. What makes this uncomfortable is the reader’s identity. Whoever reads the contribution guide is, by definition, someone new to the repository; they do not have the knowledge to tell that a step is no longer valid and assume the wrong step is their own mistake. The repository’s most falsifiable text is handed to the reader least able to notice the wrong.
Two separate maintenance rules follow from this. The readme and the contribution guide need frequent but cheap maintenance: a check that runs the embedded examples catches six claims in the readme and four in the contribution guide on its own. The architecture decision record needs infrequent but expensive maintenance: only a human, returning to the decision’s context, can verify it. Auditing both documents on the same calendar means auditing both in the wrong place.
Summary
- Repository documents’ reader is not the product’s reader: the readme meets whoever looks at the repository first, the contribution guide meets whoever is about to touch the code, the architecture decision record meets whoever is looking for a reason.
- The readme binds to all four surfaces at once (2/4/3/3), the contribution guide is flow- and name-heavy (1/6/2/3), the architecture decision record is concept-heavy (7/0/1/2).
- First-loss version is 2 in all three and distinguishes nothing; what distinguishes them is half-life version: readme 3, contribution guide 3, decision record 12.
- At version five the decision record stands at 7/3/3, the readme at 2/10/4, the contribution guide at 1/11/7; an evenly split maintenance budget therefore goes to the wrong place.
- The longest-lived document decays the most silently: at version twelve, 10 of the decision record’s 10 stale claims are silent, versus 6 of the readme’s 12.
- Pointing instead of narrating moves a claim from signature to name and extends its life; for the decision record, writing its status moves a stale sentence out of wrongness and into history.
Next Step
In none of the three documents measured in this lesson did the signature share exceed half. The repository’s most crowded signature set sits elsewhere: in the interface reference. The second lesson left it at 2/15, and the reason was not the writer’s carelessness but that thirteen of the fifteen claims hung on the fastest surface. The next lesson takes that type on its own terms — how are endpoints, parameters, and errors documented — and measures a single question: do these claims have to be hand-written, and if not, how many survive, and what exactly is left?
To keep your progress and take notes, Log in
My notes
Log in to take notes.