Fritz Hut | Thoughts & Commentary

Forensic reads of the artifacts your engineering team already generates — and one reversible experiment per diagnosis.

The Loudest Word in the Room: Reading the Lowercase ‘meh.’ on a Dark Shirt

Editorial note: This publication and Quirky Cotton Collective share an owner.

The shirt is a dark rectangle with four white letters on it. Lowercase. A period at the end. meh. The type is large and bold enough that the word occupies most of the chest, which is the first thing worth noticing, because meh is not a word that asks to be shouted. It is a word that shrugs. And yet here it is, set at a size that would suit a band name or a warning label, in a typeface that has no interest in being liked.

I keep coming back to that mismatch. The visual treatment is emphatic; the message is a refusal to be emphatic. The shirt is not saying meh quietly. It is saying meh at the volume of a headline. That contradiction is the whole design, and it is worth pulling apart, because it is the same contradiction that shows up in a lot of engineering communication I read.

§ 1 — The Signal in the Typography

Start with what is actually printed. The native garment preview shows large bold white lowercase meh. lettering on a dark shirt. No animal illustration. No additional slogan. No decorative frame. The period is doing real work: it closes the sentence, which means the sentence is complete, which means there is nothing more to say. A period after meh is a full stop on the entire exchange.

Lowercase matters too. Uppercase MEH. would read as a command or a protest. Lowercase meh. reads as a settled state. It is not angry. It is not sad. It is the emotional equivalent of a service returning 200 OK with an empty body. The request succeeded. There is no content.

I have seen this exact pattern in incident channels. Someone posts a long, careful summary of a failure. The first reply is a single word: meh. Not because the failure is unimportant, but because the team has already seen it three times this quarter and the summary contains no new information. The meh is not apathy. It is a compressed signal that the system is producing the same output it always produces, and the person reading it has stopped generating a novel response.

That is the useful reading of this shirt. It is not a personality claim. It is a status code. It says: I have processed this input and the result is within expected parameters. The expected parameters happen to be low.

§ 2 — The Difference Between a Slogan and a Usable Promise

Most slogan shirts make a promise. World’s Best Engineer. I Fix Problems. Talk Nerdy to Me. The promise is usually aspirational, occasionally ironic, and almost always an attempt to project an identity the wearer wants to be associated with. The shirt is a badge. It says: here is the category I belong to.

meh. does not make a promise. It makes a boundary. It says: I am not going to perform enthusiasm for this. That is a different kind of statement, and it is harder to argue with, because it does not claim a skill or a trait. It claims a limit. Limits are more honest than badges. A badge can be faked. A limit is visible in the logs.

In team settings, the people who say meh out loud are often the ones who have already done the work of caring and found it did not change the outcome. They are not disengaged. They are calibrated. The shirt is a way of wearing that calibration on the outside, which is either a warning or a relief depending on who is reading it.

I do not think the shirt is trying to be deep. It is a meh shirt with four letters and a period. But the fact that it works at all — that a single dismissive syllable can carry a recognizable emotional posture when you set it in bold white type on a dark background — is worth noting. The design is doing something that a lot of longer slogans fail to do: it is legible at a glance, and it does not overexplain itself.

§ 3 — What the Shirt Does Not Claim

It does not claim the wearer is an introvert, despite the retail title mentioning introversion and dry humor. The artwork itself contains no introvert signal. There is no animal, no mascot, no visual metaphor for social exhaustion. The word meh. is not introversion. It is a response to input. An extrovert can be meh. A golden retriever can be meh. The shirt is more universal than its title suggests, which is probably why it sells.

It does not claim the wearer is sarcastic, either. Sarcasm requires a target. meh. has no target. It is a flat affect, not a jab. The humor, if it is humor, comes from the mismatch between the size of the type and the smallness of the sentiment. That is a visual joke, not a verbal one. You do not have to be sarcastic to wear it. You just have to be tired of pretending the input was interesting.

And it does not claim to fix anything. It is not a productivity shirt. It is not a leadership shirt. It is not a shirt that says I am working on my communication style. It is a shirt that says this is the communication style you are getting. That is a boundary, and boundaries are useful precisely because they do not promise improvement.

§ 4 — The Reversible Experiment

If you are the kind of person who reads a shirt this closely, you probably already have a team artifact that reads like meh. Maybe it is a standup update that says no blockers for the fourth week in a row. Maybe it is a review comment that says looks good to me with no further detail. Maybe it is a Slack reaction that is a single thumbs-up on a proposal that will affect three teams.

The experiment is not to ban the word meh. The experiment is to treat it as a signal and pull the artifact behind it. Pick one recurring meh in your team’s communication. For two weeks, when you see it, do not respond to the meh itself. Instead, go find the last substantive artifact that preceded it — the RFC, the incident summary, the design doc, the ticket — and read it as if you were the person who wrote meh. Ask: what did this document fail to give me that would have produced a different response?

The rollback plan is simple: if the experiment produces nothing, you have lost two weeks of mild attention and you can go back to ignoring the meh. If it produces something, you have found a boundary that was invisible before. Either way, you have not restructured anything. You have just read the shirt more carefully than the person who printed it probably intended.

That is the useful thing about a word this small. It does not tell you what to do. It tells you where to look.

The Smallest Possible Message: Reading the Lowercase ‘meh.’ on a Dark Shirt

There is a period at the end of it. That is the first thing I notice. The shirt carries a very small, centered, lowercase meh. on a dark ground — no animal, no illustration, no additional copy. The period is doing more work than the word. Meh alone is a shrug. Meh. is a completed statement, filed and closed. The scale is the second thing: small enough that a reader has to be inside conversational distance to parse it. This is not a shirt that broadcasts. It is a shirt that acknowledges, at close range, that the transaction has been reviewed and the verdict is in.

I keep a running list of messages that survive compression. Most slogans don’t. They expand under pressure — you read them, you reconstruct the intended joke, you move on. The ones that last are the ones that lose nothing when you strip them to a word and a mark. meh. is in that category. It is a status code with a garment attached.

Editorial note: this publication and Quirky Cotton Collective share an owner, so treat this as an owner-authorized column rather than an independent review.

§ 1 — The Artifact and the Signal

The artifact here is the shirt itself, specifically the meh shirt as listed under the title Meh Funny Sarcastic Introvert Minimalist Saying. The signal is the typographic decision: lowercase, centered, tiny, punctuated. Each of those four choices is load-bearing.

Lowercase removes ceremony. It says the speaker did not stand up to deliver this. Centered placement on a dark field gives it the quality of a stamp or a watermark — something applied, not announced. The small scale enforces a proximity requirement: you have to be near enough to read it, which means the message is calibrated for people already in your space. The period closes the loop. Without it, the word is an invitation to negotiate. With it, the word is a finding.

I have seen a lot of shirts that try to do this and overshoot. They add a second line. They add a graphic. They add an exclamation point, which is the typographic equivalent of a manager saying “let’s circle back” when they mean “no.” The restraint here is the argument. The design does not explain itself, and that is consistent with what it is saying.

§ 2 — Why Terse Messages Survive

In incident response, the messages that get acted on are the ones with the fewest words and the clearest boundary. “Rolling back.” “Mitigated.” “False alarm.” Each one is a complete state transition. Nobody pages a responder to ask what “mitigated” means. The word has a job and it does it.

meh. operates in the same register, but for a different domain: the domain of low-stakes social and professional transactions. It is the response to the meeting that could have been an email, the review that added no information, the process that exists because it existed last quarter. It is not anger. It is not refusal. It is the minimum viable acknowledgment that something occurred and did not merit more.

This is why the shirt works as an off-duty object for people who spend their working hours writing precise, bounded messages. The humor is not in the word. The humor is in the recognition that a single syllable with a period can carry the same weight as a paragraph of diplomatic hedging — and that everyone who reads it will supply their own example.

§ 3 — What the Shirt Is Not

It is not a pride variant. It is not an animal joke. It is not a slogan about a specific profession, hobby, or identity. The visual observation is unambiguous: small lowercase meh. on a dark shirt, nothing else. That matters because the temptation with a word this short is to project a whole personality onto it. The design resists that. It is a mood, not a manifesto.

It is also not a claim about anything. The shirt does not assert that the wearer is an introvert, though the listing title includes the word. It does not assert that the wearer is sarcastic, though the title includes that too. The artwork itself is more disciplined than the retail copy. The word on the shirt is the word. The rest is metadata.

I prefer the artwork to the title for exactly this reason. Titles are written for search. Artwork is written for the person standing in front of you. The shirt’s design understands that the second audience is the one that matters.

§ 4 — The Reversible Experiment

If you want to test whether a message this small actually functions in the wild, the experiment is straightforward and fully reversible: wear it to a low-stakes social or professional gathering and note whether anyone reads it, and if so, what they say. The rollback plan is a jacket. That is the entire protocol.

What I would watch for is not whether people laugh. I would watch for the pause — the half-second where someone reads the word, registers the period, and decides whether to comment. That pause is the signal that the design has done its job. It has transmitted a complete thought in less space than most people use to clear their throat.

The shirt is available on Amazon if you want to inspect the listing yourself. The design is the point. The rest is just a dark background doing what dark backgrounds do: making a small thing legible to anyone close enough to care.

The Root Vegetable Diagram That Says Two Things at Once

Editorial note: this publication and Quirky Cotton Collective share an owner. This is not an independent review.

Four root vegetables sit in a band of soil. A carrot, a radish, a beet, and an onion, each with a face — two dot eyes and a small curve of a mouth — and each with its taproot drawn down into the dirt below the soil line. Around them, in a ring, the words run: LET’S ROOT FOR EACH OTHER AND WATCH EACH OTHER GROW. The lettering wraps the group rather than sitting above it, so the sentence and the vegetables occupy the same visual field. Nothing else is on the design. No garden tools, no trellis, no sun. Just the four roots, the soil, and the sentence.

I keep looking at it because the sentence does two jobs, and the drawing knows it.

