Inventorying technical debt and ordering repayment by measured interest: touch frequency, blast radius, comprehension cost. Use to decide what to fix first and justify not fixing the rest.
Installs into .claude/skills of the current project.
Are you the author of Quality Debt?
Add the live security badge to your README. It updates with every re-scan.
[](https://www.skillsdirectory.com/skills/simota-quality-debt)
---
name: quality-debt
description: "Inventorying technical debt and ordering repayment by measured interest: touch frequency, blast radius, comprehension cost. Use to decide what to fix first and justify not fixing the rest."
allowed-tools: Read, Grep, Glob, Bash, Write
---
<!-- quality:contract -->
## Owns
A ledger of what the codebase will cost to keep changing, ordered by measured
interest, plus the reasoning for everything deliberately left alone. It
sequences and justifies; **it never implements the repayment**.
Phases: `INTAKE → MEASURE → SCORE → SEQUENCE → EMIT`.
## Before starting
- **Get the numbers before the ranking.** Touch frequency comes from git, blast
radius from imports; incidents from the tracker go in `Cost today`, not the
score. An input that cannot be measured is stated as unmeasured and the
ranking is presented as partial
- **Separate deliberate debt from accidental rot.** Taken-for-a-reason with a
repayment condition, and nobody-meant-this, rank and repay differently
- **Read the existing ledger and carry `first seen` dates forward.** The age of
an entry is data
<!-- deliver:sizing -->
- **Size it before anything else**, first match wins. `T0` — one skill owns it, one file or
one number, the question fits in one sentence: answer in a line that still carries the sweep,
**no brief, no handoff payload**. `T1` — a `T0` condition fails: settle the brief first. `T2` —
two or more skills own parts of it, or the verdict depends on another's output: route it. `T0`
drops the paperwork, **never the evidence floor**. Mis-sized mid-run means re-sizing and saying so
- **Scale the checks, not the standard.** Run the narrowest check that could
falsify the claim, and **say which checks were deliberately skipped** — a
silent skip reads as coverage that was never there
- **A dialogue comes first** when the deliverable's shape is not uniquely
determined, when a threshold is implied but unstated ("enough coverage", "good
enough to ship" are numbers somebody has to choose), or when the work would set
a gate that blocks other people. `excludes` may not be empty and `floor` is
agreed before the work, not after (`_quality/SIZING.md`)
- **A term with two meanings, or a concept with two names, is a question, never
a silent choice** — one question with its default, the answer into the
brief's `terms` and `.agents/glossary.md`, and the glossary's names only from
then on (`_quality/SIZING.md` § Terms)
<!-- /deliver:sizing -->
## Decide first
| Situation | How to proceed |
|---|---|
| Deciding whether something is debt at all | [what-counts](playbooks/what-counts.md) — ugliness nobody touches costs nothing |
| Naming the kind | [debt-taxonomy](reference/debt-taxonomy.md) |
| Scoring what it costs to leave | [interest](reference/interest.md) |
| Sequencing the work | [repayment](reference/repayment.md) |
| About to propose an order | [traps](playbooks/traps.md) |
| The hot code has no tests | It ranks **above** tested hot code — every change to it is a gamble. But its repayment **starts** with characterisation tests, never with restructuring. Rank order and work order are different questions |
| An entry is not being repaid | It carries the condition that would change that. "Won't fix" without a condition is a decision nobody can revisit |
| The proposal exceeds roughly a week | That is a planning decision, not a quality verdict. Ask |
| A claim here would be expensive to get wrong | [refute](refute.py) — put it to the engines that did not make it, asked to break it rather than to agree. Unrefuted is n engines finding nothing, never proof |
<!-- deliver:values -->
- Ties break by `_quality/VALUES.md`, read top to bottom: honesty over speed ·
mechanism over intent · **independence over throughput** · subtraction over
addition · what is measured over what is believed · the human decides what,
the agent decides how. Against all of them: **a harness that is correct and
avoided has failed** — this pack is the heaviest of its kind, and when the
discipline costs more than the check, say so rather than performing it
<!-- /deliver:values -->
## Always / Never
- Always: state cost in observable units — minutes to understand, places a
change must be made, incidents attributable, changes blocked
- Always: put characterisation tests first in any repayment that restructures.
Refactoring untested code is how quality initiatives cause incidents
- Always: state what the ledger does not cover
- Always: get permission first before proposing more than about a week of work,
before any repayment that changes a public interface or a data schema, or
before declaring something permanently "won't fix"
- Never: implement the repayment. Emit a sequenced plan and fix directives
- Never: rank by how bad the code looks. The metric is what the next change
costs, and beautiful code in a file nobody opens costs nothing to leave alone
- Never: propose a large refactor of untested code as the first step. The first
step is the tests
- Never: produce the numbers yourself and then rank on them in the same breath
without saying which came from where
- Never: write outside `.agents/quality/` — the ledger, the fix directives and
this skill's journal are the whole of what it owns. Holding `Write` is not
permission to touch the code the ledger is about
## Verify with
`touch_score` and `blast_score` are `E1` at minimum — each names the command it
came from (`git log`, an import graph). `comprehension_score` is the one estimate
(`E0`), allowed only because `_quality/SEVERITY.md` §4 defines it so: it is flagged
`ESTIMATED`, never partial. Any other input that is felt rather than measured is
stated as unmeasured, and the ranking says it is partial.
- **A ranking whose inputs are unmeasured is an opinion with a sort order.**
Say which entries rest on complete data and which do not
<!-- deliver:report -->
- **Every claim carries its actual rung and is warranted for that claim** (`_quality/CONTRACT.md`
§1-3): `E0` reasoning alone never ships · `E1` static · `E2` execution · `E3` automated test ·
`E4` independent oracle · `E5` integration · `E6` production. A command that ran proves nothing
about a different claim; `E4` needs a traced independent expectation, not a different agent
- **A claim that cannot reach its floor is not downgraded and shipped anyway** — it is a
`HYPOTHESIS` with the observation or safe check that would settle it. A bounded `E1` proof may
establish a defect; missing evidence never does. Narrowing a claim does not close the
original question's unresolved parts
- **Report `status`**: `DONE` (every claim warranted, every residual classified) / `PARTIAL` / `BLOCKED`
- **Every residual is `BLOCKED` / `OUT-OF-SCOPE` / `DEFERRED` / `HYPOTHESIS`**
and appears in the handoff's `residuals`; where this skill's own write scope reaches the place a
reader would next look, a `#TODO(agent):` marker carrying that class goes there too
- **Never omit the sweep** — markers against `residuals`, claims made against claims warranted:
`swept, 0 markers; 9 claims / 9 warranted`. While either pair disagrees the status is not `DONE`
<!-- /deliver:report -->
<!-- deliver:outcome -->
- **For findings emitted or adjudicated, record the outcome**: `real` · `refuted` · `accepted` ·
`moot` · `open`. Refutation needs checked evidence; disagreement stays `open`. Report
`real / (real + refuted)` with all five counts and its scope, source and method; with a zero
denominator it is undefined. A rate of one is not suspicious by itself — read it against `open`,
and never manufacture findings to have something to adjudicate. A run with no findings owes no
precision report (`_quality/OUTCOMES.md`)
<!-- /deliver:outcome -->
## Done when
Every entry names its kind, its measured interest inputs and their sources, its
cost in observable units, and — where it is not being repaid — the condition
that would change that; and the ledger says what it does not cover.
<!-- deliver:surface -->
- **Say what the moment needs.** Start: one line naming what will be checked and what is
excluded. Mid-run: a line whenever the reader must act now — a finding that changes the verdict,
a blocked path, work that would grow the scope. Asking counts as speaking: one question, the
decision it unblocks, the default taken if nobody answers
- **End with the verdict in one line** — status, and the finding that matters; then the sweep
line, then one line per residual a human must decide, then what is next
- **The payload is the record, the report is the view.** Every finding, rung and outcome lives
there; ten findings with two that matter are reported as the two and the count of the rest
- **The report is the four parts above and nothing else** — verdict, sweep, residuals, next; the
findings file is named, never reproduced. It carries only what the payload does not, and its
length follows the residuals a human must decide (`_quality/REPORT.md`)
- **Not bigger than it is.** The requested scope is the deliverable; thought goes deeper into the
one thing asked, never wider. **A real problem is the exception** — something that would break,
is unsafe, or rests on a false premise is explained in full (`_quality/REPORT.md`)
<!-- /deliver:surface -->