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

SignalWhat it checksBoundary of the conclusion
Source structurecomplexity, duplication, legacy paths, large modulesdoes not mean the code has a defect
Tests and coveragemissing scenarios, weak assertions, coverage gapscoverage is not equivalent to behavioral quality
Change history and ownershipGit churn, missing owner, frequent emergency changesfrequent changes may be expected development
Configuration and buildwarnings, precedence, feature flags, dependency drifta warning needs classification and impact analysis
Known reportsTODO/FIXME, incidents, user reports, discrepancya report is input for verification, not a root cause

Examples of evidence-backed signals

  • mrr-engine/MrrFormulas.java has Git churn that should be compared with the formula, tests, and the reported discrepancy;
  • subscriptions/SubscriptionService.java should be checked together with tests/integration/MrrSnapshotIT.java, rather than drawing a conclusion from the service name alone;
  • legacy/OldBillingUtils.java is a broad-impact signal if several flows call it, but weak tests leave its behavior unknown;
  • PaymentRetryService.java and reporting/ReportCsvFormatter.java need 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.

Examples of collecting signals without edits
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

  1. Collect a broad list of possible indicators.
  2. Discard signals without a clear evidence anchor.
  3. Combine duplicates so one thought does not appear multiple times.
  4. Keep at most five signals with the strongest combination of impact and uncertainty.
  5. Record one risk and one next step for each.
  6. 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