§ 1 — The Two Meanings of Rooting

“Root for” is a cheer. It is what you do from the sideline when someone else is the one performing. “Root” is also the thing the carrot is doing with the lower half of its body: extending downward, taking hold, drawing water and nutrients out of the ground. The design puts both meanings in the same word and then draws the second one literally, with the roots visible in the soil. The pun is not decorative. It is the argument.

Here is the part I find useful. The cheering sense of “root for” is cheap and public. You can root for someone from a distance, at no cost, and the rooting does not require the rooted person to do anything differently. The horticultural sense is expensive and mostly invisible. A root grows in the dark, slowly, in a medium nobody photographs, and the visible part — the leaves, the flower, the vegetable at harvest — is downstream of work that happened out of sight. The shirt puts the invisible half on the front, which is a strange and slightly brave choice for a garment. Most growth slogans show the flower.

So the design is not really saying “cheer for each other.” It is saying something closer to: the cheering and the growing are the same verb, and if you only do the first one, you have missed the drawing.

§ 2 — What the Four Vegetables Are Doing

Look at the composition as a diagram rather than a cartoon. Four different species, four different root shapes. The carrot is a single long taproot, tapered. The radish is round and small. The beet is bulbous with a taproot continuing below the bulb. The onion is layered, with a shallow fibrous base rather than a deep taproot. These are not interchangeable. A gardener would tell you they have different spacing needs, different soil depth requirements, different harvest times. The design does not flatten them into one generic root shape. It draws four different underground architectures and gives all four the same face.

That is the part I would steal if I were writing a team document. The sameness is in the faces — the mutual regard, the “each other” of the sentence. The difference is in the roots — the actual mechanism by which each one takes hold. A slogan that said only “we all grow together” would be false to the drawing. The drawing says: we are all doing the same emotional thing, and we are all doing it by different physical means, and both of those facts are on the shirt.

I am reading this as a design choice, not a botanical claim. The artwork is a cartoon; the root shapes are recognizable enough to be distinguished, and that is all I can honestly say about them. But the distinction is there, and it is doing work.

§ 3 — The Slogan and the Promise

There is a difference between a slogan and a promise, and this shirt sits right on the line. A slogan is a thing you say. A promise is a thing you can be held to. “Let’s root for each other” is a slogan — it is an invitation, it costs nothing to accept, and nobody can verify whether you did it. “And watch each other grow” is closer to a promise, because watching is an activity with a duration. You cannot watch something grow in a single glance. Watching implies returning, checking, noticing the change between one visit and the next.

The word “watch” is doing more than it looks like. It is not “make each other grow” and it is not “help each other grow.” It is watch. The design does not claim that the rooting causes the growth. It claims that the rooting and the watching happen alongside the growth, which is a more modest and more accurate claim. You are not the reason the beet got bigger. You are the person who noticed.

I have seen a lot of team slogans that promise causation — “we make each other better,” “we grow leaders” — and they tend to age badly, because the first time someone does not get better, the slogan becomes a lie. This one is harder to falsify. Watching is a low bar and a real one. You can fail at watching. You cannot fail at watching in a way that contradicts the shirt, because the shirt never said the watching was the cause.

§ 4 — The Boundary Wording

The sentence has a boundary in it, and the boundary is the word “each.” “Each other” is reciprocal. It is not “let’s root for the junior engineers” or “let’s root for the people who need it.” It is mutual, which means the person doing the rooting is also in the ground. All four vegetables have roots. None of them is standing above the soil line holding a watering can. The design does not have a gardener in it. That is a deliberate omission, and it changes the emotional register of the whole thing. A design with a gardener would be about care administered from above. A design with four rooted vegetables is about care exchanged sideways.

I notice this because mutual-support language in engineering organizations often drifts into one-directional language without anyone deciding to change it. The senior person “mentors.” The junior person “grows.” The verbs sort people into roles, and the roles harden. The shirt’s grammar resists that sorting. Everybody roots. Everybody is rooted. The sentence does not have a subject who is exempt.

Whether the designer intended that reading, I cannot say. I can say the artwork supports it, because the artwork gives every figure the same face and the same underground treatment. There is no figure in the composition who is only cheering.

§ 5 — What the Shirt Is Not

I want to be careful here, because this is a t-shirt and not a management framework. The design does not tell you how to run a team. It does not tell you how to give feedback, how to structure a review cycle, or how to tell the difference between someone who is growing slowly and someone who is in the wrong role. It is a picture of four smiling vegetables and a sentence about rooting. That is the whole object.

What it does do is hold a small, specific idea in a form you can look at: that support and growth are different activities, that the visible part is downstream of the invisible part, and that the mutuality is the point. If you are the kind of person who reads diagrams for fun — and if you are reading this blog, you probably are — the shirt is a diagram. It has a legend, four labeled specimens, and a caption. The caption is the joke. The specimens are the argument.

The Let’s Root For Each Other And Watch Each Other Grow Garden shirt is listed under Quirky Cotton Collective. The design is the one described above: the ring of text, the four smiling root vegetables, the visible roots in the soil. If you are looking for the object, that is the object.

§ 6 — One Thing to Inspect

If the shirt’s argument is that watching is the real work, then the test is not whether you own the shirt. The test is whether you can name, right now, one specific change you have noticed in one specific person over the last ninety days. Not a compliment. Not a general impression. A change: a thing they did not used to do, a thing they stopped doing, a thing they got better at. If you cannot name one, the rooting has been happening at the slogan level and not at the watching level.

That is the reversible experiment. Pick one person. Write down one thing you noticed about their work this quarter that you did not notice last quarter. Do not tell them. Just write it down. If you can do it for one person, the watching is real. If you cannot do it for anyone, the shirt is a nicer slogan than most, and the drawing is still the best part.

The four vegetables are in the ground. The roots are visible. The sentence wraps around them. That is all the design does, and it is enough.

The Offer Decline Is the Most Honest Data Your Pipeline Produces — and Nobody Logs It

The decline is logged. The reason field says “candidate declined.” The requisition reopens. The recruiter gets a note about market conditions. Nobody pulls the timestamps.

That is the failure. The decline event is real. The label attached to it is usually a guess. And the guess gets aggregated into a metric that leadership reads as a verdict on compensation, when the actual signal is sitting in three columns nobody queried: how long the offer sat open, whether the company or the candidate ended the process, and whether the accepted candidate ever showed up.

Symptom

A team reports an 80 percent offer acceptance rate. The number is within the published band. Nothing looks broken. Then a hiring manager notices that two of the last five engineering offers went to candidates who accepted and then reneged before the start date, and a third was logged as a decline when the company pulled the req after a headcount freeze. The 80 percent is arithmetically correct and diagnostically useless.

This is not a data quality problem in the abstract. It is a specific failure mode: the decline reason field is the weakest artifact in the pipeline, and it is the one everyone reads.

Why the decline reason field is the weakest artifact

Three properties make it unreliable.

It is self-reported through a channel that rewards politeness. A recruiter asking a candidate why they declined is asking a person to critique the person who just rejected them, in a conversation that has no future. The answer that comes back is the socially safe one. One practitioner source puts it directly: capture decline reasons through a neutral channel, because a recruiter asking produces a polite answer and a third party asking produces a real one. That is a claim about channel effects, not a measured comparison, but it matches the structure of the interaction.

It collapses distinct failure modes into one label. “Candidate declined” can mean the candidate took a competing offer, the compensation came in below the range discussed in the screen, the role scope shifted between the loop and the letter, the company rescinded the offer, or the candidate accepted and then reneged. These are different system failures with different owners. A single label cannot tell you which lever to pull.

The denominator is a design choice, not a fact. Published benchmarks differ on whether verbal offers count, whether employer-rescinded offers count as declines, and whether internal transfers are in scope. If your definition differs from the benchmark you are comparing against, the gap between the two numbers may be definitional rather than operational.

Timeline: what the record actually shows

Pull the offer-stage duration for every offer in the last four quarters. In one dataset covering 230,000 applications that reached the offer stage, accepted offers averaged about two days in that stage while declined offers averaged about six. That is a correlation, not a controlled result, and it comes from a single vendor’s analysis. But it is the kind of signal that is cheap to check against your own data, because the timestamps already exist in the ATS.

Then pull the withdrawal flag. In the same dataset, employer-rescinded offers accounted for 17 percent of declined technical roles and 27 percent of declined business roles. Between a sixth and a quarter of what the report called a candidate decline was the company changing its mind. That figure comes from one dataset and should not be treated as a universal rate. The structural point is what matters: if your ATS does not distinguish company withdrawal from candidate choice, your decline rate is measuring two different things at once.

Then pull the acceptance-to-start gap. The difference between conditional acceptance and final acceptance reveals how many candidates accept an offer but renege before their start date. Most teams stop measuring at “accepted” and never instrument this. In markets with long notice periods, the gap between yes and day one is where the largest leak sits.

Contributing factors

Blended rates hide segment differences. In an analysis of 230,000 applications that reached the offer stage, technical roles accepted at about 73 percent against 84 percent for business roles. An 11-point gap means a company-wide number describes neither population and will drift purely on hiring mix. If your engineering hiring went up as a share of total hires, your blended rate can fall without any change in how offers are written.

Speed is a signal, not just a delay. A survey of 12,000 candidates across seven countries found 42 percent had left a recruitment process because scheduling an interview took too long. In Greenhouse’s 2025 workforce and hiring report, the most common trigger for a US candidate ghosting an employer was poor communication or long delays from that employer, at 24 percent, followed by a poor interview experience at 23 percent. A long time-to-offer correlates strongly with lower acceptance rates. These are correlations from survey and vendor data, not causal estimates, but they point at process rather than at the offer letter.

Misalignment discovered late reads as a trust problem. One source reports that 72 percent of candidates said the job differed from what was advertised. That figure comes from a secondary summary and should be treated as directional. The mechanism is plausible: when role scope, compensation, or expectations shift between the loop and the letter, the candidate does not wait for clarity.

