
Tech Debt Tracker
- 119 installs
- 451 repo stars
- Updated July 21, 2026
- borghei/claude-skills
Catalog, prioritize, and track technical debt items across services so teams can schedule refactors, measure debt burn-down, and prevent regressions during feature work.
About
Tech-debt-tracker helps engineering teams systematically identify, classify, prioritize, and monitor technical debt across repositories and services. It turns vague cleanup wishes into actionable backlog items with impact, cost, and ownership so refactors ship on a schedule instead of never.
- Structured debt inventory with severity and effort
- Prioritization tied to product and reliability risk
- Refactor scheduling and progress tracking
- Prevents silent debt accumulation in PRs
- Supports cross-team debt visibility
Tech Debt Tracker by the numbers
- 119 all-time installs (skills.sh)
- Ranked #421 of 1,352 Code Review & Quality skills by installs in the Skillselion catalog
- Data as of Aug 5, 2026 (Skillselion catalog sync)
npx skills add https://github.com/borghei/claude-skills --skill tech-debt-trackerAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 119 |
|---|---|
| repo stars | ★ 451 |
| Last updated | July 21, 2026 |
| Repository | borghei/claude-skills ↗ |
What it does
Catalog, prioritize, and track technical debt items across services so teams can schedule refactors, measure debt burn-down, and prevent regressions during feature work.
Files
Tech Debt Tracker
The agent identifies, scores, prioritizes, and tracks technical debt across codebases using AST parsing, cost-of-delay analysis, and trend dashboards.
Workflow
1. Scan codebase -- Run the Debt Scanner against the target repository. It uses AST parsing and pattern matching to detect debt signals across all six categories (code, architecture, test, documentation, dependency, infrastructure). 2. Score each item -- Apply the Severity Scoring Framework. Rate each item on velocity impact, quality impact, productivity impact, and business impact (1-10 each). Estimate effort (XS-XL) and risk level. 3. Calculate interest rate -- For each item, compute Interest Rate = Impact Score x Frequency of Encounter per sprint. Calculate Cost of Delay = Interest Rate x Sprints Until Fix x Team Size Multiplier. 4. Prioritize -- Plot items on the Cost-of-Delay vs Effort matrix. Assign priority: Immediate (high cost, low effort), Planned (high cost, high effort), Opportunistic (low cost, low effort), Backlog (low cost, high effort). 5. Allocate sprint capacity -- Apply the Debt-to-Feature Ratio based on current team velocity. Reserve the recommended percentage for debt work. 6. Generate reports -- Produce the Executive Dashboard (health score, trend, top risks, investment recommendation) and the Engineering Dashboard (daily new/resolved, interest rate by component, hotspots). 7. Track trends -- Compare current scan against previous baselines. Alert if debt accumulation rate exceeds paydown rate for two consecutive sprints.
Debt Classification
| Category | Key Indicators | Detection Method |
|---|---|---|
| Code | Functions > 50 lines, nesting > 4 levels, cyclomatic complexity > 10, duplicate blocks > 3 | AST parsing, complexity metrics |
| Architecture | Circular dependencies, tight coupling, missing abstraction layers, monolithic components | Dependency analysis, coupling metrics |
| Test | Coverage < 80% on critical paths, flaky tests, test suite > 10 min | Coverage reports, failure pattern analysis |
| Documentation | Missing API docs, outdated READMEs, no ADRs, stale comments | Coverage analysis, freshness checking |
| Dependency | Known CVEs, deprecated APIs, unused packages, version conflicts | Vulnerability scanning, usage analysis |
| Infrastructure | Manual deploys, missing monitoring, env inconsistencies, no DR plan | Audit checklists, config drift detection |
Severity Scoring Framework
Rate each dimension 1-10:
| Dimension | 1-2 | 5-6 | 9-10 |
|---|---|---|---|
| Velocity Impact | Negligible | Affects some features | Blocks new development |
| Quality Impact | No defect increase | Moderate defect increase | Critical reliability problems |
| Productivity Impact | No team impact | Regular complaints | Causing developer turnover |
| Business Impact | No customer impact | Moderate performance hit | Revenue-impacting issues |
Effort sizing: XS (1-4 hrs), S (1-2 days), M (3-5 days), L (1-2 weeks), XL (3+ weeks)
Interest Rate and Cost of Delay
Interest Rate = Impact Score x Frequency of Encounter (per sprint)
Cost of Delay = Interest Rate x Sprints Until Fix x Team Size Multiplier
Example:
Legacy auth module with poor error handling
Impact: 7 | Frequency: 15 encounters/sprint | Team: 8 devs
Planned fix: sprint 4 (3 sprints away)
Interest Rate = 7 x 15 = 105 points/sprint
Cost of Delay = 105 x 3 x 1.2 = 378 total cost pointsPrioritization Matrix
| Quadrant | Cost of Delay | Effort | Action |
|---|---|---|---|
| Immediate (quick wins) | High | Low | Do first |
| Planned (major initiatives) | High | High | Schedule dedicated sprints |
| Opportunistic | Low | Low | Fix when touching related code |
| Backlog | Low | High | Reconsider quarterly |
WSJF Alternative
WSJF = (Business Value + Time Criticality + Risk Reduction) / EffortEach component scored 1-10. Highest WSJF items are prioritized first.
Sprint Allocation (Debt-to-Feature Ratio)
| Team Velocity | Debt % | Feature % | Strategy |
|---|---|---|---|
| < 70% of capacity | 60% | 40% | Remove major blockers |
| 70-85% of capacity | 30% | 70% | Balanced maintenance |
| > 85% of capacity | 15% | 85% | Opportunistic only |
Sprint planning rule: Reserve 20% of sprint capacity for debt. Prioritize items with the highest interest rates. Add "debt tax" to feature estimates when working in high-debt areas.
Debt Item Data Structure
{
"id": "DEBT-2024-001",
"title": "Legacy user authentication module",
"category": "code",
"subcategory": "error_handling",
"location": "src/auth/legacy_auth.py:45-120",
"description": "Authentication error handling uses generic exceptions",
"impact": { "velocity": 7, "quality": 8, "productivity": 6, "business": 5 },
"effort": { "size": "M", "risk": "medium", "skill_required": "mid" },
"interest_rate": 105,
"cost_of_delay": 378,
"priority": "high",
"status": "identified",
"tags": ["security", "user-experience", "maintainability"]
}Status lifecycle: Identified > Analyzed > Prioritized > Planned > In Progress > Review > Done | Won't Fix
Refactoring Strategies
| Strategy | When to Use | How It Works |
|---|---|---|
| Strangler Fig | Large monoliths, high-risk migrations | Build new around old; gradually redirect traffic; remove old |
| Branch by Abstraction | Need old + new running in parallel | Create interface; implement both behind it; switch via config |
| Feature Toggles | Gradual rollout of refactored components | Add toggle at decision points; test both paths; remove old |
| Parallel Run | Critical business logic changes | Run both implementations; compare outputs; build confidence |
Executive Dashboard
TECH DEBT HEALTH
Overall Score: [0-100] | Trend: [improving/declining]
Cost of Delayed Fixes: [X development days]
High-Risk Items: [count]
MONTHLY REPORT:
1. Executive Summary (3 bullet points)
2. Health Score Trend (6-month view)
3. Top 3 Risk Items (business impact focus)
4. Investment Recommendation (resource allocation)
5. Success Stories (debt resolved last month)Engineering Dashboard
DAILY:
New items identified | Items resolved | Interest rate by component
SPRINT REVIEW:
Debt points completed vs planned | Velocity impact
Newly discovered debt | Team code quality sentimentExample: Scanning a Python Microservice
# Run debt scanner
python scripts/debt_scanner.py --repo ./payment-service --output debt_inventory.json
# Output summary:
# Total items found: 47
# Critical: 3 | High: 8 | Medium: 21 | Low: 15
#
# Top 3 by cost-of-delay:
# 1. DEBT-001: payment_processor.py - nested exception handling (CoD: 420)
# 2. DEBT-002: db/migrations/ - 12 unapplied migrations (CoD: 315)
# 3. DEBT-003: tests/ - 62% coverage on payment flow (CoD: 280)
# Prioritize items
python scripts/debt_prioritizer.py --inventory debt_inventory.json --sprint-capacity 40
# Generate executive report
python scripts/debt_dashboard.py --inventory debt_inventory.json --baseline previous_scan.jsonQuarterly Planning
1. Identify 1-2 major debt themes per quarter 2. Allocate dedicated sprints for large-scale refactoring 3. Plan debt work around major feature releases 4. Track: debt interest rate reduction, velocity improvements, defect rate reduction, code review cycle time
Scripts
Debt Scanner (debt_scanner.py)
Scans codebase using AST parsing and pattern matching. Detects all six debt categories. Outputs structured JSON inventory.
Debt Prioritizer (debt_prioritizer.py)
Analyses debt inventory using cost-of-delay and WSJF frameworks. Outputs prioritized backlog with sprint allocation recommendations.
Debt Dashboard (debt_dashboard.py)
Generates trend reports comparing current scan against baselines. Produces executive and engineering dashboard views.
References
See REFERENCE.md for the complete Technical Debt Quadrant (Fowler), detailed detection heuristics per category, and implementation roadmap phases.
Troubleshooting
| Problem | Cause | Solution |
|---|---|---|
| Scanner finds zero debt items | Target directory contains no recognized file extensions, or all files match ignore patterns | Verify the directory path is correct and contains source files. Check --config to ensure file_extensions and ignore_patterns are appropriate for your stack. |
| AST parsing errors on valid Python files | Files use syntax from a newer Python version than the runtime executing the scanner | Run the scanner with the same Python version the target codebase requires (e.g., python3.12 scripts/debt_scanner.py). |
| Duplicate code detection is slow on large repos | The scanner hashes every N-line sliding window across all files, which scales quadratically with file count | Reduce scope by scanning one service directory at a time, or increase min_duplicate_lines in the config to reduce candidate blocks. |
| Prioritizer produces all-zero cost-of-delay scores | Input inventory lacks severity or type fields that the enrichment step depends on | Ensure the inventory JSON was produced by debt_scanner.py or follows the Debt Item Data Structure documented above. Manual inventories must include type and severity per item. |
| Dashboard shows "No valid data files loaded" | Files passed as arguments are not valid JSON, or the JSON structure is unrecognized | The dashboard accepts scanner output (debt_items key), prioritizer output (prioritized_backlog key), or a raw JSON array of debt items. Validate file contents with python -m json.tool <file>. |
| Health score is unexpectedly low despite few critical items | High debt density (items per file) dominates the health formula even when individual severities are low | Review the density contribution: health penalizes 10 points per item-per-file. Break large files into smaller modules or resolve low-severity bulk items like todo_comment and missing_docstring. |
| Sprint allocation plan shows hundreds of sprints | Default debt capacity is 20% of --sprint-capacity, which may be too low for a large backlog | Increase --sprint-capacity to reflect actual team hours, or filter the inventory to high-priority items before running the prioritizer. |
Success Criteria
- Scan completes in under 60 seconds for repositories up to 100,000 lines of code.
- Every detected debt item includes a unique ID, file path, line number (where applicable), severity, and debt type -- no fields left as null or unknown.
- Health score correlates with manual code review assessments within 15 points on the 0-100 scale when validated against a senior engineer's judgment.
- Prioritized backlog produces a clear top-10 list where the first item has at least 2x the priority score of the tenth item, confirming meaningful differentiation.
- Sprint allocation recommendations fit within the configured capacity (no single sprint exceeds 100% of debt budget) and cover all high-priority items within the first 3 sprints.
- Dashboard trend analysis correctly identifies improving, declining, or stable directions when compared against at least 3 historical snapshots with known trajectories.
- Cost-of-delay calculations produce actionable dollar-equivalent values that engineering managers can use directly in sprint planning and quarterly roadmap discussions.
Scope & Limitations
This skill covers:
- Static detection of code-level, architecture, test, documentation, dependency, and infrastructure debt via AST parsing (Python) and regex pattern matching (all languages).
- Quantitative prioritization of debt items using cost-of-delay, WSJF, and RICE frameworks with configurable team size and sprint capacity.
- Historical trend analysis, health scoring, debt velocity tracking, and executive/engineering dashboard generation from multiple scan snapshots.
- Sprint allocation planning with capacity-aware backlog scheduling and effort estimation by debt type.
This skill does NOT cover:
- Runtime performance profiling or production monitoring -- see
engineering/performance-profilerandengineering/observability-designerfor those concerns. - Dependency vulnerability scanning (CVE detection) or software composition analysis -- see
engineering/dependency-auditorfor security-focused dependency review. - Automated refactoring or code transformation -- the skill identifies and prioritizes debt but does not modify source code.
- Database schema debt, API contract drift, or infrastructure-as-code drift detection -- see
engineering/database-schema-designer,engineering/api-design-reviewer, andengineering/migration-architectfor those domains.
Integration Points
| Skill | Integration | Data Flow |
|---|---|---|
engineering/dependency-auditor | Feed dependency audit findings into the scanner as dependency_debt items to unify all debt in one inventory. | Dependency audit JSON -> scanner config or manual merge into debt_inventory.json |
engineering/performance-profiler | Correlate performance hotspots with high-complexity debt items to prioritize refactoring that yields both quality and speed gains. | Profiler hotspot report -> cross-reference with scanner output by file path |
engineering/ci-cd-pipeline-builder | Add debt_scanner.py as a CI pipeline step to fail builds when health score drops below a threshold or critical debt count increases. | Scanner JSON output -> CI gate condition on summary.health_score |
engineering/pr-review-expert | Surface relevant debt items during code review by querying the debt inventory for files touched in a pull request. | PR changed-files list -> filter debt_inventory.json by file_path |
engineering/observability-designer | Map infrastructure debt items (missing monitoring, env inconsistencies) to observability gaps identified by the observability skill. | Dashboard category_distribution -> observability gap analysis |
engineering/migration-architect | Use the prioritized backlog to scope and sequence large-scale migration efforts, especially for architecture-category debt rated as planned initiatives. | Prioritizer sprint_allocation -> migration planning timeline |
Tool Reference
Debt Scanner (scripts/debt_scanner.py)
Purpose: Scans a codebase directory for technical debt signals using AST parsing (Python files) and regex pattern matching (all languages). Detects code smells, large functions, high complexity, duplicate code, TODO comments, and common anti-patterns. Produces a structured JSON inventory and a human-readable text report.
Usage:
python scripts/debt_scanner.py <directory> [options]Parameters:
| Flag | Type | Default | Description |
|---|---|---|---|
directory | positional, required | -- | Path to the directory to scan. |
--config | string | None | Path to a JSON configuration file that overrides default thresholds (e.g., max_function_length, max_complexity, ignore_patterns). |
--output | string | None | Output file path. When set, writes report to file instead of stdout. JSON output appends .json, text output appends .txt. |
--format | choice | both | Output format: json, text, or both. |
Example:
python scripts/debt_scanner.py ./src --config custom_thresholds.json --output scan_results --format bothOutput Formats:
- JSON: Contains
scan_metadata,summary(files scanned, lines scanned, health score, debt density, priority/type breakdowns),debt_items(array of debt objects with id, type, description, file_path, severity, metadata, priority_score, priority),file_statistics, andrecommendations. - Text: Human-readable report with header, summary statistics, priority breakdown, top 10 debt items, and numbered recommendations.
---
Debt Prioritizer (scripts/debt_prioritizer.py)
Purpose: Takes a debt inventory (from the scanner or a manual JSON file) and enriches each item with effort estimates, business impact scores, interest rate calculations, and cost-of-delay values. Produces a prioritized backlog with sprint allocation recommendations using one of three frameworks: cost-of-delay, WSJF, or RICE.
Usage:
python scripts/debt_prioritizer.py <inventory_file> [options]Parameters:
| Flag | Type | Default | Description |
|---|---|---|---|
inventory_file | positional, required | -- | Path to debt inventory JSON file (scanner output, prioritizer output, or raw array of debt items). |
--output | string | None | Output file path. JSON output appends .json, text output appends .txt. |
--format | choice | both | Output format: json, text, or both. |
--framework | choice | cost_of_delay | Prioritization framework: cost_of_delay, wsjf, or rice. |
--team-size | integer | 5 | Number of developers on the team. Affects interest rate team impact multiplier and RICE reach calculation. |
--sprint-capacity | integer | 80 | Total sprint capacity in hours. 20% is allocated to debt work by default. Used for sprint allocation planning. |
Example:
python scripts/debt_prioritizer.py scan_results.json --framework wsjf --team-size 8 --sprint-capacity 120 --output prioritized --format jsonOutput Formats:
- JSON: Contains
metadata(analysis date, framework, team size, sprint capacity),prioritized_backlog(enriched items sorted by priority score, each witheffort_estimate,business_impact,interest_rate,cost_of_delay,category,impact_tags),sprint_allocation(total debt hours, capacity per sprint, sprint plan with item assignments),insights(category distribution, effort breakdown, quick wins count, cost totals),charts_data(scatter, pie, timeline, interest trend arrays), andrecommendations. - Text: Executive summary with total effort and cost-of-delay, sprint allocation plan (first 3 sprints with top items), top 10 priority items with scores and tags, and numbered recommendations.
---
Debt Dashboard (scripts/debt_dashboard.py)
Purpose: Takes one or more historical debt inventory files (from the scanner or prioritizer) and generates trend analysis, debt velocity tracking (accruing vs. paying down), health score timelines, forecasts, and an executive summary. Supports loading files individually or from a directory.
Usage:
python scripts/debt_dashboard.py [files...] [options]Parameters:
| Flag | Type | Default | Description |
|---|---|---|---|
files | positional, optional | -- | One or more debt inventory JSON file paths. Accepts scanner output, prioritizer output, or raw arrays. |
--input-dir | string | None | Directory containing debt inventory JSON files. All *.json files in the directory are loaded. Mutually exclusive usage with positional files. |
--output | string | None | Output file path. JSON output appends .json, text output appends .txt. |
--format | choice | both | Output format: json, text, or both. |
--period | choice | monthly | Analysis period for trend grouping: weekly, monthly, or quarterly. |
--team-size | integer | 5 | Number of developers on the team. Used for velocity impact estimation. |
Example:
python scripts/debt_dashboard.py --input-dir ./debt_scans/ --period quarterly --team-size 10 --output dashboard --format bothOutput Formats:
- JSON: Contains
metadata(generated date, period, snapshot count, date range, team size),executive_summary(overall status, health score, status message, key insights, total debt items, effort hours, high priority count, velocity impact percent),current_health(overall score, debt density, velocity impact, quality score, maintainability score, technical risk score),trend_analysis(per-metric trend direction, change rate, correlation strength, forecast, confidence interval),debt_velocity(per-period new/resolved items, net change, velocity ratio, effort hours added/resolved),forecasts(3-month and 6-month projections for health, debt count, risk),recommendations(prioritized strategic actions with category, impact, effort),visualizations(health timeline, debt accumulation, category distribution, velocity chart, effort trend arrays), anddetailed_metrics. - Text: Executive summary with status and key metrics, current health metrics, trend analysis with directional indicators, and top 5 strategic recommendations with priority, impact, and effort ratings.
{
"scan_metadata": {
"directory": "/project/src",
"scan_date": "2024-01-15T09:00:00",
"scanner_version": "1.0.0"
},
"summary": {
"total_files_scanned": 25,
"total_lines_scanned": 12543,
"total_debt_items": 28,
"health_score": 68.5,
"debt_density": 1.12
},
"debt_items": [
{
"id": "DEBT-0001",
"type": "large_function",
"description": "create_user function in user_service.py is 89 lines long",
"file_path": "src/user_service.py",
"severity": "high",
"detected_date": "2024-01-15T09:00:00",
"status": "identified"
},
{
"id": "DEBT-0002",
"type": "duplicate_code",
"description": "Password validation logic duplicated in 3 locations",
"file_path": "src/user_service.py",
"severity": "medium",
"detected_date": "2024-01-15T09:00:00",
"status": "identified"
},
{
"id": "DEBT-0003",
"type": "security_risk",
"description": "Hardcoded API key in payment_processor.py",
"file_path": "src/payment_processor.py",
"severity": "critical",
"detected_date": "2024-01-15T09:00:00",
"status": "identified"
},
{
"id": "DEBT-0004",
"type": "high_complexity",
"description": "process_payment function has cyclomatic complexity of 24",
"file_path": "src/payment_processor.py",
"severity": "high",
"detected_date": "2024-01-15T09:00:00",
"status": "identified"
},
{
"id": "DEBT-0005",
"type": "missing_docstring",
"description": "PaymentProcessor class missing docstring",
"file_path": "src/payment_processor.py",
"severity": "low",
"detected_date": "2024-01-15T09:00:00",
"status": "identified"
},
{
"id": "DEBT-0006",
"type": "todo_comment",
"description": "TODO: Move this to configuration file",
"file_path": "src/user_service.py",
"severity": "low",
"detected_date": "2024-01-15T09:00:00",
"status": "identified"
},
{
"id": "DEBT-0007",
"type": "empty_catch_blocks",
"description": "Empty catch block in update_user method",
"file_path": "src/user_service.py",
"severity": "medium",
"detected_date": "2024-01-15T09:00:00",
"status": "identified"
},
{
"id": "DEBT-0008",
"type": "magic_numbers",
"description": "Magic number 1800 used for lock timeout",
"file_path": "src/user_service.py",
"severity": "low",
"detected_date": "2024-01-15T09:00:00",
"status": "identified"
},
{
"id": "DEBT-0009",
"type": "deep_nesting",
"description": "Deep nesting detected: 6 levels in preferences handling",
"file_path": "src/frontend.js",
"severity": "medium",
"detected_date": "2024-01-15T09:00:00",
"status": "identified"
},
{
"id": "DEBT-0010",
"type": "long_line",
"description": "Line too long: 156 characters",
"file_path": "src/frontend.js",
"severity": "low",
"detected_date": "2024-01-15T09:00:00",
"status": "identified"
},
{
"id": "DEBT-0011",
"type": "commented_code",
"description": "Dead code left in comments",
"file_path": "src/frontend.js",
"severity": "low",
"detected_date": "2024-01-15T09:00:00",
"status": "identified"
},
{
"id": "DEBT-0012",
"type": "global_variables",
"description": "Global variable userCache should be encapsulated",
"file_path": "src/frontend.js",
"severity": "medium",
"detected_date": "2024-01-15T09:00:00",
"status": "identified"
},
{
"id": "DEBT-0013",
"type": "synchronous_ajax",
"description": "Synchronous AJAX call blocks UI thread",
"file_path": "src/frontend.js",
"severity": "high",
"detected_date": "2024-01-15T09:00:00",
"status": "identified"
},
{
"id": "DEBT-0014",
"type": "hardcoded_values",
"description": "Tax rates hardcoded in payment processing logic",
"file_path": "src/payment_processor.py",
"severity": "medium",
"detected_date": "2024-01-15T09:00:00",
"status": "identified"
},
{
"id": "DEBT-0015",
"type": "no_error_handling",
"description": "API calls without proper error handling",
"file_path": "src/payment_processor.py",
"severity": "high",
"detected_date": "2024-01-15T09:00:00",
"status": "identified"
},
{
"id": "DEBT-0016",
"type": "inefficient_algorithm",
"description": "O(n) user search could be optimized with indexing",
"file_path": "src/user_service.py",
"severity": "medium",
"detected_date": "2024-01-15T09:00:00",
"status": "identified"
},
{
"id": "DEBT-0017",
"type": "memory_leak_risk",
"description": "Event listeners attached without cleanup",
"file_path": "src/frontend.js",
"severity": "medium",
"detected_date": "2024-01-15T09:00:00",
"status": "identified"
},
{
"id": "DEBT-0018",
"type": "sql_injection_risk",
"description": "Potential SQL injection in user query",
"file_path": "src/database.py",
"severity": "critical",
"detected_date": "2024-01-15T09:00:00",
"status": "identified"
},
{
"id": "DEBT-0019",
"type": "outdated_dependency",
"description": "jQuery version 2.1.4 has known security vulnerabilities",
"file_path": "package.json",
"severity": "high",
"detected_date": "2024-01-15T09:00:00",
"status": "identified"
},
{
"id": "DEBT-0020",
"type": "test_debt",
"description": "No unit tests for critical payment processing logic",
"file_path": "src/payment_processor.py",
"severity": "high",
"detected_date": "2024-01-15T09:00:00",
"status": "identified"
},
{
"id": "DEBT-0021",
"type": "large_class",
"description": "UserService class has 15 methods",
"file_path": "src/user_service.py",
"severity": "medium",
"detected_date": "2024-01-15T09:00:00",
"status": "identified"
},
{
"id": "DEBT-0022",
"type": "unused_imports",
"description": "Unused import: sys",
"file_path": "src/utils.py",
"severity": "low",
"detected_date": "2024-01-15T09:00:00",
"status": "identified"
},
{
"id": "DEBT-0023",
"type": "missing_type_hints",
"description": "Function get_user_score missing type hints",
"file_path": "src/user_service.py",
"severity": "low",
"detected_date": "2024-01-15T09:00:00",
"status": "identified"
},
{
"id": "DEBT-0024",
"type": "circular_dependency",
"description": "Circular import between user_service and auth_service",
"file_path": "src/user_service.py",
"severity": "high",
"detected_date": "2024-01-15T09:00:00",
"status": "identified"
},
{
"id": "DEBT-0025",
"type": "inconsistent_naming",
"description": "Variable name userID should be user_id",
"file_path": "src/auth.py",
"severity": "low",
"detected_date": "2024-01-15T09:00:00",
"status": "identified"
},
{
"id": "DEBT-0026",
"type": "broad_exception",
"description": "Catching generic Exception instead of specific types",
"file_path": "src/database.py",
"severity": "medium",
"detected_date": "2024-01-15T09:00:00",
"status": "identified"
},
{
"id": "DEBT-0027",
"type": "deprecated_api",
"description": "Using deprecated datetime.utcnow() method",
"file_path": "src/utils.py",
"severity": "low",
"detected_date": "2024-01-15T09:00:00",
"status": "identified"
},
{
"id": "DEBT-0028",
"type": "logging_issue",
"description": "Using print() instead of proper logging",
"file_path": "src/payment_processor.py",
"severity": "low",
"detected_date": "2024-01-15T09:00:00",
"status": "identified"
}
]
}{
"scan_metadata": {
"directory": "/project/src",
"scan_date": "2024-02-01T14:30:00",
"scanner_version": "1.0.0"
},
"summary": {
"total_files_scanned": 27,
"total_lines_scanned": 13421,
"total_debt_items": 22,
"health_score": 74.2,
"debt_density": 0.81
},
"debt_items": [
{
"id": "DEBT-0001",
"type": "large_function",
"description": "create_user function in user_service.py is 89 lines long",
"file_path": "src/user_service.py",
"severity": "high",
"detected_date": "2024-01-15T09:00:00",
"status": "identified"
},
{
"id": "DEBT-0002",
"type": "duplicate_code",
"description": "Password validation logic duplicated in 3 locations",
"file_path": "src/user_service.py",
"severity": "medium",
"detected_date": "2024-01-15T09:00:00",
"status": "identified"
},
{
"id": "DEBT-0004",
"type": "high_complexity",
"description": "process_payment function has cyclomatic complexity of 24",
"file_path": "src/payment_processor.py",
"severity": "high",
"detected_date": "2024-01-15T09:00:00",
"status": "identified"
},
{
"id": "DEBT-0005",
"type": "missing_docstring",
"description": "PaymentProcessor class missing docstring",
"file_path": "src/payment_processor.py",
"severity": "low",
"detected_date": "2024-01-15T09:00:00",
"status": "identified"
},
{
"id": "DEBT-0007",
"type": "empty_catch_blocks",
"description": "Empty catch block in update_user method",
"file_path": "src/user_service.py",
"severity": "medium",
"detected_date": "2024-01-15T09:00:00",
"status": "identified"
},
{
"id": "DEBT-0009",
"type": "deep_nesting",
"description": "Deep nesting detected: 6 levels in preferences handling",
"file_path": "src/frontend.js",
"severity": "medium",
"detected_date": "2024-01-15T09:00:00",
"status": "identified"
},
{
"id": "DEBT-0010",
"type": "long_line",
"description": "Line too long: 156 characters",
"file_path": "src/frontend.js",
"severity": "low",
"detected_date": "2024-01-15T09:00:00",
"status": "identified"
},
{
"id": "DEBT-0011",
"type": "commented_code",
"description": "Dead code left in comments",
"file_path": "src/frontend.js",
"severity": "low",
"detected_date": "2024-01-15T09:00:00",
"status": "identified"
},
{
"id": "DEBT-0012",
"type": "global_variables",
"description": "Global variable userCache should be encapsulated",
"file_path": "src/frontend.js",
"severity": "medium",
"detected_date": "2024-01-15T09:00:00",
"status": "identified"
},
{
"id": "DEBT-0013",
"type": "synchronous_ajax",
"description": "Synchronous AJAX call blocks UI thread",
"file_path": "src/frontend.js",
"severity": "high",
"detected_date": "2024-01-15T09:00:00",
"status": "identified"
},
{
"id": "DEBT-0014",
"type": "hardcoded_values",
"description": "Tax rates hardcoded in payment processing logic",
"file_path": "src/payment_processor.py",
"severity": "medium",
"detected_date": "2024-01-15T09:00:00",
"status": "identified"
},
{
"id": "DEBT-0015",
"type": "no_error_handling",
"description": "API calls without proper error handling",
"file_path": "src/payment_processor.py",
"severity": "high",
"detected_date": "2024-01-15T09:00:00",
"status": "identified"
},
{
"id": "DEBT-0016",
"type": "inefficient_algorithm",
"description": "O(n) user search could be optimized with indexing",
"file_path": "src/user_service.py",
"severity": "medium",
"detected_date": "2024-01-15T09:00:00",
"status": "identified"
},
{
"id": "DEBT-0017",
"type": "memory_leak_risk",
"description": "Event listeners attached without cleanup",
"file_path": "src/frontend.js",
"severity": "medium",
"detected_date": "2024-01-15T09:00:00",
"status": "identified"
},
{
"id": "DEBT-0021",
"type": "large_class",
"description": "UserService class has 15 methods",
"file_path": "src/user_service.py",
"severity": "medium",
"detected_date": "2024-01-15T09:00:00",
"status": "identified"
},
{
"id": "DEBT-0024",
"type": "circular_dependency",
"description": "Circular import between user_service and auth_service",
"file_path": "src/user_service.py",
"severity": "high",
"detected_date": "2024-01-15T09:00:00",
"status": "identified"
},
{
"id": "DEBT-0026",
"type": "broad_exception",
"description": "Catching generic Exception instead of specific types",
"file_path": "src/database.py",
"severity": "medium",
"detected_date": "2024-01-15T09:00:00",
"status": "identified"
},
{
"id": "DEBT-0029",
"type": "missing_validation",
"description": "New API endpoint missing input validation",
"file_path": "src/api.py",
"severity": "high",
"detected_date": "2024-02-01T14:30:00",
"status": "identified"
},
{
"id": "DEBT-0030",
"type": "performance_issue",
"description": "N+1 query detected in user listing",
"file_path": "src/user_service.py",
"severity": "medium",
"detected_date": "2024-02-01T14:30:00",
"status": "identified"
},
{
"id": "DEBT-0031",
"type": "css_debt",
"description": "Inline styles should be moved to CSS files",
"file_path": "templates/user_profile.html",
"severity": "low",
"detected_date": "2024-02-01T14:30:00",
"status": "identified"
},
{
"id": "DEBT-0032",
"type": "accessibility_issue",
"description": "Missing alt text for images",
"file_path": "templates/dashboard.html",
"severity": "medium",
"detected_date": "2024-02-01T14:30:00",
"status": "identified"
},
{
"id": "DEBT-0033",
"type": "configuration_debt",
"description": "Environment-specific config hardcoded in application",
"file_path": "src/config.py",
"severity": "medium",
"detected_date": "2024-02-01T14:30:00",
"status": "identified"
}
]
}// Frontend JavaScript with various technical debt examples
// TODO: Move configuration to separate file
const API_BASE_URL = "https://api.example.com";
const API_KEY = "abc123def456"; // FIXME: Should be in environment
// Global variables - should be encapsulated
var userCache = {};
var authToken = null;
var currentUser = null;
// HACK: Polyfill for older browsers - should use proper build system
if (!String.prototype.includes) {
String.prototype.includes = function(search) {
return this.indexOf(search) !== -1;
};
}
class UserInterface {
constructor() {
this.components = {};
this.eventHandlers = [];
// Long parameter list in constructor
this.init(document, window, localStorage, sessionStorage, navigator, history, location);
}
// Function with too many parameters
init(doc, win, localStorage, sessionStorage, nav, hist, loc) {
this.document = doc;
this.window = win;
this.localStorage = localStorage;
this.sessionStorage = sessionStorage;
this.navigator = nav;
this.history = hist;
this.location = loc;
// Deep nesting example
if (this.localStorage) {
if (this.localStorage.getItem('user')) {
if (JSON.parse(this.localStorage.getItem('user'))) {
if (JSON.parse(this.localStorage.getItem('user')).preferences) {
if (JSON.parse(this.localStorage.getItem('user')).preferences.theme) {
if (JSON.parse(this.localStorage.getItem('user')).preferences.theme === 'dark') {
document.body.classList.add('dark-theme');
} else if (JSON.parse(this.localStorage.getItem('user')).preferences.theme === 'light') {
document.body.classList.add('light-theme');
} else {
document.body.classList.add('default-theme');
}
}
}
}
}
}
}
// Large function that does too many things
renderUserDashboard(userId, includeStats, includeRecent, includeNotifications, includeSettings, includeHelp) {
let user = this.getUser(userId);
if (!user) {
console.log("User not found"); // Should use proper logging
return;
}
let html = '<div class="dashboard">';
// Inline HTML generation - should use templates
html += '<header class="dashboard-header">';
html += '<h1>Welcome, ' + user.name + '</h1>';
html += '<div class="user-avatar">';
html += '<img src="' + user.avatar + '" alt="Avatar" />';
html += '</div>';
html += '</header>';
// Repeated validation pattern
if (includeStats && includeStats === true) {
html += '<section class="stats">';
html += '<h2>Your Statistics</h2>';
// Magic numbers everywhere
if (user.loginCount > 100) {
html += '<div class="stat-item">Frequent User (100+ logins)</div>';
} else if (user.loginCount > 50) {
html += '<div class="stat-item">Regular User (50+ logins)</div>';
} else if (user.loginCount > 10) {
html += '<div class="stat-item">Casual User (10+ logins)</div>';
} else {
html += '<div class="stat-item">New User</div>';
}
html += '</section>';
}
if (includeRecent && includeRecent === true) {
html += '<section class="recent">';
html += '<h2>Recent Activity</h2>';
// No error handling for API calls
let recentActivity = this.fetchRecentActivity(userId);
if (recentActivity && recentActivity.length > 0) {
html += '<ul class="activity-list">';
for (let i = 0; i < recentActivity.length; i++) {
let activity = recentActivity[i];
html += '<li class="activity-item">';
html += '<span class="activity-type">' + activity.type + '</span>';
html += '<span class="activity-description">' + activity.description + '</span>';
html += '<span class="activity-time">' + this.formatTime(activity.timestamp) + '</span>';
html += '</li>';
}
html += '</ul>';
} else {
html += '<p>No recent activity</p>';
}
html += '</section>';
}
if (includeNotifications && includeNotifications === true) {
html += '<section class="notifications">';
html += '<h2>Notifications</h2>';
let notifications = this.getNotifications(userId);
// Duplicate HTML generation pattern
if (notifications && notifications.length > 0) {
html += '<ul class="notification-list">';
for (let i = 0; i < notifications.length; i++) {
let notification = notifications[i];
html += '<li class="notification-item">';
html += '<span class="notification-title">' + notification.title + '</span>';
html += '<span class="notification-message">' + notification.message + '</span>';
html += '<span class="notification-time">' + this.formatTime(notification.timestamp) + '</span>';
html += '</li>';
}
html += '</ul>';
} else {
html += '<p>No notifications</p>';
}
html += '</section>';
}
html += '</div>';
// Direct DOM manipulation without cleanup
document.getElementById('main-content').innerHTML = html;
// Event handler attachment without cleanup
let buttons = document.querySelectorAll('.action-button');
for (let i = 0; i < buttons.length; i++) {
buttons[i].addEventListener('click', function(event) {
// Nested event handlers - memory leak risk
let buttonType = event.target.getAttribute('data-type');
if (buttonType === 'edit') {
// Inline event handling - should be separate methods
let modal = document.createElement('div');
modal.className = 'modal';
modal.innerHTML = '<div class="modal-content"><h3>Edit Profile</h3><button onclick="closeModal()">Close</button></div>';
document.body.appendChild(modal);
} else if (buttonType === 'delete') {
if (confirm('Are you sure?')) { // Using confirm - poor UX
// No error handling
fetch(API_BASE_URL + '/users/' + userId, {
method: 'DELETE',
headers: {'Authorization': 'Bearer ' + authToken}
});
}
} else if (buttonType === 'share') {
// Hardcoded share logic
if (navigator.share) {
navigator.share({
title: 'Check out my profile',
url: window.location.href
});
} else {
// Fallback for browsers without Web Share API
let shareUrl = 'https://twitter.com/intent/tweet?url=' + encodeURIComponent(window.location.href);
window.open(shareUrl, '_blank');
}
}
});
}
}
// Duplicate code - similar to above but for admin dashboard
renderAdminDashboard(adminId) {
let admin = this.getUser(adminId);
if (!admin) {
console.log("Admin not found");
return;
}
let html = '<div class="admin-dashboard">';
html += '<header class="dashboard-header">';
html += '<h1>Admin Panel - Welcome, ' + admin.name + '</h1>';
html += '<div class="user-avatar">';
html += '<img src="' + admin.avatar + '" alt="Avatar" />';
html += '</div>';
html += '</header>';
// Same pattern repeated
html += '<section class="admin-stats">';
html += '<h2>System Statistics</h2>';
let stats = this.getSystemStats();
if (stats) {
html += '<div class="stat-grid">';
html += '<div class="stat-item">Total Users: ' + stats.totalUsers + '</div>';
html += '<div class="stat-item">Active Users: ' + stats.activeUsers + '</div>';
html += '<div class="stat-item">New Today: ' + stats.newToday + '</div>';
html += '</div>';
}
html += '</section>';
html += '</div>';
document.getElementById('main-content').innerHTML = html;
}
getUser(userId) {
// Check cache first - but cache never expires
if (userCache[userId]) {
return userCache[userId];
}
// Synchronous AJAX - blocks UI
let xhr = new XMLHttpRequest();
xhr.open('GET', API_BASE_URL + '/users/' + userId, false);
xhr.setRequestHeader('Authorization', 'Bearer ' + authToken);
xhr.send();
if (xhr.status === 200) {
let user = JSON.parse(xhr.responseText);
userCache[userId] = user;
return user;
} else {
// Generic error handling
console.error('Failed to fetch user');
return null;
}
}
fetchRecentActivity(userId) {
// Another synchronous call
try {
let xhr = new XMLHttpRequest();
xhr.open('GET', API_BASE_URL + '/users/' + userId + '/activity', false);
xhr.setRequestHeader('Authorization', 'Bearer ' + authToken);
xhr.send();
if (xhr.status === 200) {
return JSON.parse(xhr.responseText);
} else {
return [];
}
} catch (error) {
// Swallowing errors
return [];
}
}
getNotifications(userId) {
// Yet another sync call - should be async
let xhr = new XMLHttpRequest();
xhr.open('GET', API_BASE_URL + '/users/' + userId + '/notifications', false);
xhr.setRequestHeader('Authorization', 'Bearer ' + authToken);
xhr.send();
if (xhr.status === 200) {
return JSON.parse(xhr.responseText);
} else {
return [];
}
}
formatTime(timestamp) {
// Basic time formatting - should use proper library
let date = new Date(timestamp);
return date.getMonth() + '/' + date.getDate() + '/' + date.getFullYear();
}
// XXX: This method is never used
formatCurrency(amount, currency) {
if (currency === 'USD') {
return '$' + amount.toFixed(2);
} else if (currency === 'EUR') {
return '€' + amount.toFixed(2);
} else {
return amount.toFixed(2) + ' ' + currency;
}
}
getSystemStats() {
// Hardcoded test data - should come from API
return {
totalUsers: 12534,
activeUsers: 8765,
newToday: 23
};
}
}
// Global functions - should be methods or modules
function closeModal() {
// Assumes modal exists - no error checking
document.querySelector('.modal').remove();
}
function validateEmail(email) {
// Regex without explanation - magic pattern
return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email);
}
function validatePassword(password) {
// Duplicate validation logic from backend
if (password.length < 8) return false;
if (!/[A-Z]/.test(password)) return false;
if (!/[a-z]/.test(password)) return false;
if (!/\d/.test(password)) return false;
return true;
}
// jQuery-style utility - reinventing the wheel
function $(selector) {
return document.querySelector(selector);
}
function $all(selector) {
return document.querySelectorAll(selector);
}
// Global event handlers - should be encapsulated
document.addEventListener('DOMContentLoaded', function() {
// Inline anonymous function
let ui = new UserInterface();
// Event delegation would be better
document.body.addEventListener('click', function(event) {
if (event.target.classList.contains('login-button')) {
// Inline login logic
let username = $('#username').value;
let password = $('#password').value;
if (!username || !password) {
alert('Please enter username and password'); // Poor UX
return;
}
// No CSRF protection
fetch(API_BASE_URL + '/auth/login', {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({username: username, password: password})
})
.then(response => response.json())
.then(data => {
if (data.success) {
authToken = data.token;
currentUser = data.user;
localStorage.setItem('authToken', authToken); // Storing sensitive data
localStorage.setItem('currentUser', JSON.stringify(currentUser));
window.location.reload(); // Poor navigation
} else {
alert('Login failed: ' + data.error);
}
})
.catch(error => {
console.error('Login error:', error);
alert('Login failed');
});
}
});
});
// // Old code left as comments - should be removed
// function oldRenderFunction() {
// var html = '<div>Old implementation</div>';
// document.body.innerHTML = html;
// }
// Commented out feature - should be removed or implemented
// function darkModeToggle() {
// if (document.body.classList.contains('dark-theme')) {
// document.body.classList.remove('dark-theme');
// document.body.classList.add('light-theme');
// } else {
// document.body.classList.remove('light-theme');
// document.body.classList.add('dark-theme');
// }
// }"""
Payment processing module - contains various technical debt examples
"""
import json
import time
import requests
from decimal import Decimal
from typing import Dict, Any
class PaymentProcessor:
def __init__(self):
# TODO: These should come from environment or config
self.stripe_key = "sk_test_1234567890"
self.paypal_key = "paypal_secret_key_here"
self.square_key = "square_api_key"
def process_payment(self, amount, currency, payment_method, customer_data, billing_address, shipping_address, items, discount_code, tax_rate, processing_fee, metadata):
"""
Process a payment - this function is too large and complex
"""
# Input validation - should be extracted to separate function
if not amount or amount <= 0:
return {"success": False, "error": "Invalid amount"}
if not currency:
return {"success": False, "error": "Currency required"}
if currency not in ["USD", "EUR", "GBP", "CAD", "AUD"]: # Hardcoded list
return {"success": False, "error": "Unsupported currency"}
if not payment_method:
return {"success": False, "error": "Payment method required"}
if not customer_data or "email" not in customer_data:
return {"success": False, "error": "Customer email required"}
# Tax calculation - complex business logic that should be separate service
tax_amount = 0
if tax_rate:
if currency == "USD":
# US tax logic - hardcoded rules
if billing_address and "state" in billing_address:
state = billing_address["state"]
if state == "CA":
tax_amount = amount * 0.08 # California tax
elif state == "NY":
tax_amount = amount * 0.085 # New York tax
elif state == "TX":
tax_amount = amount * 0.0625 # Texas tax
elif state == "FL":
tax_amount = amount * 0.06 # Florida tax
else:
tax_amount = amount * 0.05 # Default tax
elif currency == "EUR":
# EU VAT logic - also hardcoded
tax_amount = amount * 0.20 # 20% VAT
elif currency == "GBP":
tax_amount = amount * 0.20 # UK VAT
# Discount calculation - another complex block
discount_amount = 0
if discount_code:
# FIXME: This should query a discount service
if discount_code == "SAVE10":
discount_amount = amount * 0.10
elif discount_code == "SAVE20":
discount_amount = amount * 0.20
elif discount_code == "NEWUSER":
discount_amount = min(50, amount * 0.25) # Max $50 discount
elif discount_code == "LOYALTY":
# Complex loyalty discount logic
customer_tier = customer_data.get("tier", "bronze")
if customer_tier == "gold":
discount_amount = amount * 0.15
elif customer_tier == "silver":
discount_amount = amount * 0.10
elif customer_tier == "bronze":
discount_amount = amount * 0.05
# Calculate final amount
final_amount = amount - discount_amount + tax_amount + processing_fee
# Payment method routing - should use strategy pattern
if payment_method["type"] == "credit_card":
# Credit card processing
if payment_method["provider"] == "stripe":
try:
# Stripe API call - no retry logic
response = requests.post(
"https://api.stripe.com/v1/charges",
headers={"Authorization": f"Bearer {self.stripe_key}"},
data={
"amount": int(final_amount * 100), # Convert to cents
"currency": currency.lower(),
"source": payment_method["token"],
"description": f"Payment for {len(items)} items"
}
)
if response.status_code == 200:
stripe_response = response.json()
# Store transaction - should be in database
transaction = {
"id": stripe_response["id"],
"amount": final_amount,
"currency": currency,
"status": "completed",
"timestamp": time.time(),
"provider": "stripe",
"customer": customer_data["email"],
"items": items,
"tax_amount": tax_amount,
"discount_amount": discount_amount
}
# Send confirmation email - inline instead of separate service
self.send_payment_confirmation_email(customer_data["email"], transaction)
return {"success": True, "transaction": transaction}
else:
return {"success": False, "error": "Stripe payment failed"}
except Exception as e:
# Broad exception handling - should be more specific
print(f"Stripe error: {e}") # Should use proper logging
return {"success": False, "error": "Payment processing error"}
elif payment_method["provider"] == "square":
# Square processing - duplicate code structure
try:
response = requests.post(
"https://connect.squareup.com/v2/payments",
headers={"Authorization": f"Bearer {self.square_key}"},
json={
"source_id": payment_method["token"],
"amount_money": {
"amount": int(final_amount * 100),
"currency": currency
}
}
)
if response.status_code == 200:
square_response = response.json()
transaction = {
"id": square_response["payment"]["id"],
"amount": final_amount,
"currency": currency,
"status": "completed",
"timestamp": time.time(),
"provider": "square",
"customer": customer_data["email"],
"items": items,
"tax_amount": tax_amount,
"discount_amount": discount_amount
}
self.send_payment_confirmation_email(customer_data["email"], transaction)
return {"success": True, "transaction": transaction}
else:
return {"success": False, "error": "Square payment failed"}
except Exception as e:
print(f"Square error: {e}")
return {"success": False, "error": "Payment processing error"}
elif payment_method["type"] == "paypal":
# PayPal processing - more duplicate code
try:
response = requests.post(
"https://api.paypal.com/v2/checkout/orders",
headers={"Authorization": f"Bearer {self.paypal_key}"},
json={
"intent": "CAPTURE",
"purchase_units": [{
"amount": {
"currency_code": currency,
"value": str(final_amount)
}
}]
}
)
if response.status_code == 201:
paypal_response = response.json()
transaction = {
"id": paypal_response["id"],
"amount": final_amount,
"currency": currency,
"status": "completed",
"timestamp": time.time(),
"provider": "paypal",
"customer": customer_data["email"],
"items": items,
"tax_amount": tax_amount,
"discount_amount": discount_amount
}
self.send_payment_confirmation_email(customer_data["email"], transaction)
return {"success": True, "transaction": transaction}
else:
return {"success": False, "error": "PayPal payment failed"}
except Exception as e:
print(f"PayPal error: {e}")
return {"success": False, "error": "Payment processing error"}
else:
return {"success": False, "error": "Unsupported payment method"}
def send_payment_confirmation_email(self, email, transaction):
# Email sending logic - should be separate service
# HACK: Using print instead of actual email service
print(f"Sending confirmation email to {email}")
print(f"Transaction ID: {transaction['id']}")
print(f"Amount: {transaction['currency']} {transaction['amount']}")
# TODO: Implement actual email sending
pass
def refund_payment(self, transaction_id, amount=None):
# Refund logic - incomplete implementation
# TODO: Implement refund for different providers
print(f"Refunding transaction {transaction_id}")
if amount:
print(f"Partial refund: {amount}")
else:
print("Full refund")
# XXX: This doesn't actually process the refund
return {"success": True, "message": "Refund initiated"}
def get_transaction(self, transaction_id):
# Should query database, but we don't have one
# FIXME: Implement actual transaction lookup
return {"id": transaction_id, "status": "unknown"}
def validate_credit_card(self, card_number, expiry_month, expiry_year, cvv):
# Basic card validation - should use proper validation library
if not card_number or len(card_number) < 13 or len(card_number) > 19:
return False
# Luhn algorithm check - reimplemented poorly
digits = [int(d) for d in card_number if d.isdigit()]
checksum = 0
for i, digit in enumerate(reversed(digits)):
if i % 2 == 1:
digit *= 2
if digit > 9:
digit -= 9
checksum += digit
if checksum % 10 != 0:
return False
# Expiry validation
if expiry_month < 1 or expiry_month > 12:
return False
current_year = int(time.strftime("%Y"))
current_month = int(time.strftime("%m"))
if expiry_year < current_year:
return False
elif expiry_year == current_year and expiry_month < current_month:
return False
# CVV validation
if not cvv or len(cvv) < 3 or len(cvv) > 4:
return False
return True
# Module-level functions that should be in class or separate module
def calculate_processing_fee(amount, provider):
"""Calculate processing fee - hardcoded rates"""
if provider == "stripe":
return amount * 0.029 + 0.30 # Stripe rates
elif provider == "paypal":
return amount * 0.031 + 0.30 # PayPal rates
elif provider == "square":
return amount * 0.026 + 0.10 # Square rates
else:
return 0
def format_currency(amount, currency):
"""Format currency - basic implementation"""
# Should use proper internationalization
if currency == "USD":
return f"${amount:.2f}"
elif currency == "EUR":
return f"€{amount:.2f}"
elif currency == "GBP":
return f"£{amount:.2f}"
else:
return f"{currency} {amount:.2f}"
# Global state - anti-pattern
payment_processor_instance = None
def get_payment_processor():
global payment_processor_instance
if payment_processor_instance is None:
payment_processor_instance = PaymentProcessor()
return payment_processor_instance#!/usr/bin/env python3
"""
User service module with various tech debt examples
"""
import hashlib
import json
import time
import re
from typing import Dict, List, Any, Optional
# TODO: Move this to configuration file
DATABASE_URL = "postgresql://user:password123@localhost:5432/mydb"
API_KEY = "sk-1234567890abcdef" # FIXME: This should be in environment variables
class UserService:
def __init__(self):
self.users = {}
self.cache = {}
# HACK: Using dict for now, should be proper database connection
self.db_connection = None
def create_user(self, name, email, password, age, phone, address, city, state, zip_code, country, preferences, notifications, billing_info):
# Function with too many parameters - should use User dataclass
if not name:
return None
if not email:
return None
if not password:
return None
if not age:
return None
if not phone:
return None
if not address:
return None
if not city:
return None
if not state:
return None
if not zip_code:
return None
if not country:
return None
# Duplicate validation logic - should be extracted
if age < 13:
print("User must be at least 13 years old")
return None
if age > 150:
print("Invalid age")
return None
# More validation
if not self.validate_email(email):
print("Invalid email format")
return None
# Password validation - duplicated elsewhere
if len(password) < 8:
print("Password too short")
return None
if not re.search(r"[A-Z]", password):
print("Password must contain uppercase letter")
return None
if not re.search(r"[a-z]", password):
print("Password must contain lowercase letter")
return None
if not re.search(r"\d", password):
print("Password must contain digit")
return None
# Deep nesting example
if preferences:
if 'notifications' in preferences:
if preferences['notifications']:
if 'email' in preferences['notifications']:
if preferences['notifications']['email']:
if 'frequency' in preferences['notifications']['email']:
if preferences['notifications']['email']['frequency'] == 'daily':
print("Daily email notifications enabled")
elif preferences['notifications']['email']['frequency'] == 'weekly':
print("Weekly email notifications enabled")
else:
print("Invalid notification frequency")
# TODO: Implement proper user ID generation
user_id = str(hash(email)) # XXX: This is terrible for production
# Magic numbers everywhere
password_hash = hashlib.sha256((password + "salt123").encode()).hexdigest()
user_data = {
"id": user_id,
"name": name,
"email": email,
"password_hash": password_hash,
"age": age,
"phone": phone,
"address": address,
"city": city,
"state": state,
"zip_code": zip_code,
"country": country,
"preferences": preferences,
"notifications": notifications,
"billing_info": billing_info,
"created_at": time.time(),
"updated_at": time.time(),
"last_login": None,
"login_count": 0,
"is_active": True,
"is_verified": False,
"verification_token": None,
"reset_token": None,
"failed_login_attempts": 0,
"locked_until": None,
"subscription_level": "free",
"credits": 100
}
self.users[user_id] = user_data
return user_id
def validate_email(self, email):
# Duplicate validation logic - should be in utils
if not email:
return False
if "@" not in email:
return False
if "." not in email:
return False
return True
def authenticate_user(self, email, password):
# More duplicate validation
if not email:
return None
if not password:
return None
# Linear search through users - O(n) complexity
for user_id, user_data in self.users.items():
if user_data["email"] == email:
# Same password hashing logic duplicated
password_hash = hashlib.sha256((password + "salt123").encode()).hexdigest()
if user_data["password_hash"] == password_hash:
# Update login stats
user_data["last_login"] = time.time()
user_data["login_count"] += 1
user_data["failed_login_attempts"] = 0
return user_id
else:
# Failed login handling
user_data["failed_login_attempts"] += 1
if user_data["failed_login_attempts"] >= 5: # Magic number
user_data["locked_until"] = time.time() + 1800 # 30 minutes
return None
return None
def get_user(self, user_id):
# No error handling
return self.users[user_id]
def update_user(self, user_id, updates):
try:
# Empty catch block - bad practice
user = self.users[user_id]
except:
pass
# More validation duplication
if "age" in updates:
if updates["age"] < 13:
print("User must be at least 13 years old")
return False
if updates["age"] > 150:
print("Invalid age")
return False
if "email" in updates:
if not self.validate_email(updates["email"]):
print("Invalid email format")
return False
# Direct dictionary manipulation without validation
for key, value in updates.items():
user[key] = value
user["updated_at"] = time.time()
return True
def delete_user(self, user_id):
# print("Deleting user", user_id) # Commented out code
# TODO: Implement soft delete instead
del self.users[user_id]
def search_users(self, query):
results = []
# Inefficient search algorithm - O(n*m)
for user_id, user_data in self.users.items():
if query.lower() in user_data["name"].lower():
results.append(user_data)
elif query.lower() in user_data["email"].lower():
results.append(user_data)
elif query in user_data.get("phone", ""):
results.append(user_data)
return results
def export_users(self):
# Security risk - no access control
return json.dumps(self.users, indent=2)
def import_users(self, json_data):
# No validation of imported data
imported_users = json.loads(json_data)
self.users.update(imported_users)
# def old_create_user(self, name, email):
# # Old implementation kept as comment
# return {"name": name, "email": email}
def calculate_user_score(self, user_id):
user = self.users[user_id]
score = 0
# Complex scoring logic with magic numbers
if user["login_count"] > 10:
score += 50
elif user["login_count"] > 5:
score += 30
elif user["login_count"] > 1:
score += 10
if user["subscription_level"] == "premium":
score += 100
elif user["subscription_level"] == "pro":
score += 75
elif user["subscription_level"] == "basic":
score += 25
# Age-based scoring with arbitrary rules
if user["age"] >= 18 and user["age"] <= 65:
score += 20
elif user["age"] > 65:
score += 10
return score
# Global variable - should be encapsulated
user_service_instance = UserService()
def get_user_service():
return user_service_instance
# Utility function that should be in separate module
def hash_password(password, salt="salt123"):
# Hardcoded salt - security issue
return hashlib.sha256((password + salt).encode()).hexdigest()
# Another utility function with duplicate logic
def validate_password(password):
if len(password) < 8:
return False, "Password too short"
if not re.search(r"[A-Z]", password):
return False, "Password must contain uppercase letter"
if not re.search(r"[a-z]", password):
return False, "Password must contain lowercase letter"
if not re.search(r"\d", password):
return False, "Password must contain digit"
return True, "Valid password"[
{
"id": "DEBT-0001",
"type": "large_function",
"description": "create_user function in user_service.py is 89 lines long",
"file_path": "src/user_service.py",
"line_number": 13,
"severity": "high",
"metadata": {
"function_name": "create_user",
"length": 89,
"recommended_max": 50
},
"detected_date": "2024-02-10T10:30:00",
"status": "identified"
},
{
"id": "DEBT-0002",
"type": "duplicate_code",
"description": "Password validation logic duplicated in 3 locations",
"file_path": "src/user_service.py",
"line_number": 45,
"severity": "medium",
"metadata": {
"duplicate_count": 3,
"other_files": ["src/auth.py", "src/frontend.js"]
},
"detected_date": "2024-02-10T10:30:00",
"status": "identified"
},
{
"id": "DEBT-0003",
"type": "security_risk",
"description": "Hardcoded API key in payment_processor.py",
"file_path": "src/payment_processor.py",
"line_number": 10,
"severity": "critical",
"metadata": {
"security_issue": "hardcoded_credentials",
"exposure_risk": "high"
},
"detected_date": "2024-02-10T10:30:00",
"status": "identified"
},
{
"id": "DEBT-0004",
"type": "high_complexity",
"description": "process_payment function has cyclomatic complexity of 24",
"file_path": "src/payment_processor.py",
"line_number": 19,
"severity": "high",
"metadata": {
"function_name": "process_payment",
"complexity": 24,
"recommended_max": 10
},
"detected_date": "2024-02-10T10:30:00",
"status": "identified"
},
{
"id": "DEBT-0005",
"type": "missing_docstring",
"description": "PaymentProcessor class missing docstring",
"file_path": "src/payment_processor.py",
"line_number": 8,
"severity": "low",
"metadata": {
"class_name": "PaymentProcessor"
},
"detected_date": "2024-02-10T10:30:00",
"status": "identified"
},
{
"id": "DEBT-0006",
"type": "todo_comment",
"description": "TODO: Move this to configuration file",
"file_path": "src/user_service.py",
"line_number": 8,
"severity": "low",
"metadata": {
"comment": "TODO: Move this to configuration file"
},
"detected_date": "2024-02-10T10:30:00",
"status": "identified"
},
{
"id": "DEBT-0007",
"type": "empty_catch_blocks",
"description": "Empty catch block in update_user method",
"file_path": "src/user_service.py",
"line_number": 156,
"severity": "medium",
"metadata": {
"method_name": "update_user",
"exception_type": "generic"
},
"detected_date": "2024-02-10T10:30:00",
"status": "identified"
},
{
"id": "DEBT-0008",
"type": "magic_numbers",
"description": "Magic number 1800 used for lock timeout",
"file_path": "src/user_service.py",
"line_number": 98,
"severity": "low",
"metadata": {
"value": 1800,
"context": "account_lockout_duration"
},
"detected_date": "2024-02-10T10:30:00",
"status": "identified"
},
{
"id": "DEBT-0009",
"type": "deep_nesting",
"description": "Deep nesting detected: 6 levels in preferences handling",
"file_path": "src/frontend.js",
"line_number": 32,
"severity": "medium",
"metadata": {
"nesting_level": 6,
"recommended_max": 4
},
"detected_date": "2024-02-10T10:30:00",
"status": "identified"
},
{
"id": "DEBT-0010",
"type": "long_line",
"description": "Line too long: 156 characters",
"file_path": "src/frontend.js",
"line_number": 127,
"severity": "low",
"metadata": {
"length": 156,
"recommended_max": 120
},
"detected_date": "2024-02-10T10:30:00",
"status": "identified"
},
{
"id": "DEBT-0011",
"type": "commented_code",
"description": "Dead code left in comments",
"file_path": "src/frontend.js",
"line_number": 285,
"severity": "low",
"metadata": {
"lines_of_commented_code": 8
},
"detected_date": "2024-02-10T10:30:00",
"status": "identified"
},
{
"id": "DEBT-0012",
"type": "global_variables",
"description": "Global variable userCache should be encapsulated",
"file_path": "src/frontend.js",
"line_number": 7,
"severity": "medium",
"metadata": {
"variable_name": "userCache",
"scope": "global"
},
"detected_date": "2024-02-10T10:30:00",
"status": "identified"
},
{
"id": "DEBT-0013",
"type": "synchronous_ajax",
"description": "Synchronous AJAX call blocks UI thread",
"file_path": "src/frontend.js",
"line_number": 189,
"severity": "high",
"metadata": {
"method": "XMLHttpRequest",
"async": false
},
"detected_date": "2024-02-10T10:30:00",
"status": "identified"
},
{
"id": "DEBT-0014",
"type": "hardcoded_values",
"description": "Tax rates hardcoded in payment processing logic",
"file_path": "src/payment_processor.py",
"line_number": 45,
"severity": "medium",
"metadata": {
"values": ["0.08", "0.085", "0.0625", "0.06"],
"context": "tax_calculation"
},
"detected_date": "2024-02-10T10:30:00",
"status": "identified"
},
{
"id": "DEBT-0015",
"type": "no_error_handling",
"description": "API calls without proper error handling",
"file_path": "src/payment_processor.py",
"line_number": 78,
"severity": "high",
"metadata": {
"api_endpoint": "stripe",
"error_scenarios": ["network_failure", "invalid_response"]
},
"detected_date": "2024-02-10T10:30:00",
"status": "identified"
},
{
"id": "DEBT-0016",
"type": "inefficient_algorithm",
"description": "O(n) user search could be optimized with indexing",
"file_path": "src/user_service.py",
"line_number": 178,
"severity": "medium",
"metadata": {
"current_complexity": "O(n)",
"recommended_complexity": "O(log n)",
"method_name": "search_users"
},
"detected_date": "2024-02-10T10:30:00",
"status": "identified"
},
{
"id": "DEBT-0017",
"type": "memory_leak_risk",
"description": "Event listeners attached without cleanup",
"file_path": "src/frontend.js",
"line_number": 145,
"severity": "medium",
"metadata": {
"event_type": "click",
"cleanup_missing": true
},
"detected_date": "2024-02-10T10:30:00",
"status": "identified"
},
{
"id": "DEBT-0018",
"type": "sql_injection_risk",
"description": "Potential SQL injection in user query",
"file_path": "src/database.py",
"line_number": 25,
"severity": "critical",
"metadata": {
"query_type": "dynamic",
"user_input": "unsanitized"
},
"detected_date": "2024-02-10T10:30:00",
"status": "identified"
},
{
"id": "DEBT-0019",
"type": "outdated_dependency",
"description": "jQuery version 2.1.4 has known security vulnerabilities",
"file_path": "package.json",
"line_number": 15,
"severity": "high",
"metadata": {
"package": "jquery",
"current_version": "2.1.4",
"latest_version": "3.6.4",
"vulnerabilities": ["CVE-2020-11022", "CVE-2020-11023"]
},
"detected_date": "2024-02-10T10:30:00",
"status": "identified"
},
{
"id": "DEBT-0020",
"type": "test_debt",
"description": "No unit tests for critical payment processing logic",
"file_path": "src/payment_processor.py",
"line_number": 19,
"severity": "high",
"metadata": {
"coverage": 0,
"critical_paths": ["process_payment", "refund_payment"],
"risk_level": "high"
},
"detected_date": "2024-02-10T10:30:00",
"status": "identified"
}
]{
"metadata": {
"generated_date": "2026-02-16T12:59:34.530390",
"analysis_period": "monthly",
"snapshots_analyzed": 2,
"date_range": {
"start": "2024-01-15T09:00:00",
"end": "2024-02-01T14:30:00"
},
"team_size": 5
},
"executive_summary": {
"overall_status": "excellent",
"health_score": 87.3,
"status_message": "Code quality is excellent with minimal technical debt.",
"key_insights": [
"Good progress on debt reduction"
],
"total_debt_items": 22,
"estimated_effort_hours": 193.5,
"high_priority_items": 6,
"velocity_impact_percent": 12.3
},
"current_health": {
"overall_score": 87.3,
"debt_density": 0.81,
"velocity_impact": 12.3,
"quality_score": 81.8,
"maintainability_score": 72.7,
"technical_risk_score": 38.2,
"date": "2024-02-01T14:30:00"
},
"trend_analysis": {
"overall_score": {
"metric_name": "overall_score",
"trend_direction": "improving",
"change_rate": 3.7,
"correlation_strength": 0.0,
"forecast_next_period": 91.0,
"confidence_interval": [
91.0,
91.0
]
},
"debt_density": {
"metric_name": "debt_density",
"trend_direction": "improving",
"change_rate": -0.31,
"correlation_strength": 0.0,
"forecast_next_period": 0.5,
"confidence_interval": [
0.5,
0.5
]
},
"velocity_impact": {
"metric_name": "velocity_impact",
"trend_direction": "improving",
"change_rate": -2.9,
"correlation_strength": 0.0,
"forecast_next_period": 9.4,
"confidence_interval": [
9.4,
9.4
]
},
"quality_score": {
"metric_name": "quality_score",
"trend_direction": "declining",
"change_rate": -3.9,
"correlation_strength": 0.0,
"forecast_next_period": 77.9,
"confidence_interval": [
77.9,
77.9
]
},
"technical_risk_score": {
"metric_name": "technical_risk_score",
"trend_direction": "improving",
"change_rate": -47.5,
"correlation_strength": 0.0,
"forecast_next_period": -9.3,
"confidence_interval": [
-9.3,
-9.3
]
}
},
"debt_velocity": [
{
"period": "2024-01-15 to 2024-02-01",
"new_debt_items": 0,
"resolved_debt_items": 6,
"net_change": -6,
"velocity_ratio": 10.0,
"effort_hours_added": 0,
"effort_hours_resolved": 77.0,
"net_effort_change": -77.0
}
],
"forecasts": {
"health_score_3_months": 98.4,
"health_score_6_months": 100,
"debt_count_3_months": 4,
"debt_count_6_months": 0,
"risk_score_3_months": 0
},
"recommendations": [
{
"priority": "medium",
"category": "focus_area",
"title": "Focus on Other Debt",
"description": "Other represents the largest debt category (16 items). Consider targeted initiatives.",
"impact": "medium",
"effort": "medium"
}
],
"visualizations": {
"health_timeline": [
{
"date": "2024-01-15",
"overall_score": 83.6,
"quality_score": 85.7,
"technical_risk": 85.7
},
{
"date": "2024-02-01",
"overall_score": 87.3,
"quality_score": 81.8,
"technical_risk": 38.2
}
],
"debt_accumulation": [
{
"date": "2024-01-15",
"total_debt": 28,
"high_priority": 9,
"security_debt": 5
},
{
"date": "2024-02-01",
"total_debt": 22,
"high_priority": 6,
"security_debt": 2
}
],
"category_distribution": [
{
"category": "code_quality",
"count": 5
},
{
"category": "other",
"count": 16
},
{
"category": "maintenance",
"count": 1
}
],
"debt_velocity": [
{
"period": "2024-01-15 to 2024-02-01",
"new_items": 0,
"resolved_items": 6,
"net_change": -6,
"velocity_ratio": 10.0
}
],
"effort_trend": [
{
"date": "2024-01-15",
"total_effort": 270.5
},
{
"date": "2024-02-01",
"total_effort": 193.5
}
]
},
"detailed_metrics": {
"debt_breakdown": {
"large_function": 1,
"duplicate_code": 1,
"high_complexity": 1,
"missing_docstring": 1,
"empty_catch_blocks": 1,
"deep_nesting": 1,
"long_line": 1,
"commented_code": 1,
"global_variables": 1,
"synchronous_ajax": 1,
"hardcoded_values": 1,
"no_error_handling": 1,
"inefficient_algorithm": 1,
"memory_leak_risk": 1,
"large_class": 1,
"circular_dependency": 1,
"broad_exception": 1,
"missing_validation": 1,
"performance_issue": 1,
"css_debt": 1,
"accessibility_issue": 1,
"configuration_debt": 1
},
"severity_breakdown": {
"high": 6,
"medium": 12,
"low": 4
},
"category_breakdown": {
"code_quality": 5,
"other": 16,
"maintenance": 1
},
"files_analyzed": 27,
"debt_density": 0.8148148148148148,
"average_effort_per_item": 8.795454545454545
}
}Tech Debt Tracker
A comprehensive technical debt management system that helps engineering teams identify, prioritize, and track technical debt across codebases. This skill provides three interconnected tools for a complete debt management workflow.
Overview
Technical debt is like financial debt - it compounds over time and reduces team velocity if not managed systematically. This skill provides:
- Automated Debt Detection: Scan codebases to identify various types of technical debt
- Intelligent Prioritization: Use proven frameworks to prioritize debt based on business impact
- Trend Analysis: Track debt evolution over time with executive-friendly dashboards
Tools
1. Debt Scanner (debt_scanner.py)
Scans codebases to automatically detect technical debt signals using AST parsing for Python and regex patterns for other languages.
Features:
- Detects 15+ types of technical debt (large functions, complexity, duplicates, security issues, etc.)
- Multi-language support (Python, JavaScript, Java, C#, Go, etc.)
- Configurable thresholds and rules
- Dual output: JSON for tools, human-readable for reports
Usage:
# Basic scan
python scripts/debt_scanner.py /path/to/codebase
# With custom config and output
python scripts/debt_scanner.py /path/to/codebase --config config.json --output report.json
# Different output formats
python scripts/debt_scanner.py /path/to/codebase --format both2. Debt Prioritizer (debt_prioritizer.py)
Takes debt inventory and creates prioritized backlog using proven prioritization frameworks.
Features:
- Multiple prioritization frameworks (Cost of Delay, WSJF, RICE)
- Business impact analysis with ROI calculations
- Sprint allocation recommendations
- Effort estimation with risk adjustment
- Executive and engineering reports
Usage:
# Basic prioritization
python scripts/debt_prioritizer.py debt_inventory.json
# Custom framework and team size
python scripts/debt_prioritizer.py inventory.json --framework wsjf --team-size 8
# Sprint capacity planning
python scripts/debt_prioritizer.py inventory.json --sprint-capacity 80 --output backlog.json3. Debt Dashboard (debt_dashboard.py)
Analyzes historical debt data to provide trend analysis, health scoring, and executive reporting.
Features:
- Health score trending over time
- Debt velocity analysis (accumulation vs resolution)
- Executive summary with business impact
- Forecasting based on current trends
- Strategic recommendations
Usage:
# Single directory of scans
python scripts/debt_dashboard.py --input-dir ./debt_scans/
# Multiple specific files
python scripts/debt_dashboard.py scan1.json scan2.json scan3.json
# Custom analysis period
python scripts/debt_dashboard.py data.json --period quarterly --team-size 6Quick Start
1. Scan Your Codebase
# Scan your project
python scripts/debt_scanner.py ~/my-project --output initial_scan.json
# Review the results
python scripts/debt_scanner.py ~/my-project --format text2. Prioritize Your Debt
# Create prioritized backlog
python scripts/debt_prioritizer.py initial_scan.json --output backlog.json
# View sprint recommendations
python scripts/debt_prioritizer.py initial_scan.json --format text3. Track Over Time
# After multiple scans, analyze trends
python scripts/debt_dashboard.py scan1.json scan2.json scan3.json --output dashboard.json
# Generate executive report
python scripts/debt_dashboard.py --input-dir ./scans/ --format textConfiguration
Scanner Configuration
Create config.json to customize detection rules:
{
"max_function_length": 50,
"max_complexity": 10,
"max_nesting_depth": 4,
"ignore_patterns": ["*.test.js", "build/", "node_modules/"],
"file_extensions": {
"python": [".py"],
"javascript": [".js", ".jsx", ".ts", ".tsx"]
}
}Team Configuration
Adjust tools for your team size and sprint capacity:
# 8-person team with 2-week sprints
python scripts/debt_prioritizer.py inventory.json --team-size 8 --sprint-capacity 160Sample Data
The assets/ directory contains sample data for testing:
sample_codebase/: Example codebase with various debt typessample_debt_inventory.json: Example debt inventoryhistorical_debt_*.json: Sample historical data for trending
Try the tools on sample data:
# Test scanner
python scripts/debt_scanner.py assets/sample_codebase
# Test prioritizer
python scripts/debt_prioritizer.py assets/sample_debt_inventory.json
# Test dashboard
python scripts/debt_dashboard.py assets/historical_debt_*.jsonUnderstanding the Output
Health Score (0-100)
- 85-100: Excellent - Minimal debt, sustainable practices
- 70-84: Good - Manageable debt level, some attention needed
- 55-69: Fair - Debt accumulating, requires focused effort
- 40-54: Poor - High debt level, impacts productivity
- 0-39: Critical - Immediate action required
Priority Levels
- Critical: Security issues, blocking problems (fix immediately)
- High: Significant impact on quality or velocity (next sprint)
- Medium: Moderate impact, plan for upcoming work (next quarter)
- Low: Minor issues, fix opportunistically (when convenient)
Debt Categories
- Code Quality: Large functions, complexity, duplicates
- Architecture: Design issues, coupling problems
- Security: Vulnerabilities, hardcoded secrets
- Testing: Missing tests, poor coverage
- Documentation: Missing or outdated docs
- Dependencies: Outdated packages, license issues
Integration with Development Workflow
CI/CD Integration
Add debt scanning to your CI pipeline:
# In your CI script
python scripts/debt_scanner.py . --output ci_scan.json
# Compare with baseline, fail build if critical issues foundSprint Planning
1. Weekly: Run scanner to detect new debt 2. Sprint Planning: Use prioritizer for debt story sizing 3. Monthly: Generate dashboard for trend analysis 4. Quarterly: Executive review with strategic recommendations
Code Review Integration
Use scanner output to focus code reviews:
# Scan PR branch
python scripts/debt_scanner.py . --output pr_scan.json
# Compare with main branch baseline
# Focus review on areas with new debtBest Practices
Debt Management Strategy
1. Prevention: Use scanner in CI to catch debt early 2. Prioritization: Always use business impact for priority 3. Allocation: Reserve 15-20% sprint capacity for debt work 4. Measurement: Track health score and velocity impact 5. Communication: Use dashboard reports for stakeholders
Common Pitfalls to Avoid
- Analysis Paralysis: Don't spend too long on perfect prioritization
- Technical Focus Only: Always consider business impact
- Inconsistent Application: Ensure all teams use same approach
- Ignoring Trends: Pay attention to debt accumulation rate
- All-or-Nothing: Incremental debt reduction is better than none
Success Metrics
- Health Score Improvement: Target 5+ point quarterly improvement
- Velocity Impact: Keep debt velocity impact below 20%
- Team Satisfaction: Survey developers on code quality satisfaction
- Incident Reduction: Track correlation between debt and production issues
Advanced Usage
Custom Debt Types
Extend the scanner for organization-specific debt patterns:
1. Add patterns to config.json 2. Modify detection logic in scanner 3. Update categorization in prioritizer
Integration with External Tools
- Jira/GitHub: Import debt items as tickets
- SonarQube: Combine with static analysis metrics
- APM Tools: Correlate debt with performance metrics
- Chat Systems: Send debt alerts to team channels
Automated Reporting
Set up automated debt reporting:
#!/bin/bash
# Daily debt monitoring script
python scripts/debt_scanner.py . --output daily_scan.json
python scripts/debt_dashboard.py daily_scan.json --output daily_report.json
# Send report to stakeholdersTroubleshooting
Common Issues
Scanner not finding files: Check ignore_patterns in config Prioritizer giving unexpected results: Verify business impact scoring Dashboard shows flat trends: Need more historical data points
Performance Tips
- Use
.gitignorepatterns to exclude irrelevant files - Limit scan depth for large monorepos
- Run dashboard analysis on subset for faster iteration
Getting Help
1. Check the references/ directory for detailed documentation 2. Review sample data and expected outputs 3. Examine the tool source code for customization ideas
Contributing
This skill is designed to be customized for your organization's needs:
1. Add Detection Rules: Extend scanner patterns for your tech stack 2. Custom Prioritization: Modify scoring algorithms for your business context 3. New Report Formats: Add output formats for your stakeholders 4. Integration Hooks: Add connectors to your existing tools
The codebase is designed with extensibility in mind - each tool is modular and can be enhanced independently.
---
Remember: Technical debt management is a journey, not a destination. These tools help you make informed decisions about balancing new feature development with technical excellence. Start small, measure impact, and iterate based on what works for your team.
Tech Debt Tracker -- Reference Material
Technical Debt Quadrant (Martin Fowler)
Quadrant 1: Reckless & Deliberate
- "We don't have time for design"
- Highest priority for remediation
Quadrant 2: Prudent & Deliberate
- "We must ship now and deal with consequences"
- Schedule for near-term resolution
Quadrant 3: Reckless & Inadvertent
- "What's layering?"
- Focus on education and process improvement
Quadrant 4: Prudent & Inadvertent
- "Now we know how we should have done it"
- Normal part of learning, lowest priority
Detailed Detection Heuristics
Code Debt Indicators
- Long functions (>50 lines for complex logic, >20 for simple operations)
- Deep nesting (>4 levels of indentation)
- High cyclomatic complexity (>10)
- Duplicate code patterns (>3 similar blocks)
- Missing or inadequate error handling
- Poor variable/function naming
- Magic numbers and hardcoded values
- Commented-out code blocks
Architecture Debt Indicators
- Monolithic components that should be modular
- Circular dependencies between modules
- Violation of separation of concerns
- Inconsistent data flow patterns
- Over-engineering or under-engineering for current scale
- Tightly coupled components
- Missing abstraction layers
Test Debt Indicators
- Low test coverage (<80% for critical paths)
- Missing unit tests for complex logic
- No integration tests for key workflows
- Flaky tests that pass/fail intermittently
- Slow test execution (>10 minutes for unit tests)
- Tests that don't test meaningful behavior
- Missing test data management strategy
Documentation Debt Indicators
- Missing API documentation
- Outdated README files
- No architectural decision records (ADRs)
- Missing code comments for complex algorithms
- No onboarding documentation
- Inconsistent documentation formats
- Documentation that contradicts implementation
Dependency Debt Indicators
- Outdated packages with known security vulnerabilities
- Dependencies with incompatible licenses
- Unused dependencies bloating the build
- Version conflicts between packages
- Deprecated APIs still in use
- Heavy dependencies for simple tasks
- Missing dependency pinning
Infrastructure Debt Indicators
- Manual deployment processes
- Missing monitoring and alerting
- Inadequate logging
- No disaster recovery plan
- Inconsistent environments (dev/staging/prod)
- Missing CI/CD pipelines
- Infrastructure as code gaps
Implementation Roadmap
Phase 1: Foundation (Weeks 1-2)
1. Set up debt scanning infrastructure 2. Establish debt taxonomy and scoring criteria 3. Scan initial codebase and create baseline inventory 4. Train team on debt identification and reporting
Phase 2: Process Integration (Weeks 3-4)
1. Integrate debt tracking into sprint planning 2. Establish debt budgets and allocation rules 3. Create stakeholder reporting templates 4. Set up automated debt scanning in CI/CD
Phase 3: Optimization (Weeks 5-6)
1. Refine scoring algorithms based on team feedback 2. Implement trend analysis and predictive metrics 3. Create specialized debt reduction initiatives 4. Establish cross-team debt coordination processes
Phase 4: Maturity (Ongoing)
1. Continuous improvement of detection algorithms 2. Advanced analytics and prediction models 3. Integration with planning and project management tools 4. Organization-wide debt management best practices
Success Criteria
Quantitative targets (6 months):
- 25% reduction in debt interest rate
- 15% improvement in development velocity
- 30% reduction in production defects
- 20% faster code review cycles
Qualitative targets:
- Improved developer satisfaction scores
- Reduced context switching during feature development
- Faster onboarding for new team members
- Better predictability in feature delivery timelines
Common Pitfalls
| Pitfall | Solution |
|---|---|
| Analysis paralysis | Set time limits for analysis; use "good enough" scoring |
| Perfectionism | Focus on high-impact debt; accept some debt is acceptable |
| Ignoring business context | Tie debt work to business outcomes and customer impact |
| Inconsistent adoption | Make debt tracking part of standard development workflow |
| Tool over-engineering | Start simple; iterate based on actual usage patterns |
Technical Debt Classification Taxonomy
Overview
This document provides a comprehensive taxonomy for classifying technical debt across different dimensions. Consistent classification is essential for tracking, prioritizing, and managing technical debt effectively across teams and projects.
Primary Categories
1. Code Debt
Definition: Issues at the code level that make software harder to understand, modify, or maintain.
Subcategories:
- Structural Issues
large_function: Functions exceeding recommended size limitshigh_complexity: High cyclomatic complexity (>10)deep_nesting: Excessive indentation levels (>4)long_parameter_list: Too many function parameters (>5)data_clumps: Related data that should be grouped together
- Naming and Documentation
poor_naming: Unclear or misleading variable/function namesmissing_docstring: Functions/classes without documentationmagic_numbers: Hardcoded numeric values without explanationcommented_code: Dead code left in comments
- Duplication and Patterns
duplicate_code: Identical or similar code blockscopy_paste_programming: Evidence of code duplicationinconsistent_patterns: Mixed coding styles within codebase
- Error Handling
empty_catch_blocks: Exception handling without proper actiongeneric_exceptions: Catching overly broad exception typesmissing_error_handling: No error handling for failure scenarios
Severity Indicators:
- Critical: Security vulnerabilities, syntax errors
- High: Functions >100 lines, complexity >20
- Medium: Functions 50-100 lines, complexity 10-20
- Low: Minor style issues, short functions with minor problems
2. Architecture Debt
Definition: High-level design decisions that limit system flexibility, scalability, or maintainability.
Subcategories:
- Structural Issues
monolithic_design: Components that should be separatedcircular_dependencies: Modules depending on each other cyclicallygod_object: Classes/modules with too many responsibilitiesinappropriate_intimacy: Excessive coupling between modules
- Layer Violations
abstraction_inversion: Lower-level modules depending on higher-level onesleaky_abstractions: Implementation details exposed through interfacesbroken_hierarchy: Inheritance relationships that don't make sense
- Scalability Issues
performance_bottlenecks: Known architectural performance limitationsresource_contention: Shared resources creating bottleneckssingle_point_failure: Critical components without redundancy
Impact Assessment:
- High Impact: Affects system scalability, blocks major features
- Medium Impact: Makes changes more difficult, affects team productivity
- Low Impact: Minor architectural inconsistencies
3. Test Debt
Definition: Inadequate testing infrastructure, coverage, or quality that increases risk and slows development.
Subcategories:
- Coverage Issues
low_coverage: Test coverage below team standards (<80%)missing_unit_tests: No tests for critical business logicmissing_integration_tests: No tests for component interactionsmissing_end_to_end_tests: No full system workflow validation
- Test Quality
flaky_tests: Tests that pass/fail inconsistentlyslow_tests: Test suite taking too long to executebrittle_tests: Tests that break with minor code changesunclear_test_intent: Tests without clear purpose or documentation
- Infrastructure
manual_testing_only: No automated testing processesmissing_test_data: No proper test data managementenvironment_dependencies: Tests requiring specific environments
Priority Matrix:
- Critical Path Coverage: High priority for business-critical features
- Regression Risk: High priority for frequently changed code
- Development Velocity: Medium priority for developer productivity
- Documentation Value: Low priority for test clarity improvements
4. Documentation Debt
Definition: Missing, outdated, or poor-quality documentation that hinders understanding and maintenance.
Subcategories:
- API Documentation
missing_api_docs: No documentation for public APIsoutdated_api_docs: Documentation doesn't match implementationincomplete_examples: No usage examples for complex APIs
- Code Documentation
missing_comments: Complex algorithms without explanationoutdated_comments: Comments contradicting current implementationredundant_comments: Comments that just restate the code
- System Documentation
missing_architecture_docs: No high-level system design documentationmissing_deployment_docs: No deployment or operations guidemissing_onboarding_docs: No guide for new team members
Freshness Assessment:
- Stale: Documentation >6 months out of date
- Outdated: Documentation 3-6 months out of date
- Current: Documentation <3 months out of date
5. Dependency Debt
Definition: Issues with external libraries, frameworks, and system dependencies.
Subcategories:
- Version Management
outdated_dependencies: Libraries with available updatesvulnerable_dependencies: Dependencies with known security issuesdeprecated_dependencies: Dependencies no longer maintainedversion_conflicts: Incompatible dependency versions
- License and Compliance
license_violations: Dependencies with incompatible licenseslicense_unknown: Dependencies without clear licensingcompliance_risk: Dependencies creating legal/regulatory risks
- Usage Optimization
unused_dependencies: Dependencies included but not usedoversized_dependencies: Heavy libraries for simple functionalityredundant_dependencies: Multiple libraries solving same problem
Risk Assessment:
- Security Risk: Known vulnerabilities, unmaintained dependencies
- Legal Risk: License conflicts, compliance issues
- Technical Risk: Breaking changes, deprecation notices
- Maintenance Risk: Outdated versions, unsupported libraries
6. Infrastructure Debt
Definition: Operations, deployment, and infrastructure-related technical debt.
Subcategories:
- Deployment and CI/CD
manual_deployment: No automated deployment processesmissing_pipeline: No CI/CD pipeline automationbrittle_deployments: Deployment process prone to failureenvironment_drift: Inconsistencies between environments
- Monitoring and Observability
missing_monitoring: No application/system monitoringinadequate_logging: Insufficient logging for troubleshootingmissing_alerting: No alerts for critical system conditionspoor_observability: Can't understand system behavior in production
- Configuration Management
hardcoded_config: Configuration embedded in codemanual_configuration: No automated configuration managementsecrets_in_code: Sensitive information stored in codeinconsistent_environments: Dev/staging/prod differences
Operational Impact:
- Availability: Affects system uptime and reliability
- Debuggability: Affects ability to troubleshoot issues
- Scalability: Affects ability to handle load increases
- Security: Affects system security posture
Severity Classification
Critical (Score: 9-10)
- Security vulnerabilities
- Production-breaking issues
- Legal/compliance violations
- Blocking issues for team productivity
High (Score: 7-8)
- Significant technical risk
- Major productivity impact
- Customer-visible quality issues
- Architecture limitations
Medium (Score: 4-6)
- Moderate productivity impact
- Code quality concerns
- Maintenance difficulties
- Minor security concerns
Low (Score: 1-3)
- Style and convention issues
- Documentation gaps
- Minor optimizations
- Cosmetic improvements
Impact Dimensions
Business Impact
- Customer Experience: User-facing quality and performance
- Revenue: Direct impact on business metrics
- Compliance: Regulatory and legal requirements
- Market Position: Competitive advantage considerations
Technical Impact
- Development Velocity: Speed of feature development
- Code Quality: Maintainability and reliability
- System Reliability: Uptime and performance
- Security Posture: Vulnerability and risk exposure
Team Impact
- Developer Productivity: Individual efficiency
- Team Morale: Job satisfaction and engagement
- Knowledge Sharing: Team collaboration and learning
- Onboarding Speed: New team member integration
Effort Estimation Guidelines
T-Shirt Sizing
- XS (1-4 hours): Simple fixes, documentation updates
- S (1-2 days): Minor refactoring, simple feature additions
- M (3-5 days): Moderate refactoring, component changes
- L (1-2 weeks): Major refactoring, architectural changes
- XL (3+ weeks): System-wide changes, major migrations
Complexity Factors
- Technical Complexity: How difficult is the change technically?
- Business Risk: What's the risk if something goes wrong?
- Testing Requirements: How much testing is needed?
- Team Knowledge: Does the team understand this area well?
- Dependencies: How many other systems/teams are involved?
Usage Guidelines
When Classifying Debt
1. Start with primary category (code, architecture, test, etc.) 2. Identify specific subcategory for precise tracking 3. Assess severity based on business and technical impact 4. Estimate effort using t-shirt sizing 5. Tag with relevant impact dimensions
Consistency Rules
- Use consistent terminology across teams
- Document custom categories for domain-specific debt
- Regular reviews to ensure classification accuracy
- Training for team members on taxonomy usage
Review and Updates
- Quarterly review of taxonomy relevance
- Add new categories as patterns emerge
- Remove unused categories to keep taxonomy lean
- Update severity and impact criteria based on experience
This taxonomy should be adapted to your organization's specific context, technology stack, and business priorities. The key is consistency in application across teams and over time.
Technical Debt Prioritization Framework
Introduction
Technical debt prioritization is a critical capability that separates high-performing engineering teams from those struggling with maintenance burden. This framework provides multiple approaches to systematically prioritize technical debt based on business value, risk, effort, and strategic alignment.
Core Principles
1. Business Value Alignment
Technical debt work must connect to business outcomes. Every debt item should have a clear story about how fixing it supports business goals.
2. Evidence-Based Decisions
Use data, not opinions, to drive prioritization. Measure impact, track trends, and validate assumptions with evidence.
3. Cost-Benefit Optimization
Balance the cost of fixing debt against the cost of leaving it unfixed. Sometimes living with debt is the right business decision.
4. Risk Management
Consider both the probability and impact of negative outcomes. High-probability, high-impact issues get priority.
5. Sustainable Pace
Debt work should be sustainable over time. Avoid boom-bust cycles of neglect followed by emergency remediation.
Prioritization Frameworks
Framework 1: Cost of Delay (CoD)
Best For: Teams with clear business metrics and well-understood customer impact.
Formula: Priority Score = (Business Value + Urgency + Risk Reduction) / Effort
Components:
Business Value (1-10 scale)
- Customer impact: How many users affected?
- Revenue impact: Direct effect on business metrics
- Strategic value: Alignment with business goals
- Competitive advantage: Market positioning benefits
Urgency (1-10 scale)
- Time sensitivity: How quickly does value decay?
- Dependency criticality: Does this block other work?
- Market timing: External deadlines or windows
- Regulatory pressure: Compliance requirements
Risk Reduction (1-10 scale)
- Security risk mitigation: Vulnerability reduction
- Reliability improvement: Stability gains
- Compliance risk: Regulatory issue prevention
- Technical risk: Architectural problem prevention
Effort Estimation
- Development time in story points or days
- Risk multiplier for uncertainty (1.0-2.0x)
- Skill requirements and availability
- Cross-team coordination needs
Example Calculation:
Authentication module refactor:
- Business Value: 8 (affects all users, blocks SSO)
- Urgency: 7 (blocks Q2 enterprise features)
- Risk Reduction: 9 (high security risk)
- Total Numerator: 24
- Effort: 3 weeks = 15 story points
- CoD Score: 24/15 = 1.6Framework 2: Weighted Shortest Job First (WSJF)
Best For: SAFe/Agile environments with portfolio-level planning.
Formula: WSJF = (Business Value + Time Criticality + Risk Reduction) / Job Size
Scoring Guidelines:
Business Value (1-20 scale)
- User/business value from fixing this debt
- Direct revenue or cost impact
- Strategic importance to business objectives
Time Criticality (1-20 scale)
- How user/business value declines over time
- Dependency on other work items
- Fixed deadlines or time-sensitive opportunities
Risk Reduction/Opportunity Enablement (1-20 scale)
- Risk mitigation value
- Future opportunities this enables
- Options this preserves or creates
Job Size (1-20 scale)
- Relative sizing compared to other debt items
- Include uncertainty and risk factors
- Consider dependencies and coordination overhead
WSJF Bands:
- Highest (WSJF > 10): Do immediately
- High (WSJF 5-10): Next quarter priority
- Medium (WSJF 2-5): Planned work
- Low (WSJF < 2): Backlog
Framework 3: RICE (Reach, Impact, Confidence, Effort)
Best For: Product-focused teams with user-centric metrics.
Formula: RICE Score = (Reach × Impact × Confidence) / Effort
Components:
Reach (number or percentage)
- How many developers/users affected per period?
- Percentage of codebase impacted
- Number of features that would benefit
Impact (1-3 scale)
- 3 = Massive impact
- 2 = High impact
- 1 = Medium impact
- 0.5 = Low impact
- 0.25 = Minimal impact
Confidence (percentage)
- How confident are you in your estimates?
- Based on evidence, not gut feeling
- 100% = High confidence with data
- 80% = Medium confidence with some data
- 50% = Low confidence, mostly assumptions
Effort (story points or person-months)
- Total effort from all team members
- Include design, development, testing, deployment
- Account for coordination and communication overhead
Example:
Legacy API cleanup:
- Reach: 5 teams × 4 developers = 20 people per quarter
- Impact: 2 (high - significantly improves developer experience)
- Confidence: 80% (have done similar cleanups before)
- Effort: 8 story points
- RICE: (20 × 2 × 0.8) / 8 = 4.0Framework 4: Technical Debt Quadrants
Best For: Teams needing to understand debt context and strategy.
Based on Martin Fowler's framework, categorize debt into quadrants:
Quadrant 1: Reckless & Deliberate
- "We don't have time for design"
- Strategy: Immediate remediation
- Priority: Highest - created knowingly with poor justification
Quadrant 2: Prudent & Deliberate
- "We must ship now and deal with consequences"
- Strategy: Planned remediation
- Priority: High - was right decision at time, now needs attention
Quadrant 3: Reckless & Inadvertent
- "What's layering?"
- Strategy: Education and process improvement
- Priority: Medium - focus on preventing more
Quadrant 4: Prudent & Inadvertent
- "Now we know how we should have done it"
- Strategy: Opportunistic improvement
- Priority: Low - normal part of learning
Framework 5: Risk-Impact Matrix
Best For: Risk-averse organizations or regulated environments.
Plot debt items on 2D matrix:
- X-axis: Likelihood of negative impact (1-5)
- Y-axis: Severity of negative impact (1-5)
Priority Quadrants:
- Critical (High likelihood, High impact): Immediate action
- Important (High likelihood, Low impact OR Low likelihood, High impact): Planned action
- Monitor (Medium likelihood, Medium impact): Watch and assess
- Accept (Low likelihood, Low impact): Document decision to accept
Impact Categories:
- Security: Data breaches, vulnerability exploitation
- Reliability: System outages, data corruption
- Performance: User experience degradation
- Compliance: Regulatory violations, audit findings
- Productivity: Team velocity reduction, developer frustration
Multi-Framework Approach
When to Use Multiple Frameworks
Portfolio-Level Planning:
- Use WSJF for quarterly planning
- Use CoD for sprint-level decisions
- Use Risk-Impact for security review
Team Maturity Progression:
- Start with simple Risk-Impact matrix
- Progress to RICE as metrics improve
- Advanced teams can use CoD effectively
Context-Dependent Selection:
- Regulated industries: Risk-Impact primary, WSJF secondary
- Product companies: RICE primary, CoD secondary
- Enterprise software: CoD primary, WSJF secondary
Combining Framework Results
Weighted Scoring:
Final Priority = 0.4 × CoD_Score + 0.3 × RICE_Score + 0.3 × Risk_ScoreTier-Based Approach: 1. Security/compliance items (Risk-Impact) 2. High business value items (RICE/CoD) 3. Developer productivity items (WSJF) 4. Technical excellence items (Quadrants)
Implementation Guidelines
Setting Up Prioritization
Step 1: Choose Primary Framework
- Consider team maturity, organization culture, available data
- Start simple, evolve complexity over time
- Ensure framework aligns with business planning cycles
Step 2: Define Scoring Criteria
- Create rubrics for each scoring dimension
- Use organization-specific examples
- Train team on consistent application
Step 3: Establish Review Cadence
- Weekly: New urgent items
- Bi-weekly: Sprint planning integration
- Monthly: Portfolio review and reprioritization
- Quarterly: Framework effectiveness review
Step 4: Tool Integration
- Use existing project management tools
- Automate scoring where possible
- Create dashboards for stakeholder communication
Common Pitfalls
Analysis Paralysis
- Problem: Spending too much time on perfect prioritization
- Solution: Use "good enough" decisions, iterate quickly
Ignoring Business Context
- Problem: Purely technical prioritization
- Solution: Always include business stakeholder perspective
Inconsistent Application
- Problem: Different teams using different approaches
- Solution: Standardize framework, provide training
Over-Engineering the Process
- Problem: Complex frameworks nobody uses
- Solution: Start simple, add complexity only when needed
Neglecting Stakeholder Buy-In
- Problem: Engineering-only prioritization decisions
- Solution: Include product, business stakeholders in framework design
Measuring Framework Effectiveness
Leading Indicators:
- Framework adoption rate across teams
- Time to prioritization decision
- Stakeholder satisfaction with decisions
- Consistency of scoring across team members
Lagging Indicators:
- Debt reduction velocity
- Business outcome improvements
- Technical incident reduction
- Developer satisfaction improvements
Review Questions: 1. Are we making better debt decisions than before? 2. Do stakeholders trust our prioritization process? 3. Are we delivering measurable business value from debt work? 4. Is the framework sustainable for long-term use?
Stakeholder Communication
For Engineering Leaders
Monthly Dashboard:
- Debt portfolio health score
- Priority distribution by framework
- Progress on high-priority items
- Framework effectiveness metrics
Quarterly Business Review:
- Debt work business impact
- Framework ROI analysis
- Resource allocation recommendations
- Strategic debt initiative proposals
For Product Managers
Sprint Planning Input:
- Debt items affecting feature velocity
- User experience impact from debt
- Feature delivery risk from debt
- Opportunity cost of debt work vs features
Roadmap Integration:
- Debt work timing with feature releases
- Dependencies between debt work and features
- Resource allocation for debt vs features
- Customer impact communication
for Executive Leadership
Executive Summary:
- Overall technical health trend
- Business risk from technical debt
- Investment recommendations
- Competitive implications
Key Metrics:
- Debt-adjusted development velocity
- Technical incident trends
- Customer satisfaction correlations
- Team retention and satisfaction
This prioritization framework should be adapted to your organization's context, but the core principles of evidence-based, business-aligned, systematic prioritization should remain constant.