# Tech Debt Analysis

> Analyze codebase for structural tech debt using software design principles from Fowler's Refactoring, the Design Stamina Hypothesis, and the AWS Builders' Library

- Skill: `jankneumann/tech-debt-analysis` (Agent Skill, multi-file: 16 files)
- Install (CLI): `npx skillmds@latest add jankneumann/tech-debt-analysis`
- Raw SKILL.md: https://api.skillmd.com/api/skills/jankneumann/tech-debt-analysis/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: DevOps & Infra
- Author: jankneumann (https://skillmd.com/u/jankneumann)
- Updated: 2026-09-10
- Page: https://skillmd.com/skills/jankneumann/tech-debt-analysis

---


# Tech Debt Analysis

Perform a structural analysis of the codebase to identify tech debt — areas where design quality has degraded and future development velocity is at risk.

Grounded in principles from:
- **Martin Fowler's *Refactoring*** — code smell detection (Long Method, Large Class, Duplicated Code, Long Parameter List, etc.)
- **Design Stamina Hypothesis** — good design pays off by keeping development speed high over time
- **AWS Builders' Library** — minimize blast radius through loose coupling and clear module boundaries

This is a **read-only diagnostic skill** — it does not modify code. Use its output to prioritize refactoring work via `/plan-feature`.

## Arguments

`$ARGUMENTS` - Optional flags:
- `--analyzer <list>` (comma-separated analyzers; default: all)
- `--severity <level>` (minimum severity: critical, high, medium, low, info; default: low)
- `--project-dir <path>` (directory to analyze; default: auto-detect)
- `--out-dir <path>` (default: `docs/tech-debt`)
- `--format <md|json|both>` (default: both)
- `--no-parallel` (run analyzers sequentially)

Valid analyzers: `complexity`, `coupling`, `duplication`, `imports`

## Script Location

Scripts live in `<agent-skills-dir>/tech-debt-analysis/scripts/`. Each agent runtime substitutes `<agent-skills-dir>` with its config directory:
- **Claude**: `.claude/skills`
- **Codex**: `.codex/skills`
- **Gemini**: `.gemini/skills`

Installed skill copies are expected to include these scripts. If they are missing,
reinstall the skill from its canonical distribution rather than invoking a repo-local path.

## Prerequisites

- Python 3.11+
- For the `coupling` analyzer: architecture artifacts must exist (`docs/architecture-analysis/architecture.graph.json`). Run `/refresh-architecture` first if missing.
- No external dependencies — uses only Python stdlib (`ast`, `hashlib`, `json`, `pathlib`)

## Analyzers

### 1. Complexity Analyzer (`complexity`)

Uses Python's `ast` module to detect:

| Code Smell | Metric | Threshold | Critical | Reference |
|------------|--------|-----------|----------|-----------|
| Long Method | Function line count | 50 | 100 | Fowler: Extract Method |
| Large File / God File | File line count | 500 | 1000 | Fowler: Extract Class |
| Complex Function | McCabe cyclomatic complexity | 10 | 20 | Fowler: Decompose Conditional |
| Deep Nesting | Control-flow nesting depth | 4 | 6 | Fowler: Guard Clauses |
| Long Parameter List | Parameter count (excl. self/cls) | 5 | 8 | Fowler: Introduce Parameter Object |
| Too Many Definitions | Top-level classes + functions | 20 | 40 | SRP: Single Responsibility Principle |

### 2. Coupling Analyzer (`coupling`)

Reads from existing architecture artifacts to detect:

| Code Smell | Metric | Threshold | Reference |
|------------|--------|-----------|-----------|
| High Fan-out | Outgoing dependencies | 10 | Shotgun Surgery / Feature Envy |
| High Fan-in | Incoming dependents | 10 | Change Amplifier |
| Hub Node | High fan-in AND fan-out | 8 each | God Object / Blob |
| High Impact | Transitive dependents | 15 | AWS: Blast Radius |

**Requires**: `docs/architecture-analysis/architecture.graph.json` (from `/refresh-architecture`)

### 3. Duplication Analyzer (`duplication`)

Uses structural fingerprinting to detect copy-pasted code:

- Normalizes source (strip comments, collapse whitespace, abstract literals)
- Extracts sliding windows of 6 consecutive normalized lines
- Groups by fingerprint hash to find exact structural duplicates
- Reports cross-file vs same-file duplication

### 4. Import Analyzer (`imports`)

Builds a module-level import graph to detect:

| Code Smell | Description | Reference |
|------------|-------------|-----------|
| Circular Import | Cycles in the import graph | Fragile initialization order |
| Import Fan-out | Module importing 15+ other modules | Divergent Change |
| Star Import | `from X import *` | Namespace Pollution |

## Steps

### 0. Ensure Fresh Architecture Artifacts

The `coupling` analyzer reads `architecture.graph.json` rather than the source, so
its freshness is this skill's responsibility at the moment of reading — no gate or
sync point keeps it current on your behalf:

```bash
# Ensure architecture artifacts are current, immediately before the first read.
# `--ensure` is `--check` plus a staged refresh only when the check is not fresh,
# so on an already-fresh checkout it writes nothing. PYTHON must name the same
# interpreter this repository's architecture targets use: the check runs in-process
# and the pipeline runs in a subprocess, and if the two disagree about which
# optional grammars are importable they report permanent, unfixable drift.
ARCH_PY="${PYTHON:-python3}"
if "$ARCH_PY" "<agent-skills-dir>/refresh-architecture/scripts/run_architecture.py" --ensure --python "$ARCH_PY"; then
  ARCH_FRESHNESS="ensured"
else
  ARCH_FRESHNESS="DEGRADED"
  echo "DEGRADED: architecture artifacts could not be made current; the last known-good analysis is left intact but unverified. Report every architecture-derived finding below as unverified rather than as current." >&2
fi
```

The coupling analyzer also detects stale artifacts (> 7 days old) and warns in its
output, but that warning is a backstop: the ensure call above is what makes the
fan-in/fan-out figures describe the tree you are analyzing.

### 1. Run Orchestrator

```bash
python3 <agent-skills-dir>/tech-debt-analysis/scripts/main.py \
  --analyzer <analyzers-or-omit-for-all> \
  --severity <level> \
  --project-dir <path> \
  --out-dir docs/tech-debt \
  --format both
```

### 2. Review Report

The orchestrator produces:
- `docs/tech-debt/tech-debt-report.md` — human-readable report with hotspots, severity breakdown, and refactoring recommendations
- `docs/tech-debt/tech-debt-report.json` — machine-readable for downstream tools

### 3. Interpret Results

**Severity Levels** (descending): critical > high > medium > low > info

**Severity mapping**:
- Metric ≥ 2× threshold → **high** (active pain point)
- Metric ≥ threshold → **medium** (accumulating debt)
- Below threshold → not reported (unless severity filter is `info`)

**Hotspot files**: Files with the most findings across all analyzers. These are the best candidates for refactoring investment.

### 4. Next Steps

- **Quick wins**: Address high-severity Long Method and Complex Function findings — these directly impact bug rates
- **Structural**: Use hotspot files to plan Extract Class / Move Method refactorings
- **Coupling**: Hub nodes and high-impact nodes need stable interfaces before further feature work
- **Plan refactoring**: Create a `/plan-feature` proposal for significant refactoring efforts
- **Track over time**: Re-run periodically and compare JSON reports to measure design stamina

### 5. Remediation Routing

Do **not** send every finding to `/plan-feature`. Route by blast radius and skill contract:

| Finding class | Typical analyzers / smells | Next skill |
|---|---|---|
| Local clarity / complexity | Long Method, Deep Nesting, Complex Function (single file, small surface) | **`/simplify`** — behavior-preserving polish with coverage gate + dual-run |
| Local duplication | Same-file or few-file structural duplicates under Rule of 500 | **`/simplify`** (isomorphic extract) after characterization pins all sites |
| Structural redesign | Large Class / God File, multi-module Extract Class, high fan-out redesign | **`/plan-feature`** — needs proposal, design, review gates |
| Coupling hubs | High fan-in/out, hub nodes, high-impact transitive dependents | **`/plan-feature`** (stabilize interfaces first); optional `/refresh-architecture` before re-analysis |
| Dead / zombie public surfaces | Unused public API with external consumers, orphan systems | **`/deprecation-and-migration`** — Hyrum's Law + migration, not silent delete |
| Measured performance debt | Hot paths with budgets or known p95 pain | **`/performance-optimization`** — measure before rewrite |

**Quick-win rule of thumb:** if the fix fits Rule of 500 (≤500 lines, ≤5 files) and must not change behavior, prefer `/simplify`. If the change rewrites module boundaries or public contracts, plan it.

When citing a finding in a follow-up PR, include the finding ID from `tech-debt-report.json` so report → remediation stays traceable.

## Integration with Bug Scrub

This skill complements `/bug-scrub`:
- **Bug scrub** collects runtime signals (test failures, lint errors, type errors)
- **Tech debt analysis** collects structural signals (complexity, coupling, duplication)

Together, they provide a complete picture of codebase health. Run both before major planning sessions.

## Integration with Architecture Analysis

The `coupling` analyzer reads directly from `/refresh-architecture` artifacts. For best results:

1. Run `/refresh-architecture` to update the graph
2. Run `/tech-debt-analysis` to analyze structural quality
3. Review both reports together for a complete architectural assessment

## Quality Checks

```bash
python3 -m pytest <agent-skills-dir>/tech-debt-analysis/tests -q
```

## Common Rationalizations

| Rationalization | Why it's wrong |
|---|---|
| "Our CI doesn't fail on complexity, so high cyclomatic complexity isn't a problem" | The Design Stamina Hypothesis: design quality affects velocity over time, not pass/fail today. CI cares about *correctness now*; tech-debt analysis catches the *velocity decay* CI cannot see. |
| "Duplication is fine — the duplicated code is short" | Even short duplicates compound: a 6-line idiom copied 12 times becomes 72 lines that must change together at the next requirement shift. Fowler's Rule of Three exists to prevent that compounding. |
| "We'll fix the hub node when we have time" | Hub nodes have the largest blast radius (AWS Builders' Library); they degrade *every* dependent feature simultaneously. Refactor them first, not last. |
| "I'll skip refreshing architecture artifacts — the graph is probably fine" | The coupling analyzer reads stale fan-in/fan-out from a stale graph. Stale graph → stale findings → wrong refactoring priorities. The skill explicitly warns when artifacts are >7 days old; honor the warning. |
| "Star imports are a stylistic preference" | Star imports break the import analyzer's ability to detect what depends on what; they also defeat IDE rename refactoring. They are a real design defect, not style. |

## Red Flags

- A `tech-debt-report.json` produced without `docs/architecture-analysis/architecture.graph.json` being recent — the coupling analyzer either silently skipped or read stale data.
- The report shows zero findings from the `complexity` analyzer on a codebase >5k LOC — almost certainly the analyzer ran on the wrong `--project-dir` or excluded all source files.
- Hotspot files in the report are never cited in the next refactoring proposal — the analysis became theater.
- A refactoring PR that claims to address tech debt but does not reference a specific finding ID from the report — no traceability between report and remediation.
- Circular import findings are accepted with `# noqa` instead of resolved — fragile initialization order will eventually break in a new test runner / Python version.

## Verification

1. Confirm `docs/architecture-analysis/architecture.graph.json` exists and is <7 days old before running the `coupling` analyzer (the report's metadata includes a freshness flag — check it).
2. Confirm the report's `findings` array is non-empty for a non-trivial codebase, AND that at least two analyzers contributed findings (single-analyzer reports usually mean the others crashed silently).
3. Confirm any refactoring proposal derived from the report cites specific finding IDs (e.g., "addresses tech-debt-finding-12, tech-debt-finding-17") — traceable from report to remediation.
4. Confirm the hotspot-files list at the top of the report was used to scope the refactoring — picking a non-hotspot file usually means the analysis was ignored.
5. Confirm the report was re-run *after* the refactoring lands and the addressed findings disappeared (or moved below threshold) — closes the loop on Design Stamina.