Counteroffers are a known failure mode with a known window. In one European benchmark table, counteroffers from the current employer are listed at 12 percent of declines and described as most common in Germany and Switzerland, where notice periods give current employers time to react. The specific percentage is from one source; the structural point is that a long notice period is a window in which the current employer can act.

Worked example: reading the artifact

Consider a hypothetical team. Blended acceptance rate: 80 percent. Technical roles: 71 percent. Business roles: 86 percent. The blended number is within the published band and nobody escalates.

Pull the withdrawal flags. Of the 20 percent of offers logged as declines, six of them were employer-rescinded after a budget review. The true candidate-decline rate is lower than reported. The requisition discipline problem is worse than reported.

Pull the offer-stage duration. Accepted offers sat open for a median of two days. Declined offers sat open for a median of seven. The three offers that sat open for more than ten days were all declined. The pattern is visible in data the team already had.

Pull the acceptance-to-start gap. Two candidates accepted and then reneged during a 60-day notice period. Neither was flagged as a decline in the acceptance-rate calculation. The metric that leadership reviews does not include them.

None of this required a new survey. It required querying columns that already existed and separating events that had been collapsed into one label.

Action items

1. Fix the logging before fixing the offer. A metric that mixes company withdrawal with candidate choice cannot tell you which lever to pull. Add a distinct status for employer-rescinded offers. Add a distinct status for accepted-then-reneged. Write down whether verbal offers count. This is a schema change, not a strategy change, and it is reversible.

2. Instrument days-offer-sits-open. This is the cheapest predictive signal in the funnel. It costs nothing to compute from existing timestamps. Track it by segment, by hiring manager, and by recruiter. Do not set a target yet. Just measure the distribution for one quarter.

3. Run one reversible experiment on offer-stage latency. Pick one segment — one team, one role family, one region. Set an internal SLA from hiring-manager decision to verbal call: 48 hours. Keep the old process for a comparison segment. Measure days-offer-sits-open and acceptance rate in both segments for one quarter. If the treatment segment does not move, roll back. This is a process change with a rollback plan, not a claim about what will happen. The sources report correlations between offer-stage duration and outcomes; they do not report a controlled experiment on this specific intervention.

4. Separate the segments before comparing to any benchmark. If technical roles accept at a materially different rate than business roles, report them separately. A blended number that moves with hiring mix is not a performance metric.

5. Capture decline reasons through a channel that is not the recruiter who extended the offer. This is a recommendation, not a finding. The evidence for channel effects is thin. But the structural argument is that the person who delivered the rejection is the worst-positioned person to ask why it was rejected.

What this does not tell you

The 17 and 27 percent figures for employer-rescinded offers come from one dataset and one vendor’s analysis. They are not a universal rate. The two-day versus six-day offer-stage figures come from the same source. The 73 versus 84 percent technical-versus-business gap comes from the same analysis. These are useful as a starting hypothesis, not as a benchmark to adopt.

No source here reports a controlled experiment showing that a three-day offer SLA raises acceptance rates by a specific amount. The recommendation to run the experiment is a recommendation, not a finding.

The cost of a declined offer is sometimes cited at a fixed dollar figure. That figure comes from a single vendor citation and would need independent verification before use in a budget argument.

FAQ

What counts as a decline? That is a design choice. Decide up front whether verbal offers count, whether employer-rescinded offers count as declines, and whether internal transfers are in scope. Write the definition down next to every rate on your dashboard.

Why does the decline reason field matter if it is unreliable? Because it is the field everyone reads. The fix is not to stop collecting reasons. The fix is to stop treating the reason as the primary signal and start reading the timestamps and withdrawal flags that nobody has to narrate.

Is a slow offer really the problem, or is it compensation? Both can be true. In one survey of 2,800 professionals, 17.3 percent of offer declines cited compensation as the primary reason. In a European benchmark table, the top listed reason is accepting a competing offer at 35 percent, followed by compensation below expectations at 28 percent. These are different sources with different methodologies. The point is not to pick one. The point is that a slow process gives competing offers time to reach the same stage, which converts a speed problem into a competing-offer problem.

What is the difference between offer acceptance rate and offer-to-join ratio? Offer acceptance measures whether a candidate says yes. Offer-to-join ratio measures whether they actually start. In markets with long notice periods, the second number is often the real problem, because acceptance can look healthy while candidates drop out during a 60 to 90 day notice window.

Should we extend exploding offers with 24-hour deadlines? The sources here do not support that. A short deadline creates pressure that can produce a regretted acceptance. The recommended window in one source is two to three days, which matches the observed clustering of accepted offers around two days open. A longer window rarely produces a more considered yes; it mostly gives competing processes time to catch up.

How do we know if our decline rate is actually bad? Segment it first. If your technical-role acceptance rate is well below your business-role rate, the blended number is hiding the problem. If a meaningful share of your logged declines are employer-rescinded, your true decline rate is lower than reported and your requisition discipline is worse. Neither of those is visible in the headline number.

The forensic move

The decline is honest data in the sense that it is a real event. The label attached to it is often a guess. The forensic move is to separate the event from the label, pull the timestamps that nobody had to narrate, and run one reversible experiment on the part of the process you can still influence.

Start with the logging. A metric that cannot distinguish company withdrawal from candidate choice cannot tell you which lever to pull. Fix that first. Then measure how long your offers sit open. Then decide what to change.

The Ball at the Bottom of the Ramp: Reading the ‘I Had Potential’ Diagram

Editorial note: This publication and Quirky Cotton Collective share an owner.

The shirt shows a diagram. White capitals: I HAD POTENTIAL. Below the words, a white curved ramp descends from an upper-left ledge to a lower-right flat. A dashed empty circle sits at the top of the ramp. A solid white ball rests at the bottom. The ramp is curved, not a straight diagonal. That curve is the whole joke, and it is also the reason the shirt works as more than a slogan.

Most joke diagrams fail because they cheat. They draw a straight line, put a ball at the bottom, and let the caption do all the work. This one doesn’t. The dashed circle at the upper left is the ball’s starting position — the potential state, the place where the object could still become something. The solid ball at the lower right is the ball after the ramp. Same object, different position. The dashed outline is not decoration; it is the before. The solid fill is the after. The curve is the path between them.

That is a physics diagram, not a metaphor pasted onto a shirt. A ball released on a curved ramp accelerates, follows the surface, and arrives at the bottom with whatever kinetic energy the drop gave it. The diagram doesn’t show the ball mid-ramp. It shows the two stable states: the one where potential is still theoretical, and the one where it has been spent. The caption reads I had potential, past tense, and the drawing agrees. The ball is already at the bottom. The dashed circle is a memory.

I keep coming back to the dashed circle. In engineering diagrams, a dashed outline usually means one of two things: a hidden feature, or a previous position. Here it reads as both. The ball that could have been is still visible, but only as an outline. The solid ball is what remains. That is a more precise joke than most sarcastic shirts manage, because it doesn’t say the potential was wasted. It says the potential was located — at the top of the ramp, in a specific place, before gravity did its work. The shirt is not complaining. It is reporting a result.

I have spent a lot of time reading artifacts that teams generate without meaning to: git logs, retry counts, swap logs, PIP timelines. The signal is rarely in the stated message. It is in the structure. A PIP that lists performance concerns but no measurable prior feedback is not a performance document; it is a paper trail. A retry log with a spike every Tuesday at 2 a.m. is not a flaky test; it is a cron job nobody owns. The I Had Potential diagram has the same quality. The caption tells you one thing. The drawing tells you another. The drawing is more honest.

What the drawing says is that potential is a position, not a property. The ball at the top of the ramp has potential energy because of where it is, not because of what it is. Move it to the bottom and the potential is gone — not because the ball changed, but because the configuration changed. That is a useful distinction for anyone who has watched a promising engineer get promoted into a role with no ramp, or a strong team get reorganized into a configuration where their best work has nowhere to go. The potential didn’t disappear. The ledge did.

I am not going to pretend the shirt is making an argument about engineering management. It is a diagram joke. But it is a well-made diagram joke, and the difference between a well-made diagram joke and a bad one is the same difference between a useful postmortem and a blame session: specificity. The dashed circle is specific. The curved ramp is specific. The solid ball at the bottom is specific. A lesser version of this shirt would have drawn a straight line and a frowning face. This one drew the physics.

If you want the object, it is the I Had Potential shirt from Quirky Cotton Collective. The listing shows the same diagram I have been describing: white capitals, curved ramp, dashed circle upper left, solid ball lower right. The design is minimal enough that the curve reads at a distance, which is more than I can say for most text-heavy shirts. The joke lands whether or not you know the physics, but it lands harder if you do.

The reason I keep looking at it is the same reason I keep pulling artifacts at work. The stated message is rarely the whole message. The caption says I had potential. The diagram says here is where it was, and here is where it went. That is a more interesting sentence, and it is the one the shirt actually prints.

Twelve Thumbs-Up, Zero Written Objections, One Contested Decision

Symptom: A decision merged with twelve approvals and an empty objection field. Two weeks later, someone reopens it in a thread titled “quick question about the thing we already decided.”

Diagnosis: The review instrument was configured to count approvals. It was never configured to surface objections. Twelve approvals and zero objections are not the same measurement, and reading the second as a null result is the error this article is about.

I am going to walk through this the way I would walk through an incident: pull the artifacts, name what each one actually records, find the system boundary, run one reversible experiment. No blame. The people who clicked approve are not the problem. The instrument is.

What each artifact actually records

Three artifacts get conflated in every post-decision argument. They measure different things.

  • The CODEOWNERS file records who was asked to review. It does not record who read the diff.
  • The PR thread records who spoke. It does not record who disagreed and stayed quiet.
  • The approval count records who clicked. It does not record who examined.

If you have twelve approvals and zero written objections, you have data from the third instrument and nothing from the second. That is not a null result. It is an unmeasured variable. Treating an unmeasured variable as zero is the specific failure mode.

The mechanical fact that makes the gap possible

