Manage Tech Debt
Overview
Track, categorize, and prioritize technical debt using a structured register. This is an ongoing management skill, not a one-time audit. It uses Martin Fowler's tech debt quadrant to classify debt, assigns an "interest rate" (how much the debt slows us down per sprint), estimates payoff effort, and prioritizes by impact-to-effort ratio aligned with upcoming work.
Workflow
Read existing register -- Check for an existing tech debt register at .chalk/docs/engineering/*_tech_debt_register.md. If one exists, read it and use it as the starting point. The register is a living document -- update it, do not create duplicates.
Read project context -- Read .chalk/docs/engineering/ for:
- Architecture docs to understand system boundaries
- ADRs and RFCs to understand intentional design choices (not all suboptimal code is debt)
- Prior audit reports that may have flagged tech debt
- Upcoming roadmap or sprint plans to identify strategic alignment opportunities
Determine the operation -- Based on $ARGUMENTS and conversation context:
- Add: Add new debt items to the register
- Assess: Scan the codebase for a specific area and identify debt
- Prioritize: Re-rank existing items based on current context
- Review: Show the current register with updated priorities
- Retire: Mark items as resolved and document the resolution
For new debt items -- Classify using the Tech Debt Quadrant:
|
Deliberate |
Inadvertent |
| Reckless |
"We don't have time for tests" |
"What are integration tests?" |
| Prudent |
"We'll ship now and refactor before scaling" |
"Now we know how this should have been built" |
- Reckless/Deliberate: Knowingly cut corners with no plan to address it. Highest urgency.
- Reckless/Inadvertent: Did not know better at the time. Needs education + fix.
- Prudent/Deliberate: Intentional tradeoff with a plan. Track and execute the plan.
- Prudent/Inadvertent: Learned a better approach after building. Normal and healthy.
For each debt item, capture:
- Category: Architecture, Code Quality, Testing, Infrastructure, Dependencies, Documentation, Security
- Quadrant: Which cell in the tech debt quadrant
- Description: Concrete description of what the debt is
- Location: Files, modules, or systems affected
- Impact (Interest Rate): How much this slows the team down per sprint, quantified:
- Hours of extra work per sprint caused by this debt
- Number of bugs per quarter attributable to this debt
- Developer experience friction (onboarding time, confusion, workarounds)
- Payoff Effort: Estimated effort to resolve (T-shirt size + approximate hours/days)
- Business Justification: Why fixing this matters in business terms, not just engineering terms
- Strategic Alignment: Does fixing this unblock or de-risk upcoming planned work?
Prioritize the register -- Rank items by:
- Impact/Effort ratio: High impact, low effort items go first
- Strategic alignment: Debt that blocks upcoming planned work gets a priority boost
- Coupling to upcoming work: If you are already changing the affected area, fix the debt now (lowest marginal cost)
- Risk: Debt that could cause incidents or data loss gets a priority boost regardless of effort
Write or update the register -- Save to .chalk/docs/engineering/tech_debt_register.md. If updating an existing register, preserve history (do not delete resolved items; mark them as resolved with the date).
Summarize -- Tell the user what was added/changed, the current top 5 priorities, and any items that align with upcoming work.
Filename Convention
tech_debt_register.md
A project should have exactly one tech debt register at a fixed path (e.g., .chalk/docs/engineering/tech_debt_register.md). If one already exists, update it instead of creating a new one.
Tech Debt Register Format
# Tech Debt Register
Last updated: <YYYY-MM-DD>
Total items: <active count> active, <resolved count> resolved
## Summary
### By Category
| Category | Count | Total Interest (hrs/sprint) |
|----------|-------|-----------------------------|
| Architecture | 3 | 8 |
| Code Quality | 5 | 6 |
| Testing | 2 | 4 |
| Dependencies | 1 | 2 |
### Top 5 Priorities
| # | Item | Interest Rate | Effort | Ratio | Aligned With |
|---|------|--------------|--------|-------|-------------|
| 1 | Payment retry logic | 4 hrs/sprint | 2 days | High | Q2 billing overhaul |
| 2 | Shared validation | 3 hrs/sprint | 1 day | High | API v2 migration |
| 3 | Test database setup | 2 hrs/sprint | 3 days | Medium | — |
| 4 | Legacy auth module | 3 hrs/sprint | 5 days | Medium | Auth service RFC |
| 5 | Missing indexes | 2 hrs/sprint | 0.5 day | High | — |
## Active Debt Items
### TD-001: <Title>
- **Category**: Architecture
- **Quadrant**: Prudent / Deliberate
- **Added**: <YYYY-MM-DD>
- **Location**: `src/payments/retry.ts`, `src/payments/processor.ts`
- **Description**: Payment retry logic uses a simple loop with fixed delays instead of exponential backoff with jitter. This was acceptable at low volume but causes thundering herd problems under load.
- **Impact (Interest Rate)**: ~4 hours/sprint investigating timeout-related payment failures. 2-3 support tickets per week from merchants about failed retries.
- **Payoff Effort**: M (2 days) -- replace retry loop with a proper backoff library, add circuit breaker, update tests.
- **Business Justification**: Payment reliability directly affects merchant trust and revenue. Each failed retry costs an average of $47 in lost transaction value.
- **Strategic Alignment**: Directly relevant to Q2 billing overhaul. Fixing now reduces risk for that project.
- **Priority**: 1 (High impact/effort ratio + strategic alignment)
### TD-002: <Title>
...
## Resolved Debt Items
### TD-008: <Title> [RESOLVED <YYYY-MM-DD>]
- **Resolution**: Refactored in PR #234. Replaced manual SQL with query builder.
- **Actual effort**: 1.5 days (estimated: 2 days)
- **Outcome**: Eliminated 2 hrs/sprint of debugging SQL-related issues.
Interest Rate Guidelines
The "interest rate" is the ongoing cost of not fixing the debt. Quantify it as concretely as possible:
| Interest Level |
Hours/Sprint |
Characteristics |
| Critical |
8+ hrs |
Causes incidents, blocks features, developers actively work around it every sprint |
| High |
4-8 hrs |
Regular source of bugs, significant developer friction, slows multiple features |
| Medium |
2-4 hrs |
Occasional bugs, noticeable friction, slows some features |
| Low |
0.5-2 hrs |
Minor annoyance, rarely causes issues but adds up over time |
| Negligible |
<0.5 hrs |
Aesthetic concern, not worth prioritizing unless zero-cost to fix |
If you cannot estimate the interest rate, the debt is not well-understood enough to prioritize. Investigate further before adding it to the register.
Effort Estimation
| Size |
Duration |
Characteristics |
| XS |
< 2 hours |
Single file change, localized, no risk |
| S |
0.5-1 day |
Few files, well-understood, low risk |
| M |
1-3 days |
Multiple files, needs testing, moderate risk |
| L |
3-5 days |
Cross-module changes, needs migration, high risk |
| XL |
1-2 weeks |
Architectural change, needs RFC or ADR, phased rollout |
When to Address Debt
Fix Now (do not add to register)
- Security vulnerabilities
- Data corruption risks
- Issues causing customer-visible incidents
Fix When Touching the Area
- Debt with medium interest rate in code you are already changing
- Test gaps for code you are modifying
- Stale documentation for features you are updating
Schedule Explicitly
- High interest rate items blocking planned work
- Items with high impact/effort ratio
- Debt that will get more expensive to fix over time (coupling is increasing)
Accept and Document
- Low interest rate in stable code that rarely changes
- Prudent/deliberate debt where the planned payoff timeline has not arrived
- Debt where the fix effort exceeds the projected lifetime cost
Codebase Assessment Checklist
When asked to assess a specific area for tech debt, check:
| Area |
What to Look For |
| Architecture |
Circular dependencies, god classes/modules, missing abstraction layers, tight coupling |
| Code Quality |
Code duplication (>3 instances), long functions (>50 lines), deep nesting (>3 levels), magic numbers |
| Testing |
Missing tests for critical paths, brittle tests, slow test suite, no integration tests |
| Dependencies |
Outdated packages (>2 major versions behind), packages with known CVEs, abandoned packages |
| Infrastructure |
Manual deployment steps, missing monitoring, no alerting, single points of failure |
| Documentation |
Outdated architecture docs, missing API docs, no onboarding guide, stale comments |
| Security |
Hardcoded secrets, missing input validation, outdated auth patterns, no rate limiting |
Anti-patterns
- Infinite list with no prioritization -- A tech debt register with 50 items and no ranking is a graveyard, not a management tool. Every item must have an interest rate and effort estimate. Rank by impact/effort ratio. If the list exceeds 20 active items, the bottom items should be evaluated for removal.
- No business justification -- "This code is ugly" is not a business justification. "This code causes 3 hours of debugging per sprint and has led to 2 production incidents in the last quarter" is. Every debt item must justify its existence in terms a product manager would understand.
- "Refactor everything" -- Not all old code is debt. Stable code that works, is tested, and rarely needs changes is not debt even if it uses old patterns. Debt is code that actively costs you ongoing effort. Do not confuse "not how I would write it today" with "tech debt."
- Debt without estimated interest rate -- If you cannot estimate how much a debt item costs per sprint, you do not understand it well enough to manage it. Investigate and quantify before adding it to the register. "It feels slow" is not a measurement.
- One-time cleanup events -- "Tech debt sprint" or "cleanup week" treats debt as a batch problem. Debt is continuous -- address the highest-impact items every sprint as part of regular work. Budget 15-20% of sprint capacity for debt reduction.
- Ignoring strategic alignment -- A medium-priority debt item that blocks an upcoming Q3 feature should be fixed now, not after Q3 launches. Always cross-reference the debt register with the product roadmap.
- Never resolving items -- If the register only grows and never shrinks, it loses credibility. Track resolutions, celebrate them, and measure the actual payoff vs. estimated payoff. This builds trust in the system.
- Adding debt without a decision -- Every new debt item should have an initial decision: fix now, fix when touching, schedule, or accept. Items without a decision sit in limbo and clutter the register.
1---2name: manage-tech-debt3description: Track, categorize, and prioritize technical debt when the user asks to manage tech debt, create a tech debt register, assess code quality, or plan refactoring work4---5
6# Manage Tech Debt
7
8## Overview
9
10Track, categorize, and prioritize technical debt using a structured register. This is an ongoing management skill, not a one-time audit. It uses Martin Fowler's tech debt quadrant to classify debt, assigns an "interest rate" (how much the debt slows us down per sprint), estimates payoff effort, and prioritizes by impact-to-effort ratio aligned with upcoming work.
11
12## Workflow
13
141. **Read existing register** -- Check for an existing tech debt register at `.chalk/docs/engineering/*_tech_debt_register.md`. If one exists, read it and use it as the starting point. The register is a living document -- update it, do not create duplicates.
15
162. **Read project context** -- Read `.chalk/docs/engineering/` for:
17 - Architecture docs to understand system boundaries
18 - ADRs and RFCs to understand intentional design choices (not all suboptimal code is debt)
19 - Prior audit reports that may have flagged tech debt
20 - Upcoming roadmap or sprint plans to identify strategic alignment opportunities
21
223. **Determine the operation** -- Based on `$ARGUMENTS` and conversation context:
23 - **Add**: Add new debt items to the register
24 - **Assess**: Scan the codebase for a specific area and identify debt
25 - **Prioritize**: Re-rank existing items based on current context
26 - **Review**: Show the current register with updated priorities
27 - **Retire**: Mark items as resolved and document the resolution
28
294. **For new debt items -- Classify using the Tech Debt Quadrant**:
30
31 | | Deliberate | Inadvertent |
32 |---|---|---|
33 | **Reckless** | "We don't have time for tests" | "What are integration tests?" |
34 | **Prudent** | "We'll ship now and refactor before scaling" | "Now we know how this should have been built" |
35
36 - **Reckless/Deliberate**: Knowingly cut corners with no plan to address it. Highest urgency.
37 - **Reckless/Inadvertent**: Did not know better at the time. Needs education + fix.
38 - **Prudent/Deliberate**: Intentional tradeoff with a plan. Track and execute the plan.
39 - **Prudent/Inadvertent**: Learned a better approach after building. Normal and healthy.
40
415. **For each debt item, capture**:
42 - **Category**: Architecture, Code Quality, Testing, Infrastructure, Dependencies, Documentation, Security
43 - **Quadrant**: Which cell in the tech debt quadrant
44 - **Description**: Concrete description of what the debt is
45 - **Location**: Files, modules, or systems affected
46 - **Impact (Interest Rate)**: How much this slows the team down *per sprint*, quantified:
47 - Hours of extra work per sprint caused by this debt
48 - Number of bugs per quarter attributable to this debt
49 - Developer experience friction (onboarding time, confusion, workarounds)
50 - **Payoff Effort**: Estimated effort to resolve (T-shirt size + approximate hours/days)
51 - **Business Justification**: Why fixing this matters in business terms, not just engineering terms
52 - **Strategic Alignment**: Does fixing this unblock or de-risk upcoming planned work?
53
546. **Prioritize the register** -- Rank items by:
55 - **Impact/Effort ratio**: High impact, low effort items go first
56 - **Strategic alignment**: Debt that blocks upcoming planned work gets a priority boost
57 - **Coupling to upcoming work**: If you are already changing the affected area, fix the debt now (lowest marginal cost)
58 - **Risk**: Debt that could cause incidents or data loss gets a priority boost regardless of effort
59
607. **Write or update the register** -- Save to `.chalk/docs/engineering/tech_debt_register.md`. If updating an existing register, preserve history (do not delete resolved items; mark them as resolved with the date).
61
628. **Summarize** -- Tell the user what was added/changed, the current top 5 priorities, and any items that align with upcoming work.
63
64## Filename Convention
65
66```
67tech_debt_register.md
68```
69
70A project should have exactly one tech debt register at a fixed path (e.g., `.chalk/docs/engineering/tech_debt_register.md`). If one already exists, update it instead of creating a new one.
71
72## Tech Debt Register Format
73
74```markdown
75# Tech Debt Register
76
77Last updated: <YYYY-MM-DD>
78Total items: <active count> active, <resolved count> resolved
79
80## Summary
81
82### By Category
83
84| Category | Count | Total Interest (hrs/sprint) |
85|----------|-------|-----------------------------|
86| Architecture | 3 | 8 |
87| Code Quality | 5 | 6 |
88| Testing | 2 | 4 |
89| Dependencies | 1 | 2 |
90
91### Top 5 Priorities
92
93| # | Item | Interest Rate | Effort | Ratio | Aligned With |
94|---|------|--------------|--------|-------|-------------|
95| 1 | Payment retry logic | 4 hrs/sprint | 2 days | High | Q2 billing overhaul |
96| 2 | Shared validation | 3 hrs/sprint | 1 day | High | API v2 migration |
97| 3 | Test database setup | 2 hrs/sprint | 3 days | Medium | — |
98| 4 | Legacy auth module | 3 hrs/sprint | 5 days | Medium | Auth service RFC |
99| 5 | Missing indexes | 2 hrs/sprint | 0.5 day | High | — |
100
101## Active Debt Items
102
103### TD-001: <Title>
104
105- **Category**: Architecture
106- **Quadrant**: Prudent / Deliberate
107- **Added**: <YYYY-MM-DD>
108- **Location**: `src/payments/retry.ts`, `src/payments/processor.ts`
109- **Description**: Payment retry logic uses a simple loop with fixed delays instead of exponential backoff with jitter. This was acceptable at low volume but causes thundering herd problems under load.
110- **Impact (Interest Rate)**: ~4 hours/sprint investigating timeout-related payment failures. 2-3 support tickets per week from merchants about failed retries.
111- **Payoff Effort**: M (2 days) -- replace retry loop with a proper backoff library, add circuit breaker, update tests.
112- **Business Justification**: Payment reliability directly affects merchant trust and revenue. Each failed retry costs an average of $47 in lost transaction value.
113- **Strategic Alignment**: Directly relevant to Q2 billing overhaul. Fixing now reduces risk for that project.
114- **Priority**: 1 (High impact/effort ratio + strategic alignment)
115
116### TD-002: <Title>
117
118...
119
120## Resolved Debt Items
121
122### TD-008: <Title> [RESOLVED <YYYY-MM-DD>]
123
124- **Resolution**: Refactored in PR #234. Replaced manual SQL with query builder.
125- **Actual effort**: 1.5 days (estimated: 2 days)
126- **Outcome**: Eliminated 2 hrs/sprint of debugging SQL-related issues.
127```
128
129## Interest Rate Guidelines
130
131The "interest rate" is the ongoing cost of *not* fixing the debt. Quantify it as concretely as possible:
132
133| Interest Level | Hours/Sprint | Characteristics |
134|---------------|-------------|-----------------|
135| **Critical** | 8+ hrs | Causes incidents, blocks features, developers actively work around it every sprint |
136| **High** | 4-8 hrs | Regular source of bugs, significant developer friction, slows multiple features |
137| **Medium** | 2-4 hrs | Occasional bugs, noticeable friction, slows some features |
138| **Low** | 0.5-2 hrs | Minor annoyance, rarely causes issues but adds up over time |
139| **Negligible** | <0.5 hrs | Aesthetic concern, not worth prioritizing unless zero-cost to fix |
140
141If you cannot estimate the interest rate, the debt is not well-understood enough to prioritize. Investigate further before adding it to the register.
142
143## Effort Estimation
144
145| Size | Duration | Characteristics |
146|------|----------|-----------------|
147| **XS** | < 2 hours | Single file change, localized, no risk |
148| **S** | 0.5-1 day | Few files, well-understood, low risk |
149| **M** | 1-3 days | Multiple files, needs testing, moderate risk |
150| **L** | 3-5 days | Cross-module changes, needs migration, high risk |
151| **XL** | 1-2 weeks | Architectural change, needs RFC or ADR, phased rollout |
152
153## When to Address Debt
154
155### Fix Now (do not add to register)
156- Security vulnerabilities
157- Data corruption risks
158- Issues causing customer-visible incidents
159
160### Fix When Touching the Area
161- Debt with medium interest rate in code you are already changing
162- Test gaps for code you are modifying
163- Stale documentation for features you are updating
164
165### Schedule Explicitly
166- High interest rate items blocking planned work
167- Items with high impact/effort ratio
168- Debt that will get more expensive to fix over time (coupling is increasing)
169
170### Accept and Document
171- Low interest rate in stable code that rarely changes
172- Prudent/deliberate debt where the planned payoff timeline has not arrived
173- Debt where the fix effort exceeds the projected lifetime cost
174
175## Codebase Assessment Checklist
176
177When asked to assess a specific area for tech debt, check:
178
179| Area | What to Look For |
180|------|-----------------|
181| **Architecture** | Circular dependencies, god classes/modules, missing abstraction layers, tight coupling |
182| **Code Quality** | Code duplication (>3 instances), long functions (>50 lines), deep nesting (>3 levels), magic numbers |
183| **Testing** | Missing tests for critical paths, brittle tests, slow test suite, no integration tests |
184| **Dependencies** | Outdated packages (>2 major versions behind), packages with known CVEs, abandoned packages |
185| **Infrastructure** | Manual deployment steps, missing monitoring, no alerting, single points of failure |
186| **Documentation** | Outdated architecture docs, missing API docs, no onboarding guide, stale comments |
187| **Security** | Hardcoded secrets, missing input validation, outdated auth patterns, no rate limiting |
188
189## Anti-patterns
190
191- **Infinite list with no prioritization** -- A tech debt register with 50 items and no ranking is a graveyard, not a management tool. Every item must have an interest rate and effort estimate. Rank by impact/effort ratio. If the list exceeds 20 active items, the bottom items should be evaluated for removal.
192- **No business justification** -- "This code is ugly" is not a business justification. "This code causes 3 hours of debugging per sprint and has led to 2 production incidents in the last quarter" is. Every debt item must justify its existence in terms a product manager would understand.
193- **"Refactor everything"** -- Not all old code is debt. Stable code that works, is tested, and rarely needs changes is *not* debt even if it uses old patterns. Debt is code that actively costs you ongoing effort. Do not confuse "not how I would write it today" with "tech debt."
194- **Debt without estimated interest rate** -- If you cannot estimate how much a debt item costs per sprint, you do not understand it well enough to manage it. Investigate and quantify before adding it to the register. "It feels slow" is not a measurement.
195- **One-time cleanup events** -- "Tech debt sprint" or "cleanup week" treats debt as a batch problem. Debt is continuous -- address the highest-impact items every sprint as part of regular work. Budget 15-20% of sprint capacity for debt reduction.
196- **Ignoring strategic alignment** -- A medium-priority debt item that blocks an upcoming Q3 feature should be fixed now, not after Q3 launches. Always cross-reference the debt register with the product roadmap.
197- **Never resolving items** -- If the register only grows and never shrinks, it loses credibility. Track resolutions, celebrate them, and measure the actual payoff vs. estimated payoff. This builds trust in the system.
198- **Adding debt without a decision** -- Every new debt item should have an initial decision: fix now, fix when touching, schedule, or accept. Items without a decision sit in limbo and clutter the register.