Lesson 15 / 15
Release Publishing Workflow
Twenty-four work items and six reader questions decide 144 decisions: the raw change list answers 22 of them (0.153), the classified list 44, the meaning list 88, and with tag and release asset together 132 (0.917); all 12 of the 12 unanswered decisions are also from the unwritten requirement class.
Contents
The previous lesson saw the chain’s final transition as a single number: merged work gets bound to a point and announced outward. That announcement is itself a text and it has a reader — someone who never appeared through this whole course. Review knows the author and the reviewer; the release note’s reader has seen neither the change nor the discussion.
This lesson’s question is not how the note gets produced. The question is: what does the note tell the reader? How many questions does the gap between a list of changes and a list of the meaning of changes answer, and how many of the reader’s questions find no answer in any form?
What the Reader Asks
Someone reading a release note is not curious about the release; they are curious about their own situation. They ask six questions, and every question’s answer is found in the note only if a specific field was written.
The did it change question’s answer is in the title — this is the minimal field
that says something changed. The which area question wants a class: where the
change touched. The does it affect me question wants an impact; the what should I do question wants an action. The after which point question’s answer is a
boundary, and a tag gives it. The how do I get it question’s answer is an
asset, and a release asset gives it.
How a tag is placed and what it marks was established in the Introduction to Version Control course; which pipeline a release passes through to get published is the subject of the Continuous Integration and Delivery course. Neither is repeated here. In this lesson, the tag and the release asset are counted only as fields: two fields answering two of the reader’s questions.
Two Lists
The same release can be written in two formats, and both are produced from the same information.
# example release note — two formats, not executed ## change list - #377 timeout setting on the payment call - #381 retry counter fix - #388 log format updated ## meaning list ### Applications making outbound calls - The timeout duration is now configurable; the default did not change. To do: if no setting is given, behavior is the same, no action needed. - Retry count is two instead of three. To do: call paths expecting three attempts should be reviewed. ### Internal changes - Log format and style fixes; no effect on the reader's side.
The difference is not in length. The first list says what was done, the second says what happened to the reader. In the first list, all three lines carry the same weight; in the second, the change that does not concern the reader is folded into a single line, and the two items the reader actually needs to look at are separated out. The measurement counts these two differences separately: question answered and line scanned.
The measurement’s assumptions:
- TF29 — The release’s work items are taken from the shared setup’s set: 24
items, and the class distribution is the course’s fixed distribution.
changeand the class list are not modified. - TF30 — The item in the unwritten requirement class was never merged; it cannot enter any note format. The number of items entering the note is therefore 22.
- TF31 — The reader has six questions and every question’s answer stands in a single field. If the field is written, the question is answered; if not, it stays unanswered. There is no wrong answer in this measurement.
- TF32 — Four note formats are tried, and each covers the previous one’s fields: title; title and class; meaning list; the meaning list with tag and release asset added.
- TF33 — The reader-facing classes are interface, implementation, and documentation; test and style items do not change the reader’s situation. If the class field is not written, the reader cannot tell them apart and scans every line entering the note.
- TF34 — The set’s resolution is 1/24 at 24 items, 1/144 at the decision scale; one item’s one question is the smallest unit measurable in this measurement.
Measurement
"""Release note: the gap between a change list and a meaning list. Part 1 - four note formats and the reader's six questions. Part 2 - the line the reader scans against the line that is useful. """ SEED = 20260815 AXES = ("interface", "implementation", "test", "documentation", "style") UNWRITTEN = "unwritten requirement" CLASSES = AXES + (UNWRITTEN,) CHUNK = 50 # Reader's question -> the field carrying its answer. QUESTIONS = {"did it change": "title", "which area": "class", "does it affect me": "impact", "what should I do": "action", "after which point": "boundary", "how do I get it": "asset"} FORMATS = { "raw change list": ("title",), "classified list": ("title", "class"), "meaning list": ("title", "class", "impact", "action"), "meaning + tag + asset": ("title", "class", "impact", "action", "boundary", "asset"), } # Reader-facing class: the release note's reader searches for these. READER_FACING = {"interface", "implementation", "documentation"} def rng(seed): d = seed % 2147483646 + 1 def draw(n): nonlocal d d = (d * 48271) % 2147483647 return d % n return draw def change(lines, defect_count=24, seed=SEED): draw, defects = rng(seed), [] chunk_count = max(1, lines // CHUNK) for i in range(defect_count): defects.append({"no": i + 1, "class": CLASSES[draw(6)], "chunk": draw(chunk_count)}) return {"lines": lines, "chunks": chunk_count, "defects": defects} d = change(600) # The release's work items: the class distribution is the course's fixed distribution. ITEMS = [{"no": k["no"], "class": k["class"]} for k in d["defects"]] # The unwritten class was never merged; it cannot enter any note format. IN_NOTE = [o for o in ITEMS if o["class"] != UNWRITTEN] distribution = {s: sum(1 for o in ITEMS if o["class"] == s) for s in CLASSES} print("release: " + ", ".join(f"{s} {n}" for s, n in distribution.items())) print(f"work items {len(ITEMS)} | in note {len(IN_NOTE)} | reader questions " f"{len(QUESTIONS)} | decisions {len(ITEMS) * len(QUESTIONS)}") print() print(f"{'note format':<24s} {'fields':>6s} {'answered':>8s} {'unanswered':>10s} " f"{'ratio':>6s} {'from unwritten':>14s}") total = len(ITEMS) * len(QUESTIONS) for name, fields in FORMATS.items(): answered = sum(1 for o in IN_NOTE for s in QUESTIONS if QUESTIONS[s] in fields) unwritten = (len(ITEMS) - len(IN_NOTE)) * len(QUESTIONS) print(f"{name:<24s} {len(fields):6d} {answered:8d} {total - answered:10d} " f"{answered / total:6.3f} {unwritten:14d}") print() print(f"{'note format':<24s} {'scanned lines':>13s} {'useful':>6s} {'ratio':>6s}") for name, fields in FORMATS.items(): # No class field: the reader scans every line; with it, only the reader-facing group. scanned = (len(IN_NOTE) if "class" not in fields else sum(1 for o in IN_NOTE if o["class"] in READER_FACING)) useful = sum(1 for o in IN_NOTE if o["class"] in READER_FACING) print(f"{name:<24s} {scanned:13d} {useful:6d} {useful / scanned:6.3f}")
release: interface 3, implementation 6, test 3, documentation 3, style 7, unwritten requirement 2 work items 24 | in note 22 | reader questions 6 | decisions 144 note format fields answered unanswered ratio from unwritten raw change list 1 22 122 0.153 12 classified list 2 44 100 0.306 12 meaning list 4 88 56 0.611 12 meaning + tag + asset 6 132 12 0.917 12 note format scanned lines useful ratio raw change list 22 12 0.545 classified list 12 12 1.000 meaning list 12 12 1.000 meaning + tag + asset 12 12 1.000
Reading the Gap
22 of a hundred forty-four decisions are answered in the raw change list — a ratio of 0.153. The list is complete, no work item is skipped, and it does not answer five of the reader’s six questions. Completeness and answering are not the same thing.
Adding the class field raises answered to 44, the meaning list to 88. The real jump is in the third row: the impact and action fields alone carry 44 decisions, roughly a third of the set. What these two fields share is that neither can be derived from the merged work. Title and class can be extracted from the merged work; impact and action exist only if someone writes them.
In the fourth row, the ratio climbs to 0.917. This number is familiar in the course: in a 100-line change, the ratio of defects found was also 0.917. This is not a coincidence — in both cases what is left out is exactly 2/24, and those two items belong to the same class.
The table below gives the second gap. In the raw list, the reader scans 22 lines and 12 of them are useful: ratio 0.545. Close to half the reader’s reading is wasted. Once the class field is added, scanned drops to 12 and the ratio becomes 1.000. What stands out is that this gain is secured at the second row: grouping cuts the reader’s scanning in half before impact and action are even written. The cheapest improvement is not rewriting the note, it is classifying it.
Summary
- The release note’s reader has seen neither the change nor the discussion; they have six questions, and every question’s answer stands in a single field written in the note.
- The raw change list answers 22 of a hundred forty-four decisions (0.153), the classified list 44, the meaning list 88, and with tag and release asset together 132 (0.917).
- The impact and action fields alone carry 44 decisions, and neither can be derived from the merged work; they exist only if someone writes them.
- The reader scans 22 lines in the raw list and uses 12 (0.545); the class field drops scanned to 12 and makes the ratio 1.000 — this gain is secured without writing impact or action.
- All 12 of the 12 unanswered decisions also belong to the unwritten requirement class; unmerged work shows up in no note format.
Course Wrap-Up
The course ran on a single measure: a review’s number is not how many people are looking, it is how many axes are being looked at and how many chunks are read. Fifteen lessons applied this measure to separate places.
| lesson | measured | found or missed |
|---|---|---|
| Purpose of Code Review | what axis diversity finds | three reviewers on the same axis find 6, on separate axes 15, a single reviewer on five axes 22, five reviewers again 22; 2 unwritten-requirement defects are missed in all four |
| Meaning of Interface | the cost of closing one axis | the five axes’ sets are disjoint, the sum of pairwise intersections is 0; closing interface drops found from 22 to 19, and ten reviewers without interface stay at 19 |
| Meaning of Implementation | an axis’s marginal contribution | implementation adds 6 in both orders, style adds 7, the remaining three add 3 each; 1, 3, and 12 readings on the same axis stay at 6, ratio 0.250 |
| Reviewing Tests | the defect the test itself carries | three test defects sit in chunks 9, 1, and 7, and those chunks already had 1, 2, 1 findings from other axes; missed in an unread chunk is 0 on all five axes, and closing the test axis drops found from 22 to 19 |
| Documentation Review | what is missed when the documentation axis is closed | the five axes’ individual closing cost is 3, 6, 3, 3, and 7; closing documentation drops found from 22 to 19, documentation missed is 0 while the axis is open, and unwritten missed stays at 2 |
| Code Style and Automation | attention shifting once the style axis is handed to a tool | human findings drop from 22 to 15, style’s share from 0.318 to 0.000; the tool’s contribution equals the axis left uncovered — 0 if five axes are covered, 15 to 22 with three reviewers, and missed stays at 2 in the best tooled case |
| Change Size | size against fixed attention | 22 (0.917) at 100 and 300 lines, 18 (0.750) at 900, 2 (0.083) at 2400; 36 of 48 chunks go entirely unread |
| Feedback Language | the round the same finding’s wording produces | actionable 2 rounds / 12 wait / 44 note-rounds, observation 3 / 18 / 66, criterion-free 4 / 24 / 88; found stays at 22 and missed at 2 |
| Disagreement Resolution | the round an unresolved finding carries | rule absence: 6 rounds / 36 wait and 8 defects in the code; binding to a criterion: 3 rounds / 18 units and only 2 in the code |
| Review Metrics | wait, round, and queue health | three reviewers on the same axis: 6 rounds / 36 wait / 3 remaining, single reviewer on five axes: 2 / 12 / 0; longest open time in the queue is 2 rounds versus 15 |
| Issue Tracking and Boards | chain wait and review’s share | wait outside review fixed at 19, the link between 12 and 36, share between 0.387 and 0.655; 3 remaining defects take the chain from 55 to 105 |
| Contribution Guidelines | the round a written expectation closes | in a narrow review, round is 6, 5, 4, 3, 2 and wait drops from 36 to 12; a requirement statement drops unwritten-requirement missed from 2 to 0 |
| Ownership and Approval Rules | the effect of required reviewers on axis diversity | as approvals climb from 1 to 3, found stays at 6, rounds at 6, wait at 36; a single approval with no axis restriction finds 22, and in narrow ownership 4 axes stay open with 16 defects standing there |
| Repository Platform Capabilities | the transition each capability shortens | the chain drops from 45 to 21, gain 24; found 15, missed 9, and unwritten missed 2 stay fixed in every row; discussion’s gain is 4, 6, 12 |
| Release Publishing Workflow | the question the note answers the reader | 22 (0.153), 44, 88, and 132 (0.917) of 144 decisions; all 12 of the 12 unanswered are unwritten requirement |
Three readings come out of the table. First: what grows the number is not the person, it is the axis, and this was reconfirmed in every topic — a third person looking at the same axis adds 0, a new axis adds between 3 and 7 defects. Second: what determines round and wait is what could not be seen in the first round; the guide, ownership rule, and platform capabilities touch wait, not what is found. Third: the same two defects are missed across all fifteen rows. Adding an axis, shrinking size, cutting the round, writing a rule, opening a surface — none of them reaches them. The one mechanism that reaches them was the guide item requiring the author to write the requirement, and it was not a review tool.
The third reading draws the course’s boundary. Review looks at what was submitted. Everything inside a submitted change — its interface, implementation, test, documentation, style — can be seen with enough axes and a small enough size. The absence of what was never submitted is not review’s subject; only writing it closes that gap.
The next course — Technical Writing and Documentation — takes up exactly this work: the separation of document types from each other, the separate structures of tutorial and reference, the repository’s own documents, the layout of an interface reference, and writing release notes with the reader’s meaning in view. This lesson’s final measurement leaves a number there: how many of the six questions a note answers depended not on who wrote the note but on which fields were written. The distinction has to be set from the start: review looks at what was written; writing what was not written is a separate job. The measure this course leaves behind is the unit that will be used there to count how many questions every document written counts as answering.
To keep your progress and take notes, Log in
My notes
Log in to take notes.