GitHub’s documentation is explicit about how code-owner review works. Code owners are automatically requested for review when someone opens a pull request that modifies code they own. That is the request mechanism. It is not a reading mechanism.

More importantly: when reviews from code owners are required, an approval from any one of the owners is sufficient to meet the requirement. The documentation gives the example directly — if a line reads *.js @global-owner1 @global-owner2, changes to JavaScript files can be approved by either owner, and approvals from both are not required.

So twelve approvals can mean twelve people were asked. It does not mean twelve people examined. The instrument counts the first and is silent on the second.

There is a second mechanical gap worth checking before you do anything else. If a specified user or team does not exist or has insufficient access, a code owner will not be assigned at all. A path with no matching owner falls through. The review request never fires. The approval count still looks healthy because other reviewers were requested by other rules.

Pull your CODEOWNERS file. Find the contested path. Check whether it has an owner that actually resolves. If it does not, you have found the first contributing factor, and it has nothing to do with anyone’s diligence.

“No objection” is not “no objection recorded”

The IETF has been running consensus processes on technical decisions for decades, and RFC 7282 is the document that explains what rough consensus actually means. It is informational — it describes IETF process, not software teams — but the distinction it draws is the one that matters here.

From the RFC: determining consensus, coming to consensus, and having consensus are different things. A chair who asks “Is everyone OK with choice A?” will get objections. A chair who asks “Can anyone not live with choice A?” is more likely to hear only from people who consider the choice impossible to engineer given the constraints.

Read that again as a statement about review prompts. “Approve or request changes” is the first question. It invites a click. “State your objection in writing by Friday or we proceed” is the second question. It invites a sentence.

Silence in a review thread is the answer to the first question. It is not the answer to the second. Any process that reads the empty objection field as consensus is reading the wrong instrument.

Two failure modes that produce the empty objection field

RFC 7282 names both of them, and both look like agreement in the artifact.

Capitulation. A minority objects, gets tired of arguing, and says “forget it, do what you want.” The RFC is blunt about what this is: they have given up trying to appease the others. That is not coming to consensus. There still exists an outstanding unaddressed objection. In the PR thread, capitulation looks like a comment that stops mid-sentence, or a review that was requested and never submitted, or a thumbs-up on a comment that says “I still have concerns but I don’t want to block.”

Horse-trading. “I object to your proposal for such-and-so reasons. You object to mine for this-and-that reason. If you stop objecting to mine, I’ll stop objecting to yours and we’ll put them both in.” The RFC’s verdict: this produces an agreement of sorts, but instead of one outstanding unaddressed issue, it produces two, ignored for the sake of expedience.

Both failure modes leave the objection field empty. Both leave the decision contested. The artifact cannot tell them apart from genuine consensus, because the artifact was never designed to.

The forensic pass

Here is the sequence I would run on a contested decision. It takes about an hour and requires no meetings.

Step one: pull the CODEOWNERS file. Find the path that was changed. Check whether it has a resolving owner. Check whether the owner is a team that still exists and still has write access. If the owner does not resolve, the review request never fired, and the approval count is measuring something else entirely.

Step two: pull the PR thread. Count distinct commenters, not approvals. If twelve approvals came from three commenters, the review was performed by three people and ratified by twelve. Those are different numbers and the difference is worth knowing.

Step three: read the comments for the two failure modes. Look for capitulation language — “I don’t want to block,” “let’s just move forward,” “I’ll raise it later.” Look for horse-trading — paired concessions where two objections cancel each other out. Both are signals that an objection existed and was not recorded as one.

Step four: check the CI history for the same period. Workflow run logs can be searched, and when you search logs, only expanded steps are included in the results. That detail matters more than it looks: a flaky gate that fails and passes on retry trains reviewers to approve without reading, because the gate’s signal has stopped meaning anything. If the contested PR sat behind a job that was retried three times before going green, you have a contributing factor that has nothing to do with the reviewers.

Step five: pull the git log for the affected path. Git log output is given in reverse chronological order by default, which makes it easy to read the sequence of changes to a file. If the contested decision was reversed and re-applied twice in six months, you are looking at a retry storm at the decision level — the same argument re-litigated because the first resolution never addressed the underlying objection.

One reversible experiment

The fix is procedural, not cultural. Change the prompt.

For the next contested decision, replace the approval request with a written objection prompt. Something like: “This decision affects [path]. If you have an objection, state it in this thread by [date]. If no objection is recorded by then, we proceed.”

Name a recipient. Set a deadline. Record the responses in the thread where they can be audited later.

The rollback is trivial. You have lost nothing but a week of false confidence, and you have gained a record that distinguishes “no objection” from “no objection recorded.” If the experiment produces no objections and no re-litigation, you have learned something real. If it produces objections, you have learned something more useful.

This is the same move the SRE literature makes about postmortems. Google’s postmortem culture chapter states it plainly: an unreviewed postmortem might as well never have existed. The document’s presence is not evidence that the process ran. The same is true of an approval. The click’s presence is not evidence that a review happened.

Why this is a system boundary, not a character flaw

The temptation, when a decision gets re-litigated, is to conclude that twelve people were lazy or that one person was cowardly. That conclusion is almost always wrong, and it is expensive because it produces a fix that does not work.

The blameless postmortem literature is relevant here, and it is worth being precise about what it does and does not claim. Google’s SRE book describes blameless postmortems as focusing on contributing causes without indicting any individual or team for bad or inappropriate behavior. Atlassian’s incident management guide describes the point as removing the fear of looking stupid, being reprimanded, or losing a job, in order to encourage honest, objective, fact-centric communication. Atlassian also notes that detractors question whether blamelessness is achievable and whether it undermines accountability. I am not going to pretend that debate is settled. What is settled is the mechanism: if surfacing an objection carries social cost, objections will not be surfaced, and the artifact will show zero.

The failure is not that twelve people were lazy. The failure is that the review instrument was configured to count approvals and never configured to surface objections. That is a configuration. Configurations can be changed.

What to do with this

Pull the artifact. Find the signal. Trace the failure to the system boundary. Run one reversible experiment with a rollback plan.

In this case the artifact is the CODEOWNERS file and the PR thread. The signal is the gap between who was asked and who spoke. The system boundary is the review prompt. The experiment is a written objection prompt with a deadline and a named recipient.

Twelve thumbs-up is not consensus. It is twelve data points from an instrument that was never calibrated to measure disagreement. Stop reading it as if it were.

FAQ

Does this mean approval-based review is broken?

No. It means approval count and objection count measure different things, and conflating them produces false confidence. Approval-based review works fine for changes where the question is “is this correct?” It works poorly for changes where the question is “does anyone have a problem with this?” Those are different questions and they need different prompts.

What if nobody actually objects?

Then you have a real null result instead of an unmeasured variable. That is strictly better information. The experiment costs a week and produces a record you can point to the next time someone asks why the decision was made.

Is RFC 7282 the right model for a software team?

No, and it does not claim to be. It is an informational document about IETF process. What transfers is the distinction between determining consensus and having it, and the two failure modes — capitulation and horse-trading — that produce the appearance of agreement without the substance. The rest of the IETF process is specific to the IETF.

How do I check whether a CODEOWNERS path is actually owned?

Open the file, find the pattern that matches the path, and check that the listed user or team exists and has write access. GitHub’s documentation notes that if a specified user or team does not exist or has insufficient access, a code owner will not be assigned. You can also hover over a file in the repository to see code ownership details from the CODEOWNERS file for the branch you are viewing.

What if the objection prompt produces objections that are not technical?

Then you have learned that the decision has a stakeholder problem, not a technical one, and you can address it as such. That is still better than discovering it two weeks after the merge.

‘No Blockers’ in Standup, ‘Waiting on Review’ in the Logs

Standup: “No blockers.” The pull request timeline: opened Tuesday, first review request routed to a team, no human response until Friday. Both statements are true. That is the problem.

This is a postmortem for a class of incident that never gets declared: the review queue that everyone reports as empty because nobody is measuring it. The artifact trail is already there. You just have to read it.

Symptom

Engineers report no blockers. Delivery dates slip anyway. The gap between “work complete” and “merged” grows, but it does not appear in any status report because status reports are self-assessed and the queue is invisible to the person standing in it.

The failure mode is not lying. It is a measurement boundary problem. Standup asks a person a question about their own state. The bottleneck lives at a system boundary between people, where no individual owns the wait.

Timeline

Reconstruct it from artifacts, not memory.

  1. PR opened. GitHub automatically requests review from code owners when a pull request modifies code they own, per GitHub’s CODEOWNERS documentation. The request is generated. Whether a human sees it is a separate question.
  2. Review requested, no response. The review sits in REQUESTED state. The PR author’s local work is done. From the author’s seat, there is no blocker — they are waiting on someone else, which they classify as normal latency, not a blocker.
  3. Author pings in Slack. Not logged as an artifact unless you keep the channel. The ping is the real signal that the queue is stuck, and it is the one signal most teams do not retain.
  4. Review submitted. The Pull Request Reviews API returns reviews in chronological order with a state and a submitted_at timestamp. That timestamp is the end of the wait. The start is the review request event, which lives in the PR timeline, not the reviews endpoint.
  5. Changes requested. State flips to CHANGES_REQUESTED. The clock resets. A second wait begins.
  6. Approved and merged. Total elapsed time from open to merge is the number that never made it into standup.

Contributing factors

1. The question is wrong

“Any blockers?” asks about the individual’s ability to proceed. A reviewer who has not looked at the PR is not blocking the author’s ability to work — the author has already finished. The wait is real; the framing hides it.

2. CODEOWNERS routes requests, not attention

GitHub’s documentation is explicit: code owners are automatically requested for review when a PR modifies code they own, and code owners are not automatically requested for draft pull requests. When a draft is marked ready, code owners are notified. That is routing. It says nothing about whether the owner has capacity, is on call, or is on leave.

