On this page
- Code health metrics at a glance
- What is code health?
- The code health metrics, defined
- How metrics become a score
- Score bands
- The three signals: defect risk, maintainability, performance
- How code health differs from a technical debt ratio
- Does a code health score predict bugs?
- How to track code health over time
- Using the score
- Go deeper
- FAQ
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.
| Tool | Headline metric | Scale | Uses git history? |
|---|---|---|---|
| SonarQube Server | Maintainability rating from the technical debt ratio (remediation cost divided by development cost) | A to E (A is 5% or less) | No |
| CodeScene | Code Health, aggregated from 25+ factors, weighted by lines of code | Numeric, color-banded | Yes (hotspots, team factors) |
| Qlty | Maintainability rating from the technical debt ratio at project level, a log of total debt per file | A to F | No |
| repowise | Defect-risk score from 23 markers, with maintainability and performance as separate signals | 1 to 10, five absolute bands | Yes, 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.

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.
| Metric | What it measures | How it is computed | Fires when |
|---|---|---|---|
| Complex method | Branchy functions | Cyclomatic complexity (independent paths) per function | Complexity is 9 or more |
| Nested complexity | Deeply nested logic | Maximum control-flow depth in a function | Depth reaches 4; severity rises at 5 and 7 |
| Bumpy road | Several separate nested chunks in one function | Count of distinct medium-depth nesting humps | Multiple humps in an already branchy function |
| Large method | Long functions with real logic | Lines per function, only when it also branches | Over 60 lines |
| God class | Classes that do too much | Class size, method count, brain method inside | 200+ lines, 15+ methods, and a brain method |
| Complex conditional | Hard-to-read conditions | Boolean operators in one if, while, for or ternary | 3 or more operators |
| Function hotspot | Complex functions that keep changing | Per-function complexity joined with git blame | Complex and frequently modified |
| Brain method | Central functions that are long and branchy | Length, complexity, dependents of the file | 70+ lines, complexity 9+, 8+ dependents |
| Low cohesion | Classes that want splitting | LCOM4: method groups sharing no fields | 2 or more separate groups |
| Long parameter list | Signatures carrying raw values | Parameter count per function | 5 or more in a non-trivial file |
| DRY violation | Duplicated code | Duplicate blocks, weighted up when copies change together | Significant duplication |
| Error handling | Swallowed or ignored errors | Empty or catch-all handlers, Rust unwrap/panic!, ignored Go errors | Any; capped at half a point |
| Co-change scatter | Shotgun surgery | Distinct files this one changes with in git history | Many co-change partners |
| Knowledge loss | Bus factor of one | Main author's share of commits, and whether they are still active | Main owner has effectively left |
| Untested hotspot | Central, busy code with no tests | Churn plus dependents, joined with coverage or a matching test | Busy, depended on, untested |
| Coverage gap | Real uncovered surface | Line coverage from your report | Large uncovered share in a non-trivial file |
| Coverage gradient | Coverage as a continuous signal | Deduction proportional to the uncovered fraction | Any uncovered fraction, scaled |
| Large assertion block | Tests checking too much at once | Consecutive assertions in one test | 15 or more in a row |
| Duplicated assertion block | Copy-pasted test logic | Repeated assertion sequences across tests | Same sequence in several places |
| Churn risk | Rewritten faster than its size suggests | Churn divided by lines of code | Unusually high size-normalized churn |
| Change entropy | Scattered change history | How spread out the commits touching the file are | Changes arrive in wide, noisy commits |
| Code age volatility | Dormant code woken up | Time since last change against recent activity | Old, stable code changing again |
| Developer congestion | Too many hands at once | Active contributors in 90 days, and whether one owns it | Many active authors, no clear owner |
| Ownership risk | Fragmented ownership | Authors who each own under 5% of commits | Many drive-by authors, no clear owner |
| Prior defect | Recent bug fixes | Bug-fix commits that touched the file | Recent 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:
| Category | Cap |
|---|---|
| Git-derived (organizational) | 3.5 |
| Structural complexity | 2.5 |
| Test coverage, coverage gradient | 2.0 each |
| Size | 1.5 |
| Duplication | 1.0 |
| Test quality, error handling | 0.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.
| Band | Score | What it means |
|---|---|---|
| Excellent | 8.5 and above | Low risk, easy to change |
| Good | 7.0 to 8.5 | Sound, nothing demanding attention |
| Fair | 5.5 to 7.0 | Rising complexity or process risk |
| Needs work | 4.0 to 5.5 | Worth scheduling |
| At risk | Below 4.0 | Where 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.
| Signal | What it answers | Headline? |
|---|---|---|
| Code health (defect risk) | Which files are most likely to carry the next bug | Yes: the number, band and badge |
| Maintainability | How hard the code is to read and change | No, a co-equal view |
| Performance risk | Where 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.
| Dimension | Typical debt ratio | repowise code health |
|---|---|---|
| Inputs | Rule violations on one snapshot | 59 detectors across structure, coupling, tests, git history and performance |
| Determinism | Deterministic | Deterministic, no LLM |
| History | Limited | Churn, entropy, ownership, prior defects are first-class |
| Signal split | One blended number | Three signals; only defect risk is the headline |
| Defect validation | Not published by the vendors above | ROC AUC 0.74 on an open benchmark |
| License | Mostly proprietary | AGPL-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.
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:
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
- What is code health? A tour of the markers
- Nested vs cyclomatic complexity
- Inside the code health scorer
- Best code health tools in 2026
- The code health feature page
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 updaterescores only changed files, andrepowise health --trendprints 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.

