A technical-debt signal is an indicator, not proof of a defect
A static signal helps decide where deeper investigation is needed. It does not by itself prove a bug, a wrong design, or the need to refactor. For example, TODOs, low coverage, or frequent Git churn may have a legitimate explanation, so combine each signal with context and potential impact.
For one discovery cycle, limit the set to at most five strongest signals. Each signal should be one thought in the format: area + evidence + risk + next step.
Five classes of signals
| Signal | What it checks | Boundary of the conclusion |
|---|---|---|
| Source structure | complexity, duplication, legacy paths, large modules | does not mean the code has a defect |
| Tests and coverage | missing scenarios, weak assertions, coverage gaps | coverage is not equivalent to behavioral quality |
| Change history and ownership | Git churn, missing owner, frequent emergency changes | frequent changes may be expected development |
| Configuration and build | warnings, precedence, feature flags, dependency drift | a warning needs classification and impact analysis |
| Known reports | TODO/FIXME, incidents, user reports, discrepancy | a report is input for verification, not a root cause |
Examples of evidence-backed signals
mrr-engine/MrrFormulas.javahas Git churn that should be compared with the formula, tests, and the reported discrepancy;subscriptions/SubscriptionService.javashould be checked together withtests/integration/MrrSnapshotIT.java, rather than drawing a conclusion from the service name alone;legacy/OldBillingUtils.javais a broad-impact signal if several flows call it, but weak tests leave its behavior unknown;PaymentRetryService.javaandreporting/ReportCsvFormatter.javaneed different risk hypotheses: money recovery and external-format stability;application.yml, the JaCoCo report, and a TODO/FIXME search can explain configuration, coverage, and maintenance signals.
Commands are sources, not an automatic verdict
Record each command result with its date, scope, and limitation. Do not invent a coverage percentage or warning count if the command was not actually run. Mark a hypothesis as “hypothesis” and make the next step a concrete check: open a test, trace a caller, find an owner, or run a manual scenario.
git log --since="1 year ago" --oneline -- mrr-engine/MrrFormulas.java
./gradlew test jacocoTestReport
grep -R "TODO\|FIXME" -n legacy/Reduce the signal log to a useful set
- Collect a broad list of possible indicators.
- Discard signals without a clear evidence anchor.
- Combine duplicates so one thought does not appear multiple times.
- Keep at most five signals with the strongest combination of impact and uncertainty.
- Record one risk and one next step for each.
- Move consequences to RISK_MAP.md instead of turning the signal log into a backlog of every desired refactor.
Canonical lesson source · JavaRush
Open JavaRush material