The technical debt decision record: why the tolerance model you chose determines your refactoring surface and your engineering velocity ceiling
Technical debt tolerance decisions are made in the founding sprint, in the AI session where someone asks "how much should we care about code quality right now?" The answer is "ship it, clean it up later" — a reasonable answer in context, because the company does not yet know which parts of the codebase will become the critical paths and which will be rewritten or abandoned within six months. The implementation follows the answer: the team moves fast, the code ships, the product grows. "Later" is never defined. The debt is never classified. The clean-up condition is never specified. The implicit policy — tolerate whatever level of debt enables current velocity — becomes the permanent policy by default, because no session ever produced the document that would replace it.
The technical debt tolerance decision is not a single choice about how messy the code can be. It is a set of structural decisions that determine how debt accumulates, how it becomes visible, who decides when it is paid down, and what the repayment target looks like when it is addressed. A team that does not document these decisions does not avoid making them — it makes them by default, in individual code review discussions, in sprint planning conversations where "we should clean this up" competes with feature stories for capacity and loses, in engineer onboarding sessions where a new hire asks "why is the auth layer structured this way?" and the most accurate answer is "I don't know; it predates everyone on the team." The decisions are made. The absence of documentation means they cannot be evaluated, revised, or revisited until the accumulated consequence — a production incident, a security audit finding, an engineer who leaves as the last person who understands a critical subsystem — forces an unplanned remediation that is more expensive than the deliberate one would have been.
Two ways technical debt tolerance decisions produce the wrong outcome
The auth layer fragmentation story
A 28-person B2B SaaS company builds a microservices architecture for its HR data platform. In the founding sprint, the engineering team ships the first three services quickly: an API gateway, a user service, and a data ingestion service. The founding engineers are experienced and pragmatic: they know the domain will change as they learn from early customers, so they make a deliberate choice to keep the initial implementations simple and plan to standardize patterns once the architecture stabilizes. This is the correct decision for the stage. It is not documented anywhere. There is no document that says "we are intentionally deferring auth standardization until we have three enterprise customers and understand their SSO requirements; the repayment trigger is Q3 of the first year."
Twelve months later, the platform has grown to 14 services. Each service authenticates requests differently. The original user service validates JWT tokens using the jsonwebtoken Node.js library, version 8.5.1, with a 24-hour expiry hardcoded in the service configuration. The data ingestion service was written by a contractor who used the jose library, a newer implementation that supports the JWT best current practices draft; it validates tokens with a 1-hour expiry and explicit algorithm locking to RS256. A billing service written during a security incident was copied from a third company's open-source starter kit, which uses passport-jwt middleware with its own session handling layer. Two newer services, written by engineers who joined after the original founding team, use a shared auth middleware library that the most senior engineer wrote at month eight to solve this exact problem — but the adoption of the middleware is voluntary, and the services written before month eight predate it and have never been migrated.
A security review commissioned for an enterprise customer's procurement process finds five distinct JWT validation code paths across the 14 services, with three different expiry policies, two different algorithm configurations, and one service (the billing service) that does not explicitly validate the token algorithm and is therefore vulnerable to the "alg: none" attack described in CVE-2015-9235. The remediation is scoped by the security firm as a four-to-six week project — audit all 14 services, standardize on the shared auth middleware, update all service configurations, run penetration testing on the consolidated implementation, and produce audit evidence of the changes. The actual remediation takes eleven weeks because the auth middleware written at month eight was designed for the architectural patterns of the services that adopted it, and the older services use request lifecycle patterns that require the middleware to be extended before it can be adopted without regressions. The engineer who wrote the middleware leaves during week four of the remediation, taking with her the context needed to safely extend it. The total cost — engineering time, delayed enterprise sales cycle, security firm fees, and a one-month slip in a product roadmap milestone that was waiting for the enterprise customer to close — is substantially higher than the cost of the auth standardization project would have been at month eight, when the middleware existed and the older services were still being actively modified. The founding decision to defer auth standardization was correct at the time it was made. The absence of a documented repayment trigger — the condition under which the deferral ends — was the error.
The 20% sprint capacity story
A 40-person product engineering team at a Series B SaaS company is accumulating technical debt faster than it is paying it down. Velocity has declined measurably over 18 months: stories that took one sprint to complete in the first year now routinely take two or three, and the engineering manager's retrospective data shows that the primary reason is "unexpected complexity in the existing code." The CTO responds with a structural policy: 20% of every sprint's capacity is reserved for technical debt work, effective immediately. Engineers approve. The policy is announced as a sign that the company takes engineering quality seriously.
Six months after the policy is introduced, velocity has not improved. The engineering manager's retrospective data shows the same "unexpected complexity in the existing code" pattern at the same frequency. The CTO audits where the 20% capacity has been going. The findings: the payment service team spent their 20% time extracting business logic into a clean domain model layer with comprehensive unit test coverage — an improvement that produced genuinely clean code in a service that handles $2M of monthly recurring revenue but that is architecturally stable and rarely the source of unexpected complexity. The infrastructure team spent their 20% time refactoring the internal deployment scripts to use more idiomatic Bash — well-intentioned, low-leverage. The product engineering teams each independently worked on whatever local area they personally found problematic: a rate-limiter abstraction that the engineer disliked, a database query builder that was verbose, an event serialization pattern that was inconsistent across three services. None of these improvements addressed the actual sources of the unexpected complexity that was dragging velocity: a notification system with six independent code paths that had grown from one to six through four years of feature additions without architectural review, an authorization model that mixed business rules with infrastructure logic in ways that made both harder to test and extend, and a data model in the core product schema that had been amended eighteen times with migrations that each addressed the immediate requirement without being evaluated against the long-term schema design. These three systems were the sources of more than 70% of the "unexpected complexity" time from the retrospective data. They were not touched in six months of 20% capacity allocation because no engineer owned them strongly enough to volunteer to work in them, because they were not the most interesting areas to improve, and because the 20% policy provided no guidance on which debt to prioritize — only how much capacity to allocate. The policy had a budget and no criteria. The criteria would have required someone to ask: what are the three highest-leverage debt items in terms of their effect on the team's current velocity, and what is the specific measurable outcome that would indicate that each item has been addressed?
Three structural properties that technical debt tolerance determines
The debt classification model and the accumulation trigger
Technical debt accumulates through four distinct mechanisms, and each mechanism requires a different response model. The first is deliberate deferral: a team makes a conscious trade-off, choosing a simpler implementation now with the explicit intent to improve it later. This is the mechanism Ward Cunningham's original metaphor described, and it is the only mechanism that produces debt with a documented rationale and a condition for repayment. Deliberate deferral is not a problem to be avoided — it is a tool to be used correctly, which means documenting the deferral decision with enough specificity that the repayment trigger is unambiguous. The second mechanism is knowledge debt: a team implements a solution using the best approach they currently know, and later learns that a better approach exists. The implementation was not careless at the time it was written; it has become suboptimal as the team's domain knowledge has grown. Knowledge debt is retrospectively discoverable but not prospectively preventable, which means the response model is periodic architectural review against current best practice, not point-in-time code review. The third mechanism is architectural drift: a series of locally reasonable decisions accumulates into a global state that no individual decision intended. The auth layer fragmentation described above is architectural drift — each service author made a reasonable local choice, and the aggregate of those choices produced an inconsistent, difficult-to-audit auth architecture that no one chose. Architectural drift is the hardest category to address because it requires identifying the drift before it can be treated as debt, which requires comparing the current system against an intended architectural baseline that may never have been written. The fourth mechanism is entropy: stable code that was correct when written becomes incorrect as the context around it changes — library versions it depends on reach end-of-life, APIs it integrates with deprecate the endpoints it uses, security vulnerabilities are discovered in the algorithms it implements. Entropy-driven debt has a unique property: it does not require any action by the team to accumulate, and it can accumulate in code that is not being actively touched.
The classification model must be established before the debt registry is populated, because the category of a debt item determines who is responsible for it, what the repayment trigger is, and what a completed remediation looks like. Deliberate deferral debt has a documented author, a documented rationale, and a documented trigger — the registry entry was created at the time the deferral was made. Knowledge debt is identified in architectural reviews and code walkthroughs, and the repayment trigger is either "before the next major modification to this subsystem" or "when the complexity of the current approach begins causing velocity drag." Architectural drift requires a periodic full-system review to identify, and the repayment trigger is typically a threshold on the number of interacting inconsistencies ("more than three different patterns for the same concern in a single service boundary is the escalation threshold"). Entropy debt is tied to external timelines: a library EOL date, a deprecated API sunset date, a CVE remediation deadline. The dependency upgrade decision record is the companion document for entropy debt — the same undocumented reasoning that causes teams to defer upgrades is what causes entropy debt to accumulate undetected.
The visibility mechanism and the recency bias problem
Technical debt is only actionable when it is visible. Debt that exists but is not represented in any discoverable artifact — a registry entry, a TODO comment, a tracked issue, a test that is marked as expected to fail — is invisible until someone encounters it while working in the affected code. The invisibility creates a systematic recency bias in debt repayment: the debt that gets addressed is the debt that the current team is actively encountering, which is the debt in the code areas currently under modification. The debt in stable, rarely-touched subsystems — which may be the highest-leverage debt in terms of its risk if the subsystem contains a security vulnerability or a reliability ceiling — is encountered less frequently, addressed less frequently, and accumulates silently for longer.
The visibility mechanism has two components that both require explicit design decisions. The first is the discovery process: how is debt identified and logged? Point-in-time discovery — an engineer notices debt while implementing a feature and logs it — captures only the debt that is encountered in the course of current work. This produces the recency bias directly: work in high-velocity areas surfaces debt in high-velocity areas; stable subsystems are not discovered through current work. Systematic discovery requires periodic processes that examine the full codebase rather than just the currently-modified areas: quarterly architectural reviews, dependency audits, security scans, and onboarding sessions where a new engineer is asked to document the areas of the codebase they found surprising or difficult to understand. Onboarding-based discovery is particularly effective for architectural drift because a new engineer without established context will notice inconsistencies that existing engineers have normalized. The decisions never written down post identifies the onboarding session as the moment where the absence of documentation becomes most visible — and the debt registry is the structural response to that visibility problem. The second component is the registry format: how is debt represented such that it can be prioritized, assigned, and tracked to completion? A registry entry that names a file path and describes a vague concern ("the auth module is messy") is not actionable. A registry entry that names the specific technical condition, the affected code paths, the estimated remediation effort, and the repayment trigger provides enough context for a planning session to make a real prioritization decision without the engineer who identified the debt needing to be in the room.
The repayment ownership model and the priority displacement mechanism
Technical debt has no natural owner. Feature work has a product owner, a priority, and a sprint assignment. Bug fixes have severity classifications and SLA commitments. Technical debt competes with both for the same engineering capacity, and without an explicit ownership model it loses every time — not because anyone decides it should lose, but because it has no advocate in the prioritization process that has equivalent standing to the stakeholders advocating for features and bug fixes. The 20% sprint capacity story above is the canonical outcome of allocating capacity for debt repayment without establishing a repayment ownership model: capacity is allocated, debt is worked on, but the work is not directed toward the highest-leverage debt because no one has both the authority and the information to make that direction decision.
The ownership model must answer three questions explicitly. First, who decides which debt items are scheduled for repayment in the current sprint? The correct answer is not "engineers during the 20% sprint time" — that produces undirected improvement. The correct answer is a specific role (usually the engineering manager, tech lead, or staff engineer who owns the relevant subsystem) who reviews the debt registry against the current sprint scope and the near-term roadmap before sprint planning begins, selects the highest-leverage items, and brings a prioritized list to sprint planning as a first-class input alongside feature stories. Second, what is the prioritization criteria? The criteria must be explicit and shared, so that the engineer who disagrees with a prioritization decision has a framework for raising the disagreement rather than a feeling that their judgment is not being used. The criteria should weight debt by its leverage on current-cycle velocity (debt in code touched in this sprint costs more than debt in stable code), its risk profile (security and reliability debt above velocity debt), and its roadmap interaction (debt that will be expensive to work around in the next planned feature). Third, what is the completion standard for a debt repayment item? A registry entry that is marked as complete should have a specific technical outcome that distinguishes "done" from "improved" — the specific refactoring completed, the specific pattern consolidated, the specific test coverage reached. The completion standard is what makes the registry useful as an audit trail and as a planning input: a team that reviews a registry with clear completion records can evaluate whether past debt investments produced the expected velocity improvement, which is the only feedback loop that validates or invalidates the prioritization criteria over time. The test strategy decision record is directly downstream of the refactoring ownership model: the test coverage gate that must be met before a refactoring is merged is a product of the test strategy, and a team without an explicit test strategy has no shared standard for what "adequately tested" means for a refactored subsystem.
Three AI session types that embed debt tolerance decisions without documenting them
The founding implementation session is where the debt tolerance baseline is set. The team is building the first version of the product and asks "what's the fastest way to implement this?" The answer provides the fastest approach. Nobody asks "what would we need to change about this implementation before the codebase grows to 50 engineers and this code is being modified by people who weren't in this session?" That question is not in the founding session's agenda because the team of three is focused on shipping the first version before they run out of runway. The implementation goes in as-is. The technical debt created by the founding implementation is the highest-interest debt in the codebase: it is in the oldest code, it is the foundation that subsequent code is built on, and it is the hardest to refactor because it has the most downstream dependencies. None of this was discussed in the session. The AI conversation log from that session contains the original rationale for every implementation choice — why this data model, why this auth approach, why this error handling pattern — in the form they took when the team first made them. The open-source extractor is designed to surface exactly these founding implementation sessions as structured decision records before the cost of not having them becomes visible in a security audit or an engineer departure.
The feature extension session is where architectural drift accumulates. The team has a working system and adds a new requirement that is similar to an existing feature but not identical. The AI session proposes an implementation that extends the existing pattern with the necessary modifications. Neither the engineer asking nor the AI answering has full context on all the existing implementations of similar patterns in the codebase — the AI's context window includes the code the engineer shares, not the three other services that also implement the same pattern differently. The implementation goes in. The codebase now has four slightly different implementations of the same pattern. Each implementation was reasonable in its local context. The aggregate is an inconsistency that will need to be resolved before the next engineer who needs to implement the same pattern can rely on a single reference implementation. This session accumulates architectural drift at the rate of new feature extensions. Without a mechanism that asks "does this implementation align with the existing pattern for this concern?" at code review time and logs a debt item when the answer is "not quite," the drift compounds silently until a systematic architectural review makes the full extent visible.
The incident hotfix session is where deliberate deferral happens without documentation. The production system is misbehaving, the on-call engineer is in an AI session designing a fix, and the fix is a targeted patch that addresses the immediate symptom without addressing the underlying structural condition that caused it. This is often the correct choice during an active incident: a clean architectural fix is a high-risk change under time pressure, and the goal during the incident is to restore service, not to improve the architecture. But the incident session produces a fix and a post-incident review, and neither artifact records the structural condition as a debt item with a documented repayment trigger. The postmortem ADR covers the post-incident review as an opportunity to produce exactly this debt record — the structural root cause of the incident, written as an architecture decision record that documents the debt incurred by the hotfix and the condition under which the full structural fix is scheduled. The absence of that record means the hotfix becomes the permanent implementation when "clean it up later" is never triggered, and the next incident in the same subsystem finds the same structural condition. WhyChose's extractor surfaces the original incident response sessions from AI chat history as structured records that include the implementation rationale, the trade-offs that were explicitly weighed during the hotfix, and the improvements the team knew should be made but deferred — all in a format that can be logged as a registry entry and attached to the post-incident review.
The five sections of a technical debt decision record
The first section documents the debt classification model and tolerance threshold. This is not a single tolerance level ("we tolerate medium technical debt") but a per-category threshold: what level of deliberate deferral debt is acceptable before a mandatory review is triggered, what is the maximum acceptable age for an unresolved entropy item with a known CVE, and what is the threshold on pattern inconsistencies within a single service boundary that escalates from "accepted drift" to "architectural debt requiring remediation." The classification model must enumerate the four debt types (deliberate deferral, knowledge debt, architectural drift, entropy) and specify the discovery mechanism for each: deliberate deferral is logged at decision time; knowledge debt is discovered in architectural reviews; architectural drift is identified in periodic consistency audits; entropy is tracked via dependency version dashboards and CVE monitoring. The tolerance threshold is the statement of how much of each type the team will accept before a registry item becomes mandatory rather than optional. Without this threshold, the registry accumulates items that are logged but never escalated to mandatory status, which produces the same outcome as having no registry.
The second section documents the debt registry structure and discovery cadence. The registry format specifies the required fields for each entry: identifier, affected scope (specific file paths or service names), category, discovery context, remediation effort estimate, and repayment trigger. The discovery cadence specifies how often systematic discovery processes run — the quarterly architectural review, the annual security audit, the per-sprint new-engineer onboarding session — and who is responsible for running them and logging their outputs as registry entries. The registry maintenance owner is named explicitly, with a backup owner. Without a named owner, the registry is maintained at the rate of voluntary contribution, which declines over time as the team's attention is pulled to current work. The registry review cadence — how often the registry is reviewed to update repayment triggers, close resolved items, and escalate items whose trigger conditions have been met — must be tied to a recurring planning event (quarterly planning, sprint kickoff) so that the review happens on a schedule rather than when someone remembers to do it.
The third section documents the repayment ownership model and prioritization criteria. This section names the role responsible for producing the prioritized debt list before each sprint planning cycle, specifies the prioritization criteria (leverage on current-cycle velocity, risk profile, roadmap interaction), and defines the authority model for escalating a debt item from "accepted" to "mandatory remediation." The escalation authority is important: a debt item in the registry with a soft repayment trigger can remain unaddressed indefinitely if no one has the authority to move it to mandatory status. The most common escalation trigger is a production incident in which the debt item's affected area is a contributing factor — at which point the item should be escalated to mandatory with a remediation deadline derived from the incident's SLA commitments and the affected service's SLO. The SLO and error budget decision record is the upstream document that determines what SLA commitments are in place for each service and therefore what remediation deadline is appropriate when debt in that service contributes to an incident.
The fourth section documents the refactoring scope definition and completion standard. For each debt category, this section defines what a complete remediation looks like. For deliberate deferral debt, completion means the implementation has been replaced with the intended improved implementation and the registry entry's repayment trigger condition is explicitly no longer true. For knowledge debt, completion means the suboptimal approach has been replaced with the known better approach and a test suite validates the new implementation against the same behaviors the old implementation provided. For architectural drift, completion means the inconsistent implementations have been consolidated to a single reference implementation, and the number of implementations of the pattern within the affected service boundary is one. For entropy debt, completion means the outdated dependency or deprecated API has been replaced with a current alternative and the affected service's dependency manifest reflects a version with active maintenance and no known critical CVEs. The completion standard is what makes it possible to evaluate whether the sprint time investment produced the expected improvement — and therefore whether the prioritization criteria and the effort estimates in the registry are calibrated correctly. A registry with clear completion standards that are consistently applied over multiple planning cycles produces calibration data: teams learn which debt categories they systematically underestimate, which areas of the codebase have higher remediation costs than the initial estimates suggested, and whether the velocity improvement from debt repayment is proportional to the investment.
The fifth section documents the architectural debt review cadence and escalation triggers. Architectural debt reviews are periodic, systematic examinations of the codebase against an explicit architectural baseline. The review cadence — quarterly for most teams, biannual for stable codebases, monthly for teams in high-growth phases where the architecture is evolving fastest — must be specified alongside the review scope (which services, which patterns, which dependencies are in scope for each review cycle), the output format (each review produces a set of registry entries with categories and effort estimates), and the escalation criteria (what level of drift or entropy concentration in a single area triggers an architectural escalation rather than a routine registry entry). The architectural baseline — the description of the intended architecture that review findings are compared against — must be maintained as a living document. A review that compares the current state against an architectural document written two years ago produces findings about the delta from a two-year-old baseline, which may not reflect the current team's intent for the architecture. The ADR lifecycle decision covers how individual architecture decision records are superseded or deprecated as the architecture evolves — the architectural baseline for technical debt reviews is the aggregate of the active (non-superseded) ADRs for the system, which means the debt review cadence is directly coupled to the ADR maintenance cadence.
The founding implementation session, the feature extension session, and the incident hotfix session each produce technical debt whose eventual cost — paid during a security remediation, an engineering velocity investigation, or a refactoring forced by an upcoming feature — exceeds the cost of the original implementation decision. The decisions are in the AI chat history: the rationale for the JWT validation library, the pattern choice for the feature extension, the explicit trade-off acknowledged during the hotfix design session. WhyChose's open-source extractor surfaces these sessions as structured decision records before the cost of not having them becomes visible in an audit finding, a velocity slowdown investigation, or the departure of the engineer who was the only person who remembered why the original choice was made. The decisions never written down post covers why technical debt decisions are the canonical example of founding choices that accumulate invisible interest — and the new CTO onboarding problem describes what it costs an incoming engineering leader to evaluate the codebase's debt profile when none of the founding decisions were ever recorded.
Further reading
- The dependency upgrade decision record — entropy debt accumulates in the same undocumented way as technical debt; the upgrade deferral rationale is the debt record you need before the EOL deadline arrives
- The test strategy decision record — the test coverage gate for a refactoring is downstream of the test strategy; without one there is no shared standard for what "adequately tested" means
- The SLO and error budget decision record — service SLOs determine the remediation deadline when debt contributes to a production incident; the two decisions are coupled
- The postmortem ADR and incident decision log — incident hotfixes create deliberate deferral debt that must be logged as a registry entry with a repayment trigger at the time the fix is merged
- ADR lifecycle: superseding and deprecating decision records — the architectural baseline for technical debt reviews is the aggregate of active ADRs; the debt review cadence is coupled to the ADR maintenance cadence
- Decisions never written down — technical debt tolerance decisions as the canonical example of founding choices that accumulate invisible interest because no document ever recorded the repayment trigger
- The new CTO onboarding problem — the debt registry and its historical review records are what an incoming engineering leader needs to evaluate the codebase's current state; without them the evaluation starts from scratch
- WhyChose extractor — surfaces the original implementation sessions, feature extension decisions, and incident hotfix rationales from AI chat history as structured debt records before the next audit or velocity review makes them visible the expensive way