The cost of a wrong constraint: when an ADR documents a constraint that was never real

The constraint is the most load-bearing element of any architecture decision record. Context sections describe what forced the choice — the latency ceiling, the team skill set, the vendor contract, the deadline. Future decisions treat documented constraints as given facts and build on them. When a constraint was never real — when the engineer who wrote the ADR misidentified what was actually driving the decision — every downstream record that cites it is building on a false foundation.

Most ADR quality problems are visible and correctable at review time. A missing Alternatives section can be caught during PR review. A Decision field written as rationale rather than conclusion can be edited before merge. An ADR without a real Consequences section fails a quick five-item checklist.

The false constraint is different. It passes the checklist. It has a constraint. The constraint sounds specific and defensible. It's written in technical terms that reviewers can't easily verify without going back to source data that may not be available. And it's wrong in a way that doesn't surface until two years later, when a new engineer inherits three decisions that all cite the same phantom requirement and tries to understand why the system is built the way it is.

This isn't a rare failure mode. Most engineering teams that have been writing ADRs for two years or more have at least one false constraint in their decision log — usually in a high-stakes decision from the early days of a system, when the stakes were highest and the documentation pressure was real.

The constraint field and why it matters so much

In Nygard's original ADR format, the constraint lives in the Context section: the paragraph that explains the forces acting on the decision and why the team was making it at all. Context sets up the decision. It answers the question: "What would have to change for this decision to be wrong?" Future engineers reading the record use that answer as the basis for evaluating whether the ADR is still operative.

A constraint in the Context section is a load-bearing structural element. Not an observation — a claim. "Our p99 latency requirement is under 10ms" is a claim that frames every option evaluation in the Decision section. "The team has no operational experience with managed Kubernetes at this company size" is a claim that explains why the simpler deployment model won. "The licensing cost of the commercial option exceeded the approved quarterly budget" is a claim that eliminates entire categories of alternatives from consideration.

Future decisions don't just read those constraints — they depend on them. The next engineer evaluating a caching layer assumes the 10ms requirement is real and designs around it. The third engineer to join evaluates the self-managed infrastructure and asks whether it's time to revisit — and checks whether the stated constraint (no operational experience) has changed. The PM building the pricing model notes the budget constraint and doesn't allocate headroom for the more capable commercial tool.

When the constraint was right, this is the system working exactly as intended. The documented reasoning propagates forward, each subsequent decision benefiting from the accumulated context.

When the constraint was wrong, the compounding goes in the other direction.

Three patterns that produce false constraints

False constraints don't get written because engineers are careless. They get written because the constraint field is the hardest part of any ADR to populate accurately, and there are three well-worn paths to getting it wrong.

The misremembered constraint

The engineer writing the ADR draws on memory of the deliberation session — possibly a conversation that happened two weeks ago, or six months ago, or a meeting that was never recorded. The broad shape of the decision is correct. The outcome is correct. But a specific constraint — a number, a requirement, a limitation that felt important at the time — is misremembered from a different context entirely.

A common form: the engineer has worked at multiple companies with real sub-millisecond latency requirements. One of those requirements was genuine, hard-won, and validated under production load. It sits in their memory as what "latency constraint" feels like. They document a latency constraint in the current decision because latency was relevant to the conversation — but the specific number in the current context came from a past project, not from any measurement or requirement in this system.

The misremembered constraint is often more specific and precise than the real constraint would have been. Real constraints are hedged — "we were worried about latency at scale" — because the team didn't have clean data. Misremembered constraints are clean because they've been processed into a memory with false precision.

The rationalized constraint

The real driver of the decision was familiarity, budget, timeline, or team preference — none of which sound rigorous in a documentation artifact that will be read by engineers for the next three years. So the engineer who writes the ADR translates the real constraint into a more defensible technical or operational argument.

This is rarely intentional deception. It happens because the engineer genuinely believes both claims: the team does have limited experience with the unchosen technology, AND the team preferred the chosen technology. Both things can be true simultaneously. But when the ADR documents the experience constraint and omits the preference, future readers inherit a record that says "we chose this because of operational risk" when the weight of the decision was actually "we chose this because it's what the team knows and is comfortable with." Those are different constraints with different implications for when to revisit.

The rationalized constraint is often impossible to verify at review time. It's not wrong on its face. The reviewer can't know whether the stated constraint was the real driver or a post-hoc justification unless they were in the original conversation.

The absent constraint

The real constraint was implicit — obvious to everyone in the room, not worth spelling out, "everyone knows this." The engineer writing the ADR documents the secondary constraints that supported the choice but doesn't document the primary constraint because it felt like background knowledge rather than an explicit driver.

Three years later, "everyone who was in the room" has largely turned over. What felt like background knowledge was actually load-bearing context. The absent constraint is the most insidious form because the ADR contains no obvious gap — it has a Context section, it has constraints documented, it just doesn't have the most important one.

This is the version most likely to affect the new CTO who inherits a system she didn't build and reads through the decision log trying to understand why the architecture looks the way it does. The documented constraints tell a coherent story — but the story has a chapter missing, and the missing chapter was the one that contained the actual reason.

A worked example: the latency constraint that was a familiarity constraint

Here's the pattern in a concrete form. The specifics are generic but the structure is real.

An engineering team in 2023 is choosing between Redis and Memcached for a session caching layer. Both are mature, both solve the problem, both are well-supported. The team has six months of production Redis usage across another service; nobody has touched Memcached in a professional context. After a two-hour deliberation — including a Claude session where one engineer thinks through the clustering and eviction model differences — the team chooses Redis.

The engineer writing the ADR documents the Context section. The decision was right and defensible. They reach for a constraint to anchor it. Latency was discussed. Redis clustering was discussed. The ADR Context reads:

Our session lookup requirement is under 5ms at p99. Redis Cluster provides predictable low-latency lookups with automatic failover. Memcached's distributed model requires client-side sharding, which adds operational complexity we cannot absorb at our current team size.

The 5ms requirement did come up in the conversation — as a general statement that the system needed to be fast, not as a validated SLA or a measurement. The operational complexity statement is true in a general sense but not specifically what drove the decision. The actual weight of the choice was: the team has six months of Redis experience and zero Memcached experience, the learning cost is real and immediate, and given equal capability the familiar tool wins.

The ADR never says that. The familiarity constraint felt too informal to document. The performance and operational complexity arguments felt rigorous. So they went into the Context section and the familiarity constraint didn't.

Three consequences follow over the next eighteen months.

First: when the platform team evaluates an infrastructure consolidation that would require migrating the session cache to a different provider, they model the effort against the 5ms requirement. They spend four days determining whether the alternative can meet that SLA, run load tests, and ultimately conclude it can't. The constraint in the ADR guided four days of investigation. The real constraint — team familiarity — was never part of their evaluation and would have resolved in two hours.

Second: a new engineer inherits the caching architecture as part of an onboarding project. She reads the ADR and the 5ms requirement. She asks whether anyone has measured actual Redis p99 latency in production and whether it's anywhere near 5ms. Nobody can answer. The constraint is examined, found unverifiable, and quietly noted as "probably conservative" — but it's not corrected in the record because editing an Accepted ADR body is discouraged, and nobody writes a Notes amendment at the time.

Third: a subsequent ADR about a read-through cache layer for the product catalog cites the session cache ADR's 5ms requirement as evidence for a latency constraint across all caching layers. Now the false constraint has propagated. The product catalog caching decision is evaluated against a performance baseline that came from a misidentified constraint two ADRs back.

This is what the gap between documented reasoning and actual reasoning costs in practice. Not a catastrophic failure. A slow accumulation of decisions built on a foundation that wasn't what it claimed to be.

How the false constraint compounds

Each ADR that cites a previous constraint treats that constraint as verified fact. The review process for the citing ADR checks whether the cited constraint is still relevant, not whether it was ever accurate. Nobody re-derives the original ADR's context from first principles when writing a decision that builds on it.

This is rational behavior — the whole point of a decision log is that you don't have to re-litigate previous decisions. But it means that a false constraint in an early, high-impact ADR can propagate through a decision chain for years before anyone has a reason to examine it carefully.

The propagation follows a characteristic pattern. Constraints that are cited frequently become background knowledge — eventually treated as load-bearing facts about the system rather than claims made by a particular engineer at a particular time. The longer a constraint has been in the log, the more confidently it's cited. The more confidently it's cited, the less likely any individual reviewer is to question it.

By the time a new engineer joins a team and genuinely doesn't understand why a constraint exists — "wait, why is our p99 requirement 5ms for a session lookup?" — the constraint has been cited in three ADRs and is mentioned in two runbooks. Challenging it requires an archaeological investigation: find the original ADR, understand when it was written, find the people who were involved, determine whether the constraint was measured or assumed. Most engineers don't do that work in the middle of a sprint. The constraint persists.

This is the distinction between the decision and the reasoning behind it made concrete. The decision (use Redis) is visible and probably still correct. The reasoning (5ms requirement, operational complexity) is what gets examined when someone considers changing the decision. When the reasoning was wrong from the start, the examination is both necessary and impossible to do correctly without recovering the original deliberation.

The detection test: does the original deliberation support the constraint?

There's a direct verification test for constraint accuracy: find the deliberation session that preceded the ADR and check whether the constraint as documented appears there.

For most decisions made in the past three years, that deliberation exists somewhere. It might be in a design doc, a Slack thread, a PR comment, or — most commonly for engineers who use AI tools daily — a ChatGPT or Claude session where someone thought through the trade-offs before committing to a direction.

The AI chat session is particularly useful for this verification because the deliberation there is often more honest than the documentation. The person in the chat session was working through a real problem, not performing rigor for an audience. They said "I think we should just use Redis because the team knows it" before they thought about how to frame that for an ADR. They mentioned the timeline pressure, the staffing gap, the fact that they personally find Memcached's eviction behavior confusing. Those things are in the chat session because they were real drivers, not because they were defensible documentation.

The WhyChose extractor processes exported ChatGPT and Claude conversation history and surfaces the decision sessions — the exchanges where a real choice was being evaluated and a direction emerged. Running the extractor on the relevant time window gives you the raw deliberation. Cross-referencing that with the ADR Context section answers the verification question: does the documented constraint appear in the deliberation, or was it constructed afterward?

Three specific signals suggest a constraint is false when you run this check:

The constraint doesn't appear in the deliberation at all. The documented constraint cites a specific performance requirement. The deliberation session has no mention of a performance requirement, a latency number, or any measurement. The conversation is entirely about alternatives, team experience, and operational complexity. The performance constraint was added during writeup, not drawn from the conversation.

The deliberation contains a different constraint. The chat session does discuss constraints — but they're different from what got documented. "We have about six weeks to get this live, which means we can't afford a learning curve" appears in the deliberation; the ADR's Context section mentions nothing about timeline but does mention operational complexity. The real driver was timeline; the documented driver sounds more principled.

The constraint appears in the deliberation but at a different weight. The performance constraint was mentioned once, in passing, as a secondary consideration. The familiarity constraint was discussed at length, with the specific concern named and the alternatives evaluated against it. The ADR gives the performance constraint top billing in the Context section. The deliberation's evidence for its centrality is thin.

If you can export the relevant ChatGPT conversation history or Claude exports from around the time the ADR was written and run the extractor, this verification can be done in an afternoon for a decision log of any reasonable size. The extractor surfaces sessions with decision signals — option comparisons, trade-off evaluations, directional conclusions — and outputs them with dates and context, making the cross-reference straightforward.

The constraint verification fails silently when the original deliberation can't be recovered — when the chat history predates the export, when the decision was made in a meeting with no written trace, when the relevant sessions were deleted. In those cases, the review checklist question "can you name the event or measurement that established this constraint?" is the fallback. If nobody in the room can answer it for a constraint that's been cited in three subsequent ADRs, that's a signal worth noting.

Correcting the record without destroying it

The correct response to a confirmed false constraint is not to edit the ADR body. Editing accepted ADRs in place violates the immutability principle that gives the record its audit-trail value — in-place edits replace historical belief with current understanding without any record of the change. The ADR's body represents what was understood at the time of the decision; that historical record has independent value even when the documented understanding was wrong.

The right correction is a dated Notes amendment appended to the record. The Notes section is the designed mechanism for context evolution that doesn't reverse the decision. A well-formed constraint correction note looks like this:

2026-06-12: Context audit. The 5ms p99 latency requirement documented in this ADR's Context section was not validated by any load measurement at the time of this decision (confirmed by review of the original deliberation session recovered via ChatGPT export dated 2023-07-14). The actual primary constraint was team familiarity with Redis vs. Memcached clustering models. The decision (use Redis) remains correct and this correction does not change the operative status of the record. Downstream ADRs that cite this latency requirement should be annotated to note the constraint's origin. — [engineer name], 2026-06-12

The note does four things: names the specific claim that was incorrect, explains how the determination was made, confirms the decision itself is still sound, and flags the downstream impact. It doesn't reverse the ADR, doesn't require a new vote, and doesn't change the system. It changes the informational status of the constraint from "documented fact" to "documented but unverified claim with a note on its provenance."

The question of whether to escalate to a full supersession depends on whether the false constraint actively misleads. If three subsequent ADRs cite the constraint as the primary basis for their decisions, and those decisions would have gone differently with an accurate constraint, supersession may be warranted — not to reverse the original decision, but to write a corrective record that documents the true constraint and evaluates whether the subsequent decisions still hold. If the false constraint was cited but wasn't decisive in the downstream choices, the Notes amendment is sufficient.

The annotated false constraint is actually more useful than an uncorrected one. It signals to future readers that this record's Context section should be read with awareness of the provenance issue. It gives the next engineer who inherits this codebase a reason to ask "what was the actual constraint?" rather than accepting the documented one as fact. It creates the kind of honest, self-correcting decision log that the practice was designed to produce.

Prevention: constraint extraction before writing

The most reliable prevention for false constraints is to derive the Context section from the deliberation rather than from memory. This sounds obvious but runs against how most ADRs are actually written: in arrears, after the decision is made and the implementation is underway, when the deliberation session is two weeks old and the engineer is working from recollection.

The practical difference is where you start writing the Context section. Starting from memory produces the constraints that are easiest to recall — often the most defensible-sounding ones, the performance arguments and the operational complexity claims. Starting from the deliberation record produces the constraints that were actually operative — which frequently include the less defensible-sounding ones, the familiarity constraints and the timeline constraints and the "we're not sure but we're more comfortable with option A" constraints.

For engineers who use AI tools in their deliberation, the deliberation record exists. If you're writing an ADR for a decision that was worked through in a ChatGPT session, export the session and find the relevant conversation before you write the Context section. The constraint in the deliberation session — even if it's just "honestly the team hasn't used Memcached and we don't have time to ramp up" — is the real constraint. Document that. Document the performance argument too if it was present, but don't let it displace the real driver.

The decisions that never get written down are often the ones where the real constraint was too informal to document comfortably. The team decided to defer something because "we're not sure yet" — that's a real constraint (insufficient certainty). The team chose option A because the team lead had a strong preference — that's a real constraint (authority gradient in the decision). These constraints feel like admissions rather than technical content. They're not — they're accurate records of how decisions actually get made, and documenting them honestly makes the ADR useful.

At review time, the most useful question a reviewer can ask about the Context section is: "What is the single constraint that, if it changed, would most clearly indicate this decision should be revisited?" If the answer points to a constraint that isn't in the ADR, it needs to be added. If the answer points to a constraint that is in the ADR but nobody can explain how it was established, that's the constraint worth verifying before merge.

The ADR review checklist typically focuses on completeness: are all sections present, are alternatives named, is the decision stated clearly. Constraint verification is a different check — one that asks about provenance rather than format. Those two checks catch different failure modes. The format check catches the visible gaps. The provenance check catches the false constraint that passes every format requirement.

The honest ADR is the useful ADR

There's a version of the false constraint problem where the fix is just higher standards — more rigorous documentation, better review processes, more careful engineers. That version is real but incomplete. The false constraint also gets written because of a legitimate structural pressure: the engineer documents the decision in a form that will read as credible to people who weren't present, under time pressure, working from an imperfect memory of a conversation that happened weeks ago.

The most durable fix is to reduce the gap between when decisions are made and when they're documented — and to use the deliberation record as the primary source for the Context section rather than recollection. When the deliberation happened in an AI chat session and that session is recoverable, the constraint verification is straightforward: find the session, find the constraint, confirm the match.

An ADR that accurately names the familiarity constraint — "we chose this because the team knows it and we don't have the learning curve capacity right now" — is more useful than one that documents a performance constraint that was never validated. The familiarity constraint tells you when to revisit: when a new team member joins who does know the alternative, when the learning curve becomes worthwhile relative to the benefits, when team composition changes enough that "what the team knows" has shifted. The false performance constraint sends you chasing benchmarks that weren't the point.

The downstream cost of a false constraint isn't paid at write time. It's paid by the next engineer who reads the ADR and builds something on it, and by the engineer after that, and by the person who inherits a system and can't understand why it was built the way it was because the constraint that explains the choice was documented with false precision and never corrected.

The honest constraint — even when it's informal, even when it names a timeline pressure or a familiarity bias or an organizational factor — is the one that makes the record actually useful in three years. The defensible constraint that replaces it makes the record look more rigorous while making it less true.

Further reading