Two details matter for diagnosis. First, if a CODEOWNERS line contains invalid syntax, that line is skipped — meaning a typo can silently remove an owner from the routing table. Second, if you specify a user or team that does not exist or has insufficient access, no code owner is assigned. A PR can therefore be “waiting on review” with no reviewer ever requested. That is not a slow reviewer. That is a broken routing rule.

3. Required reviews create a deadlock surface

Repository administrators can require approvals before merge, and can require review from code owners. When reviews from code owners are required, an approval from any one of the listed owners is sufficient — approvals from all are not required. That is a relief valve. But if the only listed owner is a single person or a team with one active member, the approval gate becomes a single point of failure. The PR is not blocked by a person’s judgment. It is blocked by an org chart.

4. CI retries mask a second queue

Workflow run logs record whether a run succeeded, failed, canceled, or was neutral, and they record the time each step took. They also record “Set up job” and “Complete job” steps that GitHub adds to every job. If your PRs routinely show three or four re-runs before green, the review wait is not the only hidden queue. The CI queue is the other one, and it is visible in the logs if anyone looks.

One caveat from the same documentation: when you download the log archive for a workflow that was partially re-run, the archive only includes the jobs that were re-run. To get a complete picture, you must download the log archives for the previous run attempts. Teams that pull one archive and call it the history will undercount retries.

5. The standup is a self-report, and self-reports are lossy

DORA’s capability research treats visibility of work in the value stream and work-in-process limits as capabilities that drive delivery performance. A standup that asks each person for a verbal status is not a value-stream view. It is a set of independent self-assessments. The queue between people does not appear in any of them.

What the artifacts actually show

Pull the data before you pull the person aside.

Artifact Signal What it can and cannot tell you
CODEOWNERS file Routing rules, invalid lines, single-owner paths Shows who should be requested. Does not show capacity or availability.
PR timeline Review request event, draft-to-ready transition Shows when the clock started. Does not show whether the reviewer saw the notification.
Pull Request Reviews API state and submitted_at per review, chronological Shows when the wait ended. Does not show the start of the wait by itself.
Workflow run logs Success/failure/canceled/neutral, per-step timing, re-run history Shows CI retries and queue time. Partial re-runs require multiple archives.
On-call swap logs Reviewer availability during the wait window Explains why a request went unanswered. Does not excuse a missing backup owner.

The reviews endpoint gives you the end timestamp. The PR timeline gives you the start. Subtract. That number is your review latency, and it is the number that never appears in standup.

Action items

Action item 1: Measure review latency from artifacts, not memory

For a sample of merged PRs, compute time from review request to first review submission. Use the PR timeline for the request event and the reviews endpoint for the submission. Do not ask engineers to estimate. Estimates of waiting are systematically low because waiting is not memorable work.

Action item 2: Audit CODEOWNERS for single points of failure

List every path with exactly one owner or one team. For each, ask: what happens when that owner is on leave, on call, or in a different time zone? If the answer is “the PR waits,” you have found a structural bottleneck. Add a second owner or a fallback team. This is a reversible change with a clear rollback: revert the CODEOWNERS commit.

Action item 3: Check for silently skipped lines

GitHub highlights errors when you navigate to the CODEOWNERS file, and a list of errors is accessible via the API. Run that check. A skipped line is a routing failure that looks like a slow reviewer.

Action item 4: Separate CI queue time from review queue time

Pull workflow run logs for the same sample. Record time from PR open to first workflow start, and count re-runs per PR. If CI queue time is a meaningful fraction of total lead time, the review conversation is a distraction. Fix the queue you actually have.

Action item 5: Change the standup question

Stop asking “any blockers?” Ask “what are you waiting on, and who owns it?” The second question surfaces cross-boundary waits. It also produces a name, which is the only thing that makes a wait actionable.

What this method cannot tell you

Artifact-based diagnosis has confounders. A long review latency might mean a slow reviewer, a missing reviewer, a PR that was too large to review quickly, a holiday, an incident that consumed the reviewer’s week, or a CODEOWNERS rule that routed to the wrong team. The artifacts narrow the hypothesis space. They do not close it.

Git history and PR metadata also reflect process, not intent. A team with a healthy review culture and a team with a broken one can produce similar timestamps for different reasons. Treat the numbers as a starting point for a conversation, not a verdict about a person.

The one thing the artifacts do reliably is contradict the standup. When the log says “waiting on review” and the standup says “no blockers,” the log is the more useful document.

FAQ

Can the Pull Request Reviews API tell me how long a PR waited for review?

Not by itself. The reviews endpoint returns reviews in chronological order with a state and a submitted_at timestamp. That gives you the end of the wait. You need the review request event from the PR timeline to get the start. Combine the two.

Why did no reviewer get requested on my PR?

Check three things. First, the CODEOWNERS file must be on the base branch of the pull request for code owners to receive review requests. Second, if a line contains invalid syntax, that line is skipped. Third, if you specify a user or team that does not exist or has insufficient access, no code owner is assigned. Any of these produces a PR that looks like it is waiting on a reviewer who was never asked.

Does requiring code owner review mean every owner must approve?

No. GitHub’s documentation states that when reviews from code owners are required, an approval from any one of the owners is sufficient. Approvals from all listed owners are not required. The risk is not multiple approvals; it is a single listed owner with no backup.

How do I get complete CI retry history?

Download the log archives for every run attempt, not just the latest. When a workflow is partially re-run, the archive for that run only includes the jobs that were re-run. The earlier attempts hold the rest.

Is review latency a DORA metric?

DORA’s published capability set includes lead time for changes and visibility of work in the value stream, among other capabilities. Review latency is a component you can measure from repository artifacts; it is not a standalone DORA metric. Use it as a local diagnostic, not a benchmark against published research.

The Review Calendar That Rewrites Your Incident History

Symptom: The incident count for last quarter looks flat. The review calendar says you held every postmortem. The git history says otherwise.

Timeline: A team changes its postmortem review cadence from weekly to monthly. Six weeks later, a Sev-2 that would have been reviewed in the old cadence is closed with a Slack thread and a rollback. No postmortem document is created. The incident does not appear in the quarterly reliability report. The review calendar still shows a meeting occurred.

Contributing factors: The calendar is treated as the record. The artifacts that actually preserve incident history — postmortem documents, incident channels, commit messages, CODEOWNERS changes, CI retry logs — are not cross-checked against it. When the cadence changes, the calendar overwrites the history it was supposed to preserve.

This is a predictable failure mode of any review process that relies on a scheduled meeting as its primary evidence. The meeting is a container. The artifact is the record. When the container changes shape, the record leaks.

What the review calendar actually controls

A review calendar does three things, and only one of them is visible on the calendar.

First, it sets the trigger threshold for what gets reviewed. Google’s SRE book describes common postmortem triggers: user-visible downtime beyond a threshold, data loss, on-call intervention, resolution time above a threshold, and monitoring failure. The book is explicit that these criteria should be defined before an incident occurs so everyone knows when a postmortem is necessary. A calendar change that moves review from weekly to monthly does not change the trigger criteria on paper. It changes the practical threshold, because incidents that resolve before the next review slot are more likely to be closed informally.

Second, it sets the review latency. Atlassian’s incident management guidance recommends drafting the postmortem immediately after a post-incident review held within 24–48 hours of resolution, and not more than five business days. The Google SRE Workbook’s case study of a bad postmortem notes that a four-month publication delay meant team members likely forgot key details, and the incident recurred in the interim. Latency is not neutral. It is a lossy compression algorithm applied to operational memory.

Third, it sets who is in the room. The Google SRE book describes a formal review step where senior engineers assess the draft for completeness: whether key incident data was collected, whether impact assessments are complete, whether the root cause is sufficiently deep, whether the action plan is appropriate, and whether the outcome was shared with relevant stakeholders. Change the cadence and you change the reviewer pool. Change the reviewer pool and you change what counts as a complete postmortem.

How the calendar rewrites history

The rewrite is not malicious. It is a side effect of using the calendar as the index and the postmortem as the content. When the index changes, the content that no longer fits the index becomes invisible.

Consider a concrete sequence. A team holds weekly incident review meetings. Every incident above a severity threshold gets a postmortem document, a review slot, and a line in the weekly notes. The calendar is dense. The artifacts are dense. The two match.

Now the team moves to monthly review. The meeting still happens. The postmortem template is still available. But the weekly slot is gone. An incident that resolves on a Tuesday and would have been reviewed on Thursday now waits three weeks. By the time the monthly meeting arrives, the incident channel has been archived, the on-call engineer has rotated, and the rollback commit is buried under three weeks of merges. The postmortem is either written from memory or skipped. The calendar shows a meeting. The artifact record shows a gap.

This is the mechanism. The calendar does not delete the incident. It deletes the review of the incident, and the review is what produces the durable artifact. Without the artifact, the incident is not part of the organizational record. It is a Slack thread that will be lost when the workspace retention policy kicks in.

Artifacts that preserve incident history

If the calendar is unreliable as a record, what is reliable? The artifacts teams already generate. Here is what to pull and what each one tells you.

Postmortem documents

The postmortem is the primary record. Google’s SRE book defines it as a written record of an incident, its impact, the actions taken to mitigate or resolve it, the root cause(s), and the follow-up actions to prevent recurrence. The book also states that an unreviewed postmortem might as well never have existed. That is the standard to hold the calendar to: if the calendar shows a review but no postmortem document exists, the review did not happen in any way that matters.

Pull the postmortem repository and sort by incident date, not publication date. The gap between the two is a latency metric. A postmortem published four months after the incident is not a record of the incident. It is a record of what someone remembered four months later.

Incident channels

The incident channel is the raw log. It contains the timestamps, the hypotheses, the dead ends, and the moment someone said “wait, this looks like the thing from March.” That last one is the signal. If the same failure mode appears in two incident channels and only one has a postmortem, the review calendar has a hole in it.

Search incident channels for the phrase “this is the same as” or “didn’t we fix this.” Each hit is a candidate for a missing postmortem. Each missing postmortem is a candidate for a calendar that is not capturing what it claims to capture.

Git history

Git log is the timeline of what actually changed. The git log documentation describes it as showing commit logs in reverse chronological order by default, with options to limit by date, author, and message pattern. That is enough to reconstruct a change timeline independent of any postmortem.

Pull the commits around the incident window. Look for the rollback commit, the hotfix, the revert. Then check whether a postmortem exists for that window. If a revert commit exists and no postmortem exists, the incident happened and the review process missed it.

The commit message is also evidence. A message that says “revert #1234, fixes prod” is an incident marker. A message that says “revert #1234, see postmortem PM-456” is a linked record. The difference between the two is the difference between an incident that is traceable and one that is not.

CODEOWNERS changes

CODEOWNERS files define who is responsible for code in a repository. GitHub’s documentation states that code owners are automatically requested for review when someone opens a pull request that modifies code they own, and that branch protection can require approval from a code owner before merge. The file is a map of ownership at a point in time.

When a CODEOWNERS file changes, the ownership map changes. If a service’s code owner changes in the same week as an incident, the incident review may have been conducted by someone who no longer owns the code. The postmortem may name an owner who has since been removed. The action items may be assigned to a team that no longer exists.

Pull the CODEOWNERS history and align it with the incident timeline. A CODEOWNERS change during an incident window is a contributing factor to review confusion. It is not the cause of the incident, but it is a cause of the incident being misattributed.

CI retry logs

CI retry logs are the least glamorous artifact and the most honest. A retry is a signal that something failed and someone decided to try again rather than investigate. A cluster of retries around a deploy window is a signal that the deploy was flaky and the team normalized the flakiness.

This is normalization of deviance in its purest form. The alert that fires every Tuesday and gets acknowledged without action is the same pattern. The CI job that fails twice and passes on the third try is the same pattern. Neither generates a postmortem because neither crosses the severity threshold. Both are evidence that the threshold is wrong.

Pull the retry logs for the quarter. Count retries per pipeline. A pipeline with a rising retry rate is a pipeline with a rising incident rate that the review calendar is not capturing.

On-call swap logs

On-call swap logs are the artifact that connects incident history to human history. A swap is a signal. It can mean a vacation, a conflict, or a refusal to carry the pager for a service that pages too often. The last one is the signal that matters.

Pull the swap logs and align them with the incident timeline. A spike in swaps after a series of incidents is a retention risk. A spike in swaps before a known incident is a leading indicator. Neither appears in the postmortem. Both appear in the swap log.

PIP timelines and exit interview notes

This is where the review calendar does the most damage. A performance improvement plan that starts two weeks after an incident is a data point. An exit interview that mentions on-call burnout is a data point. Neither is a postmortem. Both are evidence that the incident review process failed to surface a system problem and the problem was attributed to a person instead.

The Google SRE book is explicit on this point: blameless postmortems focus on identifying contributing causes without indicting any individual or team, because a culture of finger pointing leads people to withhold information. The book states that you cannot fix people, but you can fix systems and processes. When a PIP timeline aligns with an incident timeline, the question is not whether the person failed. The question is whether the system failed to give the person what they needed.

Pull the PIP start dates and the incident dates. Align them. A PIP that starts within 30 days of an incident that has no postmortem is a misattribution waiting to be documented.

How to run the forensic pass

This is a procedure, not a philosophy. It takes one afternoon and produces a list of gaps.

Step 1: Pull the calendar. Export the review meeting invites for the last two quarters. Note the cadence, the attendees, and the dates.

Step 2: Pull the postmortems. Export the postmortem documents for the same period. Sort by incident date. Note the publication date for each.

Step 3: Align the two. For each review meeting, list the postmortems discussed. For each postmortem, list the review meeting where it was discussed. The gaps are the incidents that have a review slot but no postmortem, and the postmortems that have no review slot.

Step 4: Pull the git log for the same period. Use git log --since and git log --until to bound the window. Search for revert commits, hotfix commits, and commit messages that mention production. Each one is a candidate incident.

Step 5: Cross-check. For each candidate incident from git, check whether a postmortem exists. For each postmortem, check whether a revert commit exists. The mismatches are the rewrites.

Step 6: Pull the CODEOWNERS history. Use git log --follow CODEOWNERS to see the ownership changes. Align them with the incident timeline. Note any incident where the code owner changed during the incident window.

Step 7: Pull the CI retry logs. Count retries per pipeline per week. Plot the trend. A rising trend is a leading indicator of incidents that the review calendar is not capturing.

Step 8: Pull the on-call swap logs. Count swaps per week. Align with the incident timeline. A spike in swaps is a signal that the on-call load is not sustainable, regardless of what the postmortem says.

Step 9: Pull the PIP timelines and exit interview notes. Align the start dates with the incident dates. Note any PIP that starts within 30 days of an incident with no postmortem.

Step 10: Write the gap report. The report is not a postmortem. It is a list of incidents that the review calendar missed, with the artifact that proves each one. The report goes to the same people who own the review calendar.

One reversible experiment

The experiment is this: add a second review slot, not a replacement. Keep the existing cadence. Add a 15-minute weekly slot whose only agenda item is “what happened this week that we did not review.” The slot has no postmortem requirement. It has one output: a list of incidents that did not cross the threshold.

The rollback plan is simple. If the slot produces no items for four consecutive weeks, cancel it. If it produces items, the items are the evidence that the threshold is wrong. The threshold can then be adjusted with data rather than opinion.

This experiment is reversible because it adds a meeting, not a process. It does not change the postmortem template. It does not change the severity definitions. It does not change the review calendar. It adds a sensor. The sensor either reads something or it does not. Either outcome is information.

The experiment also has a second output: the list of incidents that did not cross the threshold is a list of candidates for the forensic pass described above. The weekly slot is the intake. The forensic pass is the analysis. The two together are the mechanism for detecting when the review calendar is rewriting the incident history.

What to do with the gap report

The gap report is not a blame document. It is a map of where the review process is not matching the operational reality. The map has three uses.

First, it corrects the record. The incidents that were missed are added to the incident repository with a note that they were identified retroactively. The note is important because it distinguishes a postmortem written at the time from a postmortem written after the fact. The Google SRE Workbook’s case study of a bad postmortem is explicit that delayed publication loses detail. A retroactive postmortem is better than no postmortem, but it is not the same artifact.

Second, it corrects the threshold. The incidents that were missed are the data points that define the new threshold. If the weekly slot produces five incidents in a month that did not cross the old threshold, the old threshold was wrong. The new threshold is defined by the data, not by the calendar.

Third, it corrects the attribution. The PIP timelines and exit interview notes that align with missed incidents are the evidence that the system failure was misread as a personal failure. The gap report does not reverse a PIP. It does provide the context that the PIP process did not have.

Why this matters

The review calendar is a coordination mechanism. It tells people when to show up and what to bring. It is not a record. When it is treated as a record, it overwrites the artifacts that are. The overwrite is silent because the calendar still shows a meeting. The meeting still happened. The postmortem did not.

The fix is not to abolish the calendar. The fix is to stop using it as the index. The index is the artifact. The calendar is the schedule. When the two disagree, the artifact wins. That is the rule. Everything else is a process detail.

The rule has a corollary: if the artifact does not exist, the incident did not happen in any way that the organization can learn from. The calendar cannot fix that. Only the artifact can.

FAQ

Does this mean every incident needs a postmortem?

No. Google’s SRE book is explicit that the postmortem process has an inherent cost and that teams are deliberate in choosing when to write one. The point is not to postmortem everything. The point is to know which incidents were not postmortemed and why. The gap report is the record of that decision. Without it, the decision is invisible and the calendar becomes the only record.

What if the review calendar is working?

Then the forensic pass will show that the postmortems and the calendar align. That is a useful result. It means the review process is capturing what it claims to capture. The pass is not an accusation. It is a verification. Verification that passes is still verification.

How do I get the artifacts if the team does not keep them?

Start with git. The git log is the most durable artifact because it is version-controlled by default. The git log documentation describes options for limiting by date, author, and message pattern. That is enough to reconstruct a change timeline even if no postmortem exists. The incident channel is the next most durable, depending on the retention policy. The postmortem repository is the least durable if it is not maintained, because a postmortem that is not reviewed is, in the words of the Google SRE book, a postmortem that might as well never have existed.

What if the CODEOWNERS file does not exist?

Then the ownership map is implicit. GitHub’s documentation states that CODEOWNERS files must be placed in .github/, the root, or docs/, and that GitHub searches those locations in that order and uses the first one it finds. If no file exists, ownership is defined by commit history and team conventions. That is a weaker artifact, but it is still an artifact. The commit history shows who touched what. The team conventions show who was expected to. The gap between the two is the ownership ambiguity that contributes to incident misattribution.

How often should the forensic pass run?

The pass is cheap. It is a query against artifacts that already exist. Run it quarterly, aligned with the review calendar’s own reporting cycle. The output is a gap report that either confirms the calendar or corrects it. Either outcome is better than assuming the calendar is the record.

The Promotion Packet Whose Impact Claims Have No Artifact Trail

Incident: A senior engineer’s promotion packet claims “led the migration that cut p99 latency by 40%” and “drove adoption of the new service mesh across three teams.” The packet is well-written. The committee is split. Nobody can find the migration RFC, the latency dashboard, or the adoption tracker. The packet is the only artifact.

Status: Open. Severity: Medium. Impact: The committee is now evaluating writing quality, not engineering impact. The engineer may be promoted or denied for reasons unrelated to their work. Both outcomes are wrong.

Symptom

The packet reads like a postmortem with the timeline removed. Claims are stated as facts. Numbers appear without units or baselines. Verbs are transitive but the objects are vague: “drove,” “led,” “owned,” “partnered with.” There is no artifact trail — no RFC link, no PR series, no dashboard snapshot, no incident review, no design doc with the engineer’s name in the revision history.

This is not a lying problem. It is a missing-artifact problem. The engineer did work. The work left traces. The traces are not in the packet. The committee is asked to reconstruct impact from prose.

Timeline

Promotion packets are usually assembled under deadline. The manager asks for a draft. The engineer writes it from memory, often late at night, often after a sprint. The manager edits for tone. The committee reads it cold, without the engineer in the room. The packet becomes the primary source.

If the packet cites artifacts, the committee can verify. If it does not, the committee either trusts the prose or discounts it. Neither is a system for evaluating engineering work. It is a system for evaluating packet-writing.

Contributing factors

1. The artifact trail is not part of the promotion process

Most engineering organizations have a career ladder and a promotion committee. Few have a requirement that impact claims link to artifacts. The ladder describes levels. The packet describes the engineer. The artifacts sit in git, CI, dashboards, and chat, unlinked.

This is a process gap, not a personal failing. The engineer is asked to prove impact in a format that does not require proof.

2. Impact is measured in outcomes, but artifacts record activity

Git history records commits. CI logs record builds. Incident channels record pages. None of these directly record “cut p99 latency by 40%.” That number lives in a dashboard, a query, or a before/after measurement. If the measurement was never saved, the claim is unverifiable.

This is the core mismatch: promotion packets claim outcomes, but the operational evidence teams generate records activity. The bridge between them — a saved measurement, a linked dashboard, a written before/after — is usually missing.

3. The committee has no shared standard for evidence

One committee member wants a design doc. Another wants a dashboard. Another wants peer feedback. Without a defined evidence standard, the committee defaults to prose quality and familiarity. This is how promotion becomes a writing contest with a social graph.

4. Retry storm: the same claims get re-litigated

When a packet lacks artifacts, the committee revisits the same claims in every calibration session. The claims do not resolve because there is nothing to resolve them against. This is a retry storm: the same request, the same failure, repeated until someone gives up or the deadline passes.

5. Normalization of deviance: everyone knows packets are unverifiable

The organization has learned that packets are mostly prose. The committee has learned to read between the lines. The manager has learned to write confidently. The engineer has learned to claim broadly. This is normalization of deviance: a known-bad practice that persists because it has not yet caused a visible failure. The visible failure is a bad promotion decision. It happens. It is attributed to the individual, not the process.

What the artifacts actually show

Pull the artifacts the team already generates. They tell a different story than the packet.

  • CODEOWNERS: Who is actually required to review changes in the affected area? If the engineer is not an owner, “led the migration” needs a different artifact.
  • Git history: Commit volume is not impact. But a series of commits across a migration window, with review approvals from other teams, is a trace. So is the absence of commits during the claimed period.
  • CI retry logs: If the migration introduced flaky tests that were retried for weeks, the packet’s “cut latency” claim may be true while the operational cost is omitted.
  • RFC threads: Who wrote the RFC? Who approved it? Who raised the blocking concern? The thread records the decision and the dissent.
  • Incident channels: Did the migration cause an incident? Was the engineer on call? Did they write the postmortem? The channel records the response, not the narrative.
  • On-call swap logs: If the engineer swapped out of on-call during the migration, that is a fact. It may be justified. It is still a fact.
  • Exit interview notes: If the migration drove someone out, the notes may say so. This is uncomfortable and relevant.
  • Career ladder docs: What does the ladder actually require at the next level? If it requires “impact across teams,” the packet needs cross-team artifacts, not a list of meetings.
  • PIP timelines: If a teammate was on a PIP during the migration, the packet’s “led the team” claim needs context.
  • Onboarding docs: If the migration required new onboarding steps, the doc is an artifact. If it did not, the migration may not have changed the system’s surface area.

None of these artifacts prove impact by themselves. Together, they form a trail. The trail either supports the packet’s claims, contradicts them, or is silent. Silence is a finding.

Why this gets misread as a personal failing

When the committee cannot verify a claim, it does one of two things. It trusts the engineer, or it discounts the engineer. Both are personal judgments. Neither is a system judgment.

The engineer who writes well and has a good reputation gets trusted. The engineer who writes plainly and has less visibility gets discounted. The difference is not impact. The difference is artifact trail and narrative skill.

This is the system failure: the promotion process rewards packet-writing and reputation, then attributes the outcome to engineering ability. The engineer who is denied is told to “build more visibility.” The engineer who is promoted is told they “demonstrated impact.” Neither feedback addresses the missing artifact trail.

Action items

For the committee: require artifact links for every impact claim

A claim without an artifact is a hypothesis. The committee can still consider it, but it should be labeled as unverified. This is not a punishment. It is a calibration. The committee’s job is to evaluate evidence, not prose.

Define the acceptable artifact types. A dashboard link with a saved query is an artifact. A PR series with review approvals is an artifact. A design doc with revision history is an artifact. A Slack thread is weaker but still an artifact. A verbal claim is not.

For managers: build the artifact trail before the packet deadline

The packet is a summary, not a discovery process. If the manager is writing the packet from scratch at deadline, the artifacts are already lost. Keep a running document per engineer: links to RFCs, dashboards, incident reviews, and peer feedback. This is not surveillance. It is the same evidence the committee needs.

For engineers: save the measurement, not just the outcome

When you run an experiment, save the before and after. When you ship a migration, link the dashboard. When you write an RFC, keep the thread. When you respond to an incident, write the postmortem. These are the artifacts that make impact legible.

This is not self-promotion. It is record-keeping. The organization already generates the evidence. The engineer’s job is to not lose it.

For the organization: define the evidence standard once

Publish the artifact types the committee accepts. Publish the format for linking them. Publish the rule that unverified claims are labeled. This removes the ambiguity that turns promotion into a writing contest.

HM Treasury’s Magenta Book provides a useful external reference for evaluation design: it emphasizes that evaluation should be built into an intervention’s design and delivery from the earliest stages, and that results need to be interpreted and presented with care. The same principle applies here. If impact evaluation is bolted on at packet time, the evidence is weak. If it is built into the work, the evidence is already there.

One reversible experiment

Pick one upcoming promotion packet. Before the committee reads it, ask the engineer and manager to add artifact links to every impact claim. If a claim has no artifact, mark it “unverified.” Run the committee session as usual. Compare the discussion to the previous cycle.

Rollback plan: If the artifact requirement slows the process without improving decisions, revert to the previous format for the next cycle. The experiment is reversible because it changes the packet format, not the promotion criteria.

What to measure: Did the committee spend less time debating unverifiable claims? Did the packet’s claims survive contact with the artifacts? Did any claim get withdrawn or narrowed? These are signals, not proof. But they are more useful than another cycle of prose review.

FAQ

Doesn’t requiring artifacts disadvantage engineers who work on invisible infrastructure?

It disadvantages engineers whose work leaves no artifacts. Infrastructure work leaves artifacts: dashboards, runbooks, incident reviews, migration RFCs, on-call logs. The problem is not invisibility. The problem is that the artifacts are not linked to the packet. If the work truly leaves no trace, that is a finding about the work, not the engineer.

Isn’t this just bureaucracy?

It is record-keeping. The organization already generates the artifacts. The packet currently ignores them. Linking them is less work than re-litigating the same claims in every calibration session.

What if the engineer did the work but the artifacts are owned by someone else?

Then the packet should say so and link the artifact. Ownership of the artifact is not the same as contribution to the outcome. The committee can evaluate contribution from the artifact trail: review approvals, RFC comments, incident response, commit history. The artifact does not need to be authored by the engineer. It needs to be linked.

How does this relate to the career ladder?

The ladder defines the expected level of impact. The artifacts define whether the impact occurred. If the ladder says “impact across teams,” the packet needs cross-team artifacts. If the ladder says “technical leadership,” the packet needs design docs, RFCs, or incident reviews. The ladder is the standard. The artifacts are the evidence.

What about qualitative impact, like mentoring or culture?

Qualitative impact still leaves artifacts: onboarding docs, peer feedback, exit interview notes, promotion packets of people the engineer mentored. These are weaker than dashboards but stronger than prose. The committee can weigh them accordingly.

Closing note

The packet is not the problem. The missing artifact trail is the problem. The packet is a symptom. The system failure is that promotion decisions are made on prose when the organization already generates evidence. Fix the trail, and the packet becomes a summary instead of a mystery.

The Architecture Decision Record That Records the Decision But Not the Duress

The Architecture Decision Record That Records the Decision But Not the Duress

The ADR is supposed to be institutional memory. What actually gets merged is the clean version. Six months later, a new engineer reads a confident decision and reverse-engineers a rationale that never existed.

SYMPTOM // REVERSE-ENGINEERED RATIONALE

A team I’ll call the Marlow group had a service that handled payment webhooks. Single-tenant Postgres instance, no read replicas, no connection pooling, and a max connections setting that the original engineer had guessed at. When the service started timing out under load, the team wrote an ADR proposing a migration to a connection pooler in front of a multi-tenant cluster. The ADR was clean. Context section, decision section, consequences section. Alternatives listed. Approved. Also fiction.

The migration had been proposed because the original engineer — the one who guessed at the max connections setting — had left three months earlier, and the person who inherited the service didn’t know how to tune Postgres. The ADR framed this as a scaling decision. The actual context was a knowledge gap and a deadline. The dissenting voice in the RFC thread — a backend engineer who had argued for trying pgbouncer on the existing instance first — was overruled in a meeting that wasn’t referenced in the document. Their comments were in the thread. But the reply that closed the discussion — “Let’s go with the migration, we can revisit pooling later” — was timestamped 11 PM on a Friday. The engineer who objected went on vacation the next morning. By the time they came back, the ADR was merged.

Six months later, a new hire read the ADR and concluded that the team had deliberately chosen a multi-tenant architecture for long-term scalability. They built new services on the same pattern. When one of those services hit the same connection exhaustion problem, they assumed it was a different bug — because the ADR said the pattern was chosen for scaling, not because of a knowledge gap. The rationale they inherited was a story the team told after the fact. It was not the reasoning that produced the decision.

I’ve watched this pattern break at least four teams. Not the Postgres part — the documentation part. The ADR, the RFC thread, the technical strategy document: these are supposed to be the institutional memory of why we chose what we chose. But the artifact that gets merged or approved is almost always the clean version. The dissenting comments, the “I disagree but won’t block” caveats, the concerns raised in a side channel that never made it into the thread — that’s the actual decision context. And it’s the part nobody writes down.

§ 1 — WHAT THE ARTIFACT HIDES

The function of an ADR is to preserve decision context across time and team turnover. The failure mode is that the artifact preserves the outcome but strips the duress. Duress is the pressure under which the decision was actually made: the deadline, the missing expertise, the political constraint, the person who disagreed but was too tired to fight. Strip the duress and you leave behind a decision that looks rational and deliberate. The next reader assumes it was.

Google’s SRE book dedicates an entire chapter to postmortem culture and the principle that documenting what actually happened — including the messy, uncomfortable, politically charged reality — is the only way an organization learns from failure rather than repeating it with better confidence. The Google SRE book’s postmortem culture chapter is the closest established parallel to this problem: the gap between the clean summary and the actual timeline is where institutional knowledge dies. The same principle applies to ADRs. A postmortem that records the outage but not the contributing factors teaches nothing. An ADR that records the decision but not the duress teaches the wrong thing.

The specific signals of suppressed dissent are in the artifact itself. You just have to know what to look for.

§ 2 — THE FORENSIC READ

Pull the last five merged ADRs or approved RFCs from your team’s repository. For each one, inspect these four signals:

1. Comment threading depth versus final document depth. Count the nested reply levels in the discussion thread. Then check whether the concerns raised in the deepest branches appear in the final document. If the thread has four levels of nested replies and the ADR’s Alternatives Considered section has two sentences, you have a gap. The deepest branches are where the real disagreement lives — that’s where someone stops arguing with the proposal and starts arguing with the person who made it. If that content doesn’t surface in the ADR, the document is hiding the decision’s actual shape.

In the Marlow group’s ADR, the thread had a branch that went five levels deep on whether pgbouncer in transaction mode would break prepared statements. The final ADR’s alternatives section said: “Connection pooling was considered but deemed insufficient for projected scale.” No mention of prepared statements. No mention that the objection was technical, not strategic. The sentence reads as if pooling was evaluated and dismissed on its merits. The thread shows it was dismissed because the person who understood the tradeoff went on vacation.

2. Edit timestamps versus comment timestamps. Most RFC tools and wiki platforms expose edit history. Compare the document’s last edit time to the last substantive comment. If the document was edited after the last comment without that comment’s content being incorporated, you’re looking at a decision that was finalized by editing, not by discussion. The edit is where the author quietly resolved the disagreement by removing it from the record.

This is the most common suppression pattern I see. Someone raises a concern. The author agrees to “address it” in the document. The edit that follows doesn’t address it — it reframes it. The concern about prepared statements becomes “transaction mode limitations.” The concern about timeline pressure becomes “phased rollout recommended.” The original objection is gone. In its place is a passive-voice recommendation that nobody is accountable for.

3. The gap between Approved and the last substantive objection. Measure the time between the final substantive technical objection and the approval. If it’s under 24 hours, and especially if it’s under 4 hours, the approval happened before the objection could be resolved. This doesn’t mean the decision was wrong — it means the process didn’t include the objection. The objection existed, was recorded, and was overridden by time pressure, not by argument.

In a healthy process, the gap between the last objection and the approval reflects the time it took to address the objection. In a broken process, the gap reflects the time it took for the objector to give up. You can’t tell the difference from the document alone — but if the document doesn’t mention the objection at all, you can infer which one happened.

4. The conspicuous absence of certain voices. Cross-reference the list of people in the meeting where the decision was finalized against the list of people who commented in the RFC thread. If someone was in the meeting but not in the thread, their position on the decision is unrecorded. If that person is the most senior engineer on the team, or the person who owns the system the decision affects, their silence in the artifact is a signal. They may have agreed. They may have been overruled. You can’t tell — and that’s the problem.

The absence is the hardest signal to detect because it requires knowing who should have been in the thread. But it’s the most reliable indicator of duress. When the people who have the most context on a decision don’t appear in the written record, the written record is incomplete. The decision was made somewhere else. The document is a backfill.

§ 3 — THE REVERSE-ENGINEERED RATIONALE

Here’s what happens six months later. A new engineer — call them the inheritor — reads the ADR. They see a clean decision with a context section, alternatives, and consequences. The document reads as if the team evaluated the options and chose deliberately. The inheritor doesn’t have access to the thread. Or the thread has been archived. Or the tool has changed. Or the comments are in a Slack channel that was deleted when the workspace was reorganized. The inheritor does what engineers do: they reverse-engineer the rationale from the decision.

If the ADR says “We chose a multi-tenant architecture for long-term scalability,” the inheritor assumes the team had evidence of scaling problems. They build on that assumption. They extend the pattern. They cite the ADR in their own RFC as precedent. The original decision was made under deadline pressure by someone who didn’t know how to tune a database. The inheritor’s new decision is made under no pressure by someone who thinks they’re following a proven pattern. The fiction has become infrastructure.

This is how teams accumulate architectural decisions that nobody can explain. Not because the original decision was bad — it might have been fine under the circumstances. But because the circumstances weren’t recorded, the decision can’t be evaluated, only inherited. Every inherited decision narrows the space of what the team considers possible. And none of them can be questioned because none of them have a recorded rationale that can be examined.

The result is a codebase that feels inevitable. Why is everything multi-tenant? Because the ADR said so. Why did the ADR say so? Because that’s what we decided. The circularity is invisible because the duress that broke the circle was stripped from the record.

§ 4 — THE SAME FAILURE IN NARRATIVE PLANNING

This isn’t an engineering-only problem. Any team that maintains long-form written decision records faces the same core issue: the artifact that survives is the one that’s been cleaned up, not the one that’s true.

Consider a writing team that maintains editorial outlines — plot decisions, character arc rationales, structural choices documented for collaborators and for future reference. The same suppression pattern appears. The outline says “We chose a non-linear timeline to create thematic resonance between the two storylines.” The actual decision was made because the first draft had a pacing problem in act two and the editor suggested restructuring rather than rewriting. The outline doesn’t say that. Six months later, a collaborator reads the outline, assumes the non-linear structure was a deliberate artistic choice from the start, and builds subsequent plot decisions on top of a rationale that was never artistically intended — it was a fix that got promoted to a principle.

The Authors Guild’s guidance on writing practices emphasizes preserving the original voice, thinking, and creative reasoning that shape a work — the reasoning behind a decision is part of the work, not just the output. When editorial decision records strip that reasoning, they strip the same thing a duress-free ADR strips: the context that makes the decision legible to the next person who has to build on it.

The bridge is narrow and honest: teams that use AI novel writing software that preserves the decision trail alongside the draft face the same temptation to clean up the artifact. The tool can record the reasoning, the alternatives considered, and the disagreements — but only if the team treats the decision record as part of the work, not as paperwork to be filed after the work is done. The failure mode is identical whether the artifact is an ADR in a git repo or a narrative outline in a writing tool: the cleaned version becomes the official version, and the real context is lost.

§ 5 — ONE REVERSIBLE EXPERIMENT

For the next ADR your team writes, add a section called Decision Context — distinct from Context, which describes the technical situation. Decision Context records the conditions under which the decision was made. It answers four questions:

What deadline or pressure was active when this decision was finalized? Not the project deadline — the decision deadline. If the decision had to be made by Friday because someone was going on vacation, that’s the context. If it had to be made before a funding round, that’s the context. If there was no pressure and the team had unlimited time, write that — it’s the most important signal of all.

Who disagreed, and what was their objection? Name the objection, not the person. “An objection was raised that transaction-mode pooling would break prepared statements used by the webhook consumer. The objection was not resolved before approval.” That sentence tells the next reader everything they need to know: the decision was made with an unresolved technical concern, and the concern is specific enough to investigate.

What was the strongest argument against this decision? Not the alternatives that were considered — the strongest case for not doing it at all. If the ADR can’t articulate the best argument against itself, the ADR wasn’t written by someone who understood the tradeoff.

What would make us revisit this decision? The conditions under which the decision should be re-evaluated. Not “if requirements change” — that’s meaningless. “If the webhook service exceeds 500 connections per second, the pooling decision should be revisited because the current rationale was based on projected load of 200 cps.” That gives the inheritor a concrete test, not a vague disclaimer.

The experiment: add the Decision Context section to one ADR. Don’t mandate it for all ADRs. Don’t change the template. Don’t announce a process change. Write one ADR with the section and see what happens when the next engineer reads it. If they ask better questions about the decision, the section earned its place. If nobody reads it, you have a different problem — your ADRs aren’t being read at all, and the duress issue is downstream of a documentation culture that doesn’t exist yet.

Rollback: if the section creates friction — if people spend more time arguing about what counts as duress than making decisions — remove it. The section is a diagnostic, not a process. Its value is in what it reveals about the decision, not in its compliance as a template field. If it becomes a checkbox, it’s failed. A good Decision Context section reads like a person writing honestly about what happened. A bad one reads like a form being filled out. The difference is obvious.

§ 6 — THE ARTIFACT IS THE EVIDENCE

The ADR is not a record of what the team decided. It’s a record of what the team was willing to write down about what they decided. Those are different things. The gap between them is where the next team’s confusion lives.

When you read an ADR, read it forensically. Look for the threading depth that didn’t make it into the summary. Look for the edit that came after the last comment. Look for the approval that came too fast. Look for the voices that aren’t there. The document is telling you what happened — but it’s telling you by what it omits, not just by what it says.

And when you write one, write the duress. Write the deadline. Write the objection that wasn’t resolved. Write the argument against your own decision. The clean version is the one nobody learns from. The messy version is the one that saves the next engineer from building on a rationale that never existed.

The ADR is not a record of what the team decided. It’s a record of what the team was willing to write down about what they decided.