Lesson 05 / 15
Release Notes
The four types describe the product as it is today and none carries time; the raw change list dates 17 of 56 stale claims by version twelve and 0 of the silent ones, while a note that writes what each entry falsifies dates 56 of 56 and 39 of 39 silent ones.
Contents
The previous lesson left the generated reference at 13/15 by version six and left the reader owing a question: when did the remaining two drop? The second lesson had already given this question a name — one of the six reader questions, “what version did this change in,” landed on none of the four types.
This lesson measures the text that closes that gap. What is being asked is not how release notes get published, but what they make datable: a reader looking at a stale claim — where will they learn which version falsified that sentence?
The One Text That Carries Time
The four types share a trait that has never yet been named: all four are written in the present tense. A tutorial says how to start today, a how-to says how to do it today, an explanation says why it is that way today, a reference says which field is of which type today. All four are texts that erase the past; when a field’s type changes, the reference does not mention the old type, it writes the new one, and the old one is treated as if it never existed.
This is a correct design for the four types. If history were folded into the reference, the reader would have to sort out, in every cell, which line belongs to today, and the reference’s one job — fast confirmation — would be lost. But it has a cost: because no type carries time, none of them can answer “when did this change.”
Release notes sit exactly in this gap, and what separates them from the others is not their content but their index. The four types are indexed by subject: the reader looks for a subject, opens that subject’s section. Release notes are indexed by time: the reader looks for a version, opens that version’s entry. This is why release notes are not a fifth type but a separate type standing on a separate axis.
Which pipeline a release ships through, how the note’s fields meet the reader’s six questions, and what a tag marks were measured in the Code Review and Team Process course and are not repeated here. What was measured there was what the note says to the reader; what is measured here is what it does to the other documents.
Two Lists
The same release can be written in two forms, and both are produced from the same event.
# two forms of the invented product's release notes
# example text, not executed
raw change list
v6 measurement call's option names were reorganized
v6 step order in the summary flow changed
meaning list
v6 measurement call's option names were reorganized
falsified: reference's parameter lines,
how-to text's call examples
v6 step order in the summary flow changed
falsified: tutorial's third and fourth step
The two lists carry the same number of entries. The difference is in a single field: the second writes, for every entry, what it falsified. This field looks like an ordinary detail but it reverses the direction. The raw list is written from the change’s side: it narrates the work done. The meaning list is written from the document’s side: it says which sentences are false as of today.
This distinction’s effect on the reader has to do with when the note is useful. A reader looking at the raw list has to already know what they are looking for. If an example blew up on them, they know which call broke and search the list for that call; once found, they also learn the date. But if nothing has blown up, they have no reason to look at the list at all, because they do not know which sentence went false. A raw list serves a reader who has already heard about the failure.
The Length of a Note
The cost of writing a note is its number of entries, and that number is not as large as it seems. Across twelve versions, surfaces change at their own rates; some versions no surface changes, and some, more than one changes at once. A note carries an entry only for versions where a change happens. The measurement will also give this entry count, and the number of claims dated per entry.
When an entry gets written is a choice too, and it determines the result. If the note is written all at once on release day, the writer has to reconstruct, after the fact, which sentences every change falsified; by that point this information is not easy to find and in practice does not get written. If the entry is written at the moment of the change, the person who knows the falsified sentence is already there: the person making the change. The gap looks like a discipline question, but it directly determines the measured column — in the table below, the only field separating the meaning list from the raw list is cheap only at that moment.
The measurement’s assumptions:
- DT37 — The measured set is the course’s shared setup: 56 claims, four types, four surfaces, and 17 embedded examples. The mix is not changed.
- DT38 — Surface frequencies are fixed: signature every 2, flow every 3, name every 5, concept every 12 versions. A surface changes once at every version that is a multiple of its frequency.
- DT39 — A claim’s fall version is the first version at which the surface it is bound to changes, and it is known because we wrote the setup. The reader knows it only if it was written down.
- DT40 — Release notes carry one entry for every version at which at least one surface changes. Versions where no surface changes carry no entry.
- DT41 — Three note formats are tried: no release notes, raw change list, and meaning list. All three are produced from the same events.
- DT42 — With no release notes, a stale claim cannot be dated; none of the four types carries time.
- DT43 — The raw change list writes only what was done. For it to make a claim datable, the reader has to have already suspected that claim; in this measurement, suspicion only arises when an embedded claim breaks.
- DT44 — The meaning list writes the falsified claims into every entry; the reader does not need to suspect anything, every stale claim becomes datable.
- DT45 — For a claim to count as datable, it must first be stale; a claim still true does not enter this column.
- DT46 — The set’s resolution is 1/56; at the note-entry scale it is 1/9.
Measurement
"""Release notes: is a claim's fall datable for the reader when it goes stale. Part 1 - change events across twelve versions and the note's entry count. Part 2 - datable stale claims and the silent share, under three note formats. """ TYPES = { "tutorial": {"flow": 9, "signature": 3, "name": 2, "concept": 1}, "how-to": {"flow": 6, "signature": 5, "name": 2, "concept": 1}, "explanation": {"flow": 1, "signature": 1, "name": 1, "concept": 9}, "reference": {"flow": 0, "signature": 13, "name": 2, "concept": 0}, } FREQUENCY = {"signature": 2, "flow": 3, "name": 5, "concept": 12} EMBEDDED = {"tutorial": 0.60, "how-to": 0.70, "explanation": 0.10, "reference": 0.00} VERSIONS = (2, 3, 5, 6, 12) LAST = 12 def claims(): entries, no = [], 0 for kind, mix in TYPES.items(): embedded_target = 0 for surface, count in mix.items(): for _ in range(count): no += 1 embedded_target += EMBEDDED[kind] embedded = embedded_target >= 1 and surface != "concept" if embedded: embedded_target -= 1 entries.append({"no": no, "type": kind, "surface": surface, "embedded": embedded, "fall_version": FREQUENCY[surface]}) return entries def events(last=LAST): """Which surfaces change at each version: the entries the note will write.""" return [(s, [y for y in FREQUENCY if s % FREQUENCY[y] == 0]) for s in range(1, last + 1) if any(s % FREQUENCY[y] == 0 for y in FREQUENCY)] # Note formats: under what condition they make a stale claim datable. FORMATS = { "no release notes": lambda i: False, "raw change list": lambda i: i["embedded"], "meaning list": lambda i: True, } L = claims() O = events() print(f"claims {len(L)} | embedded in example {sum(i['embedded'] for i in L)} | " f"change events across twelve versions {sum(len(y) for _, y in O)} | " f"note entries {len(O)}") print("note entries: " + "; ".join(f"v{s}: {', '.join(y)}" for s, y in O)) print() print(f"{'version':>7s} {'stale':>5s} {'silent':>6s} " + " ".join(f"{ad:>23s}" for ad in FORMATS)) print(f"{'':7s} {'':5s} {'':6s} " + " ".join(f"{'datable/of silent':>23s}" for _ in FORMATS)) for s in VERSIONS: stale = [i for i in L if s // FREQUENCY[i["surface"]] >= 1] silent = [i for i in stale if not i["embedded"]] row = f"{s:5d} {len(stale):5d} {len(silent):6d} " for ad, rule in FORMATS.items(): t = [i for i in stale if rule(i)] ts = [i for i in t if not i["embedded"]] row += f" {f'{len(t)}/{len(ts)}':>23s}" print(row) print() print(f"{'note format':<24s} {'entries':>7s} {'dated claims':>12s} " f"{'per entry':>10s} {'of silent':>9s}") last_stale = [i for i in L if LAST // FREQUENCY[i["surface"]] >= 1] last_silent = [i for i in last_stale if not i["embedded"]] for ad, rule in FORMATS.items(): t = [i for i in last_stale if rule(i)] ts = [i for i in t if not i["embedded"]] entries = 0 if ad == "no release notes" else len(O) share = len(t) / entries if entries else 0 print(f"{ad:<24s} {entries:7d} {f'{len(t)}/{len(last_stale)}':>12s} " f"{share:10.3f} {f'{len(ts)}/{len(last_silent)}':>9s}")
claims 56 | embedded in example 17 | change events across twelve versions 13 | note entries 9
note entries: v2: signature; v3: flow; v4: signature; v5: name; v6: signature, flow; v8: signature; v9: flow; v10: signature, name; v12: signature, flow, concept
version stale silent no release notes raw change list meaning list
datable/of silent datable/of silent datable/of silent
2 22 17 0/0 5/0 22/17
3 38 24 0/0 14/0 38/24
5 45 28 0/0 17/0 45/28
6 45 28 0/0 17/0 45/28
12 56 39 0/0 17/0 56/39
note format entries dated claims per entry of silent
no release notes 0 0/56 0.000 0/39
raw change list 9 17/56 1.889 0/39
meaning list 9 56/56 6.222 39/39
Reading Datability
The first line gives the note’s length: across twelve versions there are 13 change events, but the note carries only 9 entries. At three versions more than one surface changes at once — signature and flow at version six, signature and name at ten, all three at twelve. At three other versions nothing changes, and the note carries no entry for them.
The top table’s left columns give the course’s familiar numbers: stale claims are 22 at version two, 38 at three, 45 at five, 56 at twelve; silent ones are 17, 24, 28, and 39 respectively. The three columns on the right show what the reader can date at those same rows.
With no release notes, every row gives 0/0. This is the numeric counterpart of the lesson’s opening claim: no matter how well the four types are written, none can say when a single claim went false.
The raw change list dates 5 at version two, 14 at three, 17 at five, and stops there. Even though stale claims climb to 56 by version twelve, the raw list stays stuck at 17. This is not a coincidence: the embedded claim count is 17, and the raw list dates exactly those, not one more. Past version five the raw list’s curve flattens: changes keep happening, the note keeps growing, but the number of dated claims stays fixed. The effort spent writing the note rises; its return does not.
The real finding sits in the raw list’s share on the right: 0/39. Of the thirty-nine silently stale claims, not one can be dated with the raw change list. The reason is plain — a raw list serves only a reader who already suspects something, and a silent claim raises no suspicion in anyone. A raw list is text that does nothing unless the reader already knows; for a reader who does not know, it does nothing at all.
The meaning list dates the entire stale count at the same rows: 22/17, 38/24, 45/28, and 56/39. The last column gives this in a single ratio — 39 of the thirty-nine silent claims become datable.
The bottom table measures the cost, and it holds the lesson’s most practical result. Both formats carry 9 entries. The meaning list is not a longer note; it is the same nine entries with one extra field written into them. In exchange, dated claims per entry climb from 1.889 to 6.222 — more than three times. The writing order can be said in one sentence: it is not enough to write what was done to an entry; what it falsified has to be written too.
This is the first mechanism in the course that reaches silent staleness, and how it gets there matters. What made silent staleness invisible was that no signal came from the document itself. The meaning list draws its signal not from the document but from the change itself: which sentences went false is known at the moment the code changes, not afterward. What the note holds is that moment. If it is not written, it is lost and can never be produced again.
What the Note Does Not Close
The table says what the note does; what it does not do also needs writing, because the 56/56 picture promises more than it delivers.
First: dating is not fixing. The meaning list tells the reader “the reference’s parameter line went false at version six”; it does not say what the correct value is. The reader learns the wrong, not the right. This is still a large gain — knowing something is wrong is better than believing it is right — but it does not move the claim back into the true column. In the table, the true column never changes under any note format; what changes is only how visible the stale one is.
Second: the note’s reader is not the document’s reader. Whoever follows release notes already uses the product. A reader arriving for the first time today does not read past notes; for them the document is still timeless, and nothing but the 17 embedded claims gives them any warning. The meaning list makes staleness visible for the maintainer, not for the new reader.
Third: a note is only as correct as it is written, and it is itself a document. The “falsified” field in its entries depends on the document’s structure at the moment it was written; when sections get reorganized, that field goes stale too. The note itself was kept outside this measurement, but in a real repository it also enters the counted set.
Summary
- The four types are written in the present tense and indexed by subject; release notes are a separate type indexed by time, and only they close the “what version did this change in” question.
- Thirteen change events across twelve versions become 9 note entries; some versions see more than one surface change at once, some see none.
- With no release notes, 0/56 of stale claims are datable; with the raw change list, 17/56 — equal to the embedded claim count — and it does not grow further by version twelve.
- The raw change list dates 0 of the 39 silently stale claims; it serves only a reader who has already heard about the failure.
- The meaning list dates 56/56 with the same 9 entries and 39/39 of the silent ones; dated claims per entry climb from 1.889 to 6.222.
- The gap is not in entry count but in the falsified-claims field written into an entry; this information exists at the moment of change and cannot be produced afterward if not written down.
Next Step
This lesson closed one of the reader’s two unanswered questions. The second remains, and it is asked far more often than the first: “why is this not working?” The reader arriving with this question knows neither a subject name nor a version number; all they have is a symptom — an error line, an empty output, a result other than expected. What they have is only what the product showed them, and what it showed matches no section heading in the document. The next lesson compares the reader questions a symptom-first text covers against those a concept-first text covers, and names the boundary troubleshooting content cannot reach.
To keep your progress and take notes, Log in
My notes
Log in to take notes.