Code Health: The Complete Guide to Metrics and Scores (2026)

Raghav ChamadiyaUpdated 11 min read
Compared in this post: repowise and
  • SonarQube Server
  • CodeScene
  • Qlty
On this page

Code health metrics measure how risky a file is to change. The useful ones combine code shape (cyclomatic complexity, nesting depth, function length), coupling, test coverage and git history (churn, ownership, recent bug fixes). repowise rolls 23 of them into a 1-to-10 score per file: 8.5 and above is excellent, below 4.0 is at risk.

Code health metrics at a glance

Four tools publish a headline code quality number, and they answer different questions. The table compares how each defines it, as of October 2026, with each vendor's own documentation linked below.

ToolHeadline metricScaleUses git history?
SonarQube ServerMaintainability rating from the technical debt ratio (remediation cost divided by development cost)A to E (A is 5% or less)No
CodeSceneCode Health, aggregated from 25+ factors, weighted by lines of codeNumeric, color-bandedYes (hotspots, team factors)
QltyMaintainability rating from the technical debt ratio at project level, a log of total debt per fileA to FNo
repowiseDefect-risk score from 23 markers, with maintainability and performance as separate signals1 to 10, five absolute bandsYes, git-derived markers are first-class

Scroll the table sideways to see every column.

Sources: SonarQube metric definitions, CodeScene code health docs, Qlty maintainability metrics.

I build repowise, so the deep dive uses its metrics: I can say exactly how each is computed. The definitions carry over to any tool that measures the same things. For a side-by-side of the platforms, see best code health tools in 2026.

What is code health?

Code health is a per-file estimate of how likely a file is to cause bugs and how hard it is to change. repowise computes it from static checks on the parse tree and the dependency graph plus git history. The repo score is the average across files, weighted by lines of code.

The score is deterministic: the same inputs always give the same number, with no model and no LLM anywhere. The 23 markers behind the headline sit inside a wider set of 59 detectors that also drive the maintainability and performance signals. Analysis is budgeted at under 30 seconds for 3,000 files, and a CI test enforces it.

A rolled-up average hides the one file slowing delivery down. Code health puts the reason next to the number, so you can open any file and see which markers lowered its score.

repowise file page for spec.py in its own repository, showing a code health score of 8.3 out of 10 with five open findings and 59 dependents
repowise file page for spec.py in its own repository, showing a code health score of 8.3 out of 10 with five open findings and 59 dependents

The code health metrics, defined

These are the metrics that move the headline score, with the thresholds the scorer uses. "Fires" means the metric produces a finding and deducts from the file's score. A healthy file is one where none fire, or only at low severity.

MetricWhat it measuresHow it is computedFires when
Complex methodBranchy functionsCyclomatic complexity (independent paths) per functionComplexity is 9 or more
Nested complexityDeeply nested logicMaximum control-flow depth in a functionDepth reaches 4; severity rises at 5 and 7
Bumpy roadSeveral separate nested chunks in one functionCount of distinct medium-depth nesting humpsMultiple humps in an already branchy function
Large methodLong functions with real logicLines per function, only when it also branchesOver 60 lines
God classClasses that do too muchClass size, method count, brain method inside200+ lines, 15+ methods, and a brain method
Complex conditionalHard-to-read conditionsBoolean operators in one if, while, for or ternary3 or more operators
Function hotspotComplex functions that keep changingPer-function complexity joined with git blameComplex and frequently modified
Brain methodCentral functions that are long and branchyLength, complexity, dependents of the file70+ lines, complexity 9+, 8+ dependents
Low cohesionClasses that want splittingLCOM4: method groups sharing no fields2 or more separate groups
Long parameter listSignatures carrying raw valuesParameter count per function5 or more in a non-trivial file
DRY violationDuplicated codeDuplicate blocks, weighted up when copies change togetherSignificant duplication
Error handlingSwallowed or ignored errorsEmpty or catch-all handlers, Rust unwrap/panic!, ignored Go errorsAny; capped at half a point
Co-change scatterShotgun surgeryDistinct files this one changes with in git historyMany co-change partners
Knowledge lossBus factor of oneMain author's share of commits, and whether they are still activeMain owner has effectively left
Untested hotspotCentral, busy code with no testsChurn plus dependents, joined with coverage or a matching testBusy, depended on, untested
Coverage gapReal uncovered surfaceLine coverage from your reportLarge uncovered share in a non-trivial file
Coverage gradientCoverage as a continuous signalDeduction proportional to the uncovered fractionAny uncovered fraction, scaled
Large assertion blockTests checking too much at onceConsecutive assertions in one test15 or more in a row
Duplicated assertion blockCopy-pasted test logicRepeated assertion sequences across testsSame sequence in several places
Churn riskRewritten faster than its size suggestsChurn divided by lines of codeUnusually high size-normalized churn
Change entropyScattered change historyHow spread out the commits touching the file areChanges arrive in wide, noisy commits
Code age volatilityDormant code woken upTime since last change against recent activityOld, stable code changing again
Developer congestionToo many hands at onceActive contributors in 90 days, and whether one owns itMany active authors, no clear owner
Ownership riskFragmented ownershipAuthors who each own under 5% of commitsMany drive-by authors, no clear owner
Prior defectRecent bug fixesBug-fix commits that touched the fileRecent fix history

Scroll the table sideways to see every column.

Weights differ because the scorer was calibrated against real bug history. Smells that fire often but predict bugs weakly (low cohesion, long parameter list, DRY violation, error handling) count at reduced weight in the defect score, and in full in maintainability. Brain method and repeated nesting are listed as advisory findings and do not deduct. Co-change scatter, change entropy and ownership risk carry the most weight. The marker tour walks through the full roster.

How metrics become a score

Each file starts at 10 and every finding deducts from it, with a cap per category. The caps stop one kind of problem from dominating:

CategoryCap
Git-derived (organizational)3.5
Structural complexity2.5
Test coverage, coverage gradient2.0 each
Size1.5
Duplication1.0
Test quality, error handling0.5 each

Scroll the table sideways to see every column.

The result is clamped between 1 and 10. History amplifies code risk and never stands alone: a file whose code has no findings cannot drop below 9.0 from history, so a busy but clean file is read as busy, not broken.

Score bands

The bands are absolute, so a 6 means the same thing in every repository.

BandScoreWhat it means
Excellent8.5 and aboveLow risk, easy to change
Good7.0 to 8.5Sound, nothing demanding attention
Fair5.5 to 7.0Rising complexity or process risk
Needs work4.0 to 5.5Worth scheduling
At riskBelow 4.0Where defects concentrate

Scroll the table sideways to see every column.

Three numbers summarize a repository: average health (line-weighted), hotspot health (the same average over hotspot files only) and the worst performer. Read average health first. A file in an unsupported language is counted as not analysed, never scored as a 10.

The three signals: defect risk, maintainability, performance

repowise keeps three co-equal signals and never blends them into one number. They come from one stream of findings, each with its own weights.

SignalWhat it answersHeadline?
Code health (defect risk)Which files are most likely to carry the next bugYes: the number, band and badge
MaintainabilityHow hard the code is to read and changeNo, a co-equal view
Performance riskWhere the structure wastes work (N+1 queries, I/O in loops)No, a co-equal view

Scroll the table sideways to see every column.

Defect risk is the validated signal, fitted against a defect corpus. Maintainability is set by hand and never fitted to bugs, so long methods, primitive obsession and duplication show up there without diluting the bug signal. The performance scan favors precision over recall: fewer findings, fewer false alarms. All three are deterministic.

How code health differs from a technical debt ratio

A debt ratio counts rule violations on one snapshot; code health weighs git history as heavily as structure. SonarQube Server and Qlty both divide estimated remediation effort by the cost to develop the code, then map the ratio to a letter. It is a tidy number, but it is built from a single snapshot of the code.

DimensionTypical debt ratiorepowise code health
InputsRule violations on one snapshot59 detectors across structure, coupling, tests, git history and performance
DeterminismDeterministicDeterministic, no LLM
HistoryLimitedChurn, entropy, ownership, prior defects are first-class
Signal splitOne blended numberThree signals; only defect risk is the headline
Defect validationNot published by the vendors aboveROC AUC 0.74 on an open benchmark
LicenseMostly proprietaryAGPL-3.0, self-hostable

Scroll the table sideways to see every column.

Does a code health score predict bugs?

Yes: on a leakage-free benchmark, repowise scores reach ROC AUC 0.74 across 21 open-source repositories and nine languages. We scored each repo at a historical commit, then checked the files against the next six months of bug fixes. Nothing after that commit feeds the score.

Under a fixed review budget of 20% of lines, the score surfaces 2.3x the defects CodeScene does on the same files, and its effort-aware ranking (Popt) is 0.607 on the same corpus. It also beats ranking by recent churn, by +0.10 AUC, and on the external PROMISE jEdit dataset it holds at 0.76 to 0.78.

The gain is in ordering a fixed review budget and saying why. The benchmark is open and reproducible: the full method, confounds and per-repository results are in the validation study, and you can run it on your own repositories. See also why process metrics beat structural metrics.

How to track code health over time

Score every file on each merge and watch the trend, not a single snapshot. repowise stores a snapshot on every init, update and health --recompute (the last 50 per repository) and raises three alerts:

  • Declining: the score fell 0.5 or more against five snapshots back.
  • Predicted decline: three falls in a row.
  • History drag: either of the above, where only the git-history half moved, so there is nothing in the code to act on.
bash
repowise init              # full index; scores every file
repowise health            # fix first, KPIs, lowest-scoring files
repowise health --trend    # the last 10 snapshots
repowise update            # re-scores only the files that changed

To see whether refactoring helped even while its churn raises the history half, read the code-shape view with repowise health --counts code_shape. More on reading the series in spotting declining code health trends.

Using the score

Start with the worst files that also change often. Sort by lowest defect-risk score, filter to high churn or high fan-in, and inspect the top three to five. The score says where; the marker breakdown says why.

repowise health leads with a short ranked "Fix first" list. Each item is one unit of work with the first edit, the expected gain, the effort and the tests that check it:

text
Fix first (3 of 41 eligible items)
 1. Extract the retry branch from parse_config  now, effort M, +1.4 health
    src/config/loader.py:212
    CCN 47 and nesting 6 in a file changed 19 times this quarter.
    verify: pytest tests/unit/test_loader.py

Then pick the move that fits the file: add tests before touching a fragile hotspot, schedule cleanup for a file that is both complex and volatile, or split a boundary where co-change pressure says the module shape no longer matches reality. Agents get the same data through the get_health MCP tool, one of the ten tools repowise exposes.

To gate pull requests on the same signals, use the PR bot. Coverage reports (LCOV, Cobertura, Clover, JaCoCo, Go coverprofile) feed the coverage markers: repowise coverage add coverage.lcov.

Go deeper

Last reviewed: October 2026.

FAQ

What are code health metrics?
Code health metrics are per-file measurements that predict how risky and costly the next change will be. They cover code shape (cyclomatic complexity, nesting depth, function and class size), design (cohesion, duplication, error handling), coupling, test coverage, and git history (churn, change entropy, ownership, recent bug fixes). Tools roll them into one score; in repowise it is 1 to 10 per file.
How many markers does the code health score use?
The headline defect-risk score is built from 23 deterministic markers spanning structure, git history and test coverage, with no model in the loop. They sit within 59 detectors once the maintainability and performance signals are included. The same inputs always produce the same score.
Does the code health score predict bugs?
Yes, within measured limits. On a leakage-free benchmark of 21 open-source repositories in nine languages the score reached ROC AUC 0.74 and surfaced 2.3x the defects of CodeScene under a fixed review budget. The benchmark is open, so you can reproduce it on your own repositories.
What is a good code health score?
On repowise's 1-to-10 scale, 8.5 and above is excellent, 7.0 to 8.5 is good, and below 4.0 is at risk. The bands are absolute, so they mean the same thing in every repository. Files below 4.0 are where defects concentrate in the benchmark corpus.
How do you track code health metrics over time?
Score every file on each merge and watch the trend. repowise update rescores only changed files, and repowise health --trend prints the last 10 snapshots with declining, predicted-decline and history-drag alerts. Start with lowest-scoring files that also change often.
How is code health different from a technical debt ratio?
A debt ratio, as used by SonarQube Server and Qlty, divides estimated remediation effort by development cost for a single snapshot. Code health scores each file from structure plus git history, keeps defect risk, maintainability and performance as separate signals, and publishes how well the score ranks real bug fixes.
Is it fast enough to run in CI?
Yes. The scorer makes no LLM calls and the full analysis is budgeted at under 30 seconds on a 3,000-file repository, enforced by a test. repowise is AGPL-3.0 and self-hostable, so you can run it as a merge gate without sending code to a third party.