In July 2026, we rebuilt the way GearCheck converts a blood panel into a single score, and the scores shifted accordingly. Under the current model, the median score across our user base is 62, and the practical ceiling sits at 97, not 100. The old model ran meaningfully higher across the board. Nobody got sicker overnight. The old number was flattering, and that flattery obscured exactly the cases that mattered most.
This article explains what the score actually measures, why building a single number honestly is genuinely hard, and where the current model still has limits you should know about. If you use GearCheck, this is the reasoning behind every number you see. If you do not, it is a reasonable template for interrogating any health score you are handed.
A blood panel gives you anywhere from fifteen to ninety separate measurements. Compress all of that into one integer and you're discarding information by definition. The only question that matters is whether you're discarding the right information.
Picture two athletes. The first one has eleven markers sitting slightly outside optimal: mildly elevated liver enzymes, a marginal lipid panel, unremarkable inflammation. Not a single one of those would prompt a phone call. The second athlete has ten markers dead-centre and one that is not: an eGFR of 48, meaning his kidneys are filtering at roughly half the rate they should.
Average the deviations and the first athlete scores worse. He has more things wrong. But the second athlete has stage 3 chronic kidney disease and does not know it. Any scoring model that rewards him for his nine good markers is not just imprecise, it is actively dangerous, because it delivers reassurance precisely where alarm was warranted.
💡A health score is only useful if it is hardest to get a good one when something is genuinely wrong.
Everything below follows from that design constraint. The model must be able to say: one thing here is bad enough that the rest does not rescue it.
Let's be direct about the previous version, because the failure is instructive and common.
The old pipeline had it backwards. A language model wrote the report first, and only afterward did anyone try to extract a score from the prose. A regular expression scanned the generated HTML for section headings and severity words, counted what it found, and turned that tally into a number. The narrative came first, and the score was reverse-engineered from it.
This works until it does not. If the model wrote three sentences about a borderline cholesterol reading and one clause about a critically low eGFR, the scraper counted three severity signals against one, so verbosity became weight. Worse, the score was not reproducible: the same panel run twice could produce different prose and therefore a different number, with no way to explain the gap to anyone.
The current architecture inverts that. A deterministic rules engine evaluates the panel and emits findings as objects: each one carries a rule identifier, a severity, the specific measurements that triggered it, and the mechanism connecting them. Those objects drive the score. Only afterwards does a language model turn them into readable prose, and it is constrained to the findings it was handed. It phrases; it does not select.
A rule table is finite, and a panel can show something no rule was written for. So after the rules have run, a model is shown the markers no finding covered and asked whether any of them warrant one. Those assessed findings appear in your report and are labelled as what they are. They do not touch your score.
Why an assessed finding cannot move your number
Each finding gets a severity rating from a fixed four-point vocabulary, and every level maps to a fixed fraction of that domain's risk budget. The list stays closed on purpose. An open-ended severity scale invites drift.
Severity vocabulary
| Marker | Level | Risk contribution |
|---|---|---|
| Critical | Organ function is measurably impaired, or a value sits in a range associated with acute events | 1.00 — the full risk weight of that domain |
| High | A clear pathological signal that warrants medical review, not just monitoring | 0.60 |
| Moderate | Outside the athletic target range with a plausible mechanism, but not yet clinical | 0.35 |
| Low | A drift worth watching; often the earliest useful signal | 0.15 |
Severity itself is continuous underneath. A marker does not jump from fine to moderate at a threshold; it ramps. Each marker has a distance parameter, internally we call it the full-deviation point, defining how far past its reference boundary a value must sit before it counts as maximally deviant for its severity band. An ALT of 45 U/L and an ALT of 400 U/L both sit above the reference range, and the model does not pretend they are the same event.
Not every marker gets scored, and that's intentional. Sodium reflects hydration and diet on the day of the draw. Absolute lymphocyte count shifts when you're dealing with a cold. These are descriptive values. They show up in your report with context, but they don't move the number. A score that swings on whether you drank enough water that morning is measuring the wrong thing.
Findings are grouped into ten physiological domains, and those domains don't all carry the same weight. That's a value judgement, and it should be stated plainly rather than buried: we weight by how irreversible the damage is and how strongly the domain predicts hard outcomes.
Domain weights
| Marker | Domain | Weight and reasoning |
|---|---|---|
| Kidneys | 0.186 | Nephron loss does not reverse. Damage accumulates silently for years and is usually detected too late. |
| Cardiovascular | 0.186 | The dominant cause of death in AAS-using populations, and the one most responsive to early action. |
| Blood | 0.140 | Haematocrit and viscosity drive acute events — stroke, embolism — on a timescale of weeks, not decades. |
| Liver | 0.112 | Serious, but genuinely reversible when the cause is removed. Weighted below kidneys for exactly that reason. |
| Metabolic | 0.112 | Insulin resistance is a strong long-horizon predictor and is highly modifiable. |
| Hormones | 0.084 | Central to how you feel and to long-term bone and cardiovascular health, but rarely the acute threat. |
| Inflammation | 0.065 | A powerful amplifier of other risks more than a standalone one — which is how the model uses it. |
| Thyroid | 0.045 | Consequential when genuinely disordered, but assay noise and non-thyroidal illness produce many false signals. |
| Iron | 0.040 | Ferritin and saturation move with donation, blast and inflammation. Real, common and correctable — which is why it carries weight instead of sitting in a footnote. |
| Vitamins | 0.030 | The lightest domain, deliberately. Deficiency is worth knowing and worth fixing, but it is not what kills this population. |
Iron and vitamins are recent additions. They were previously measured, shown in the report, and then left out of the arithmetic: a reader could be frankly iron-deficient, read about it in their own report, and watch the headline number ignore it. They now carry weight, small and proportionate to what they actually predict. Adding two domains rescaled the other eight; the ratios between them are unchanged.
Within one domain, several findings often point at the same underlying problem. Elevated creatinine, reduced eGFR and raised cystatin C are not three independent kidney problems, they are three views of one. Adding their severities would triple-count a single issue.
The model combines them the way you'd combine overlapping evidence for the same conclusion. Each finding counts as partial evidence of domain-level risk. It multiplies the probabilities that each one is not the whole story, then takes the complement. Statisticians call that shape a noisy-OR. Then it normalises by the square root of the number of findings, so a domain with six mild findings doesn't accumulate more apparent risk than a domain with one severe one.
Finally, and this is the part that matters, a floor is applied. The domain's risk can never be lower than the risk of its single worst finding. No amount of surrounding normality dilutes a critical result. That one rule is what stops the eGFR-of-48 athlete from being rescued by his nine good markers.
You then have to turn ten domain scores into a single number. A weighted average looks like the obvious approach, but it's the wrong one, for the same reason we saw earlier: it lets nine healthy systems bury one failing one.
Instead, the domains get combined via a weighted power mean with an exponent of 0.5, which sits between an arithmetic and a harmonic mean. In practice, this pulls the result toward the weakest domain rather than the middle. Then two hard constraints apply on top.
Constraint 1: the worst-domain ceiling
Your overall score can't run more than 35 points ahead of your worst domain score. So if your kidneys score 40, your overall is capped at 75, regardless of how immaculate everything else is. That margin only applies when the domain has at least two markers behind it, meaning a single odd result on a thin panel won't drag your whole report down by itself.
Constraint 2: the organ-failure override
When a finding shows an organ system is failing rather than just strained, the overall score gets capped at 30, flat out. At that point the number stops being a nuanced summary and becomes a single instruction: take this to a licensed medical professional now. No combination of good markers can lift it.
Most people notice this change first, and it's the one we consider the most important.
A fifteen-marker panel cannot tell you your kidneys are healthy. It can only tell you it did not find a kidney problem, which is a much weaker statement. The previous model scored an unmeasured domain as though it were fine, meaning the cheapest, thinnest panel reliably produced the best-looking score. That is a perverse incentive, and we shipped it for a long time.
💡Absence of evidence was being scored as evidence of absence. A thin panel bought a good number.
Now every score carries a coverage figure: how much of the risk model your panel actually addressed. Coverage does not subtract points. An unmeasured domain is not a problem, it is an unknown. Instead it caps the maximum achievable score. You cannot reach 100 on a panel that never looked at your kidneys, because the model has no basis for that claim.
When coverage falls below a coverage threshold, the report tags the number with the word provisional. The score still exists and the findings are real, but that label is a heads-up that you're working with a partial picture.
Provisional didn't cut it. A panel of three hormones still got a two-digit verdict on your health, and a number on a page carries authority no qualifying label can take back. Now there's a floor beneath which the report prints an em dash and says why.
What a panel must clear to be scored at all
| Marker | Requirement | Why this threshold |
|---|---|---|
| At least 3 domains | 3 | Two domains cannot describe a body. A panel that looks only at hormones is a hormone report, not a health assessment. |
| At least 8 markers | 8 | Below this the arithmetic is dominated by whichever handful of markers happened to be ordered. |
| Effective coverage 0.40 | 40% | Weighted by depth, not by count — see below. Four shallow domains can still fail this where two deep ones pass. |
Coverage is measured by depth, not by how many tubes you filled. The question a domain has to answer isn't "how many markers do you have?" but "can these markers tell us whether this domain is healthy?" Some single markers can. Cystatin C answers for the kidneys, GGT for the liver, TSH for the thyroid, hs-CRP for inflammation, HbA1c for metabolic, and ApoB for cardiovascular. One of those counts a domain as fully covered. Without one, the domain's coverage grows with the square root of the markers present against what a real panel would carry. So the second marker adds a great deal, and the sixth adds little.
Haematocrit demonstrates why relying on one fixed threshold falls apart, and it points straight to the approach that replaced it.
Anything above roughly 52% gets flagged by the standard approach, and it escalates from there. Apply that to an AAS-using population and you get constant alarm, because elevated haematocrit is an expected pharmacological effect rather than a disease. Alarm that fires on everyone gets ignored, including on the person it was meant for.
The model now uses four bands, and critically, the severity of the top band depends on whether the blood is actually more likely to clot, not on the haematocrit alone.
Haematocrit bands
| Marker | Range | How the model treats it |
|---|---|---|
| Up to 0.52 | Within expectation for an enhanced athlete | No finding. Reported with context. |
| 0.52 – 0.54 | Elevated, common, usually manageable | Low severity. Worth tracking across panels. |
| 0.54 – 0.58 | Meaningfully raised viscosity | Moderate severity, escalating with cofactors. |
| Above 0.58 | High, but severity depends on context | High on its own; critical when viscosity cofactors are present. |
The cofactors are elevated CRP or hs-CRP, a raised platelet count, and elevated blood pressure. Each one independently raises clotting risk, and when they combine with a high haematocrit, they compound rather than add. A haematocrit of 0.58 with clean inflammation, normal platelets, and controlled blood pressure is a different clinical object from a haematocrit of 0.58 with hs-CRP at 4 mg/L, platelets at 420, and blood pressure at 150/95, even though a threshold-based system reports them identically.
Blood pressure is the single most powerful modifiable cardiovascular risk factor in this population. For years the model just took your reading and never looked at it again. That changed. Now it grades on a curve instead of a threshold. Risk starts building above 120/80 and climbs steeply from there, so 128/82 reads as a nudge while 155/98 reads as a serious finding, not just the next category up.
A single reading is discounted against a series. Pressure taken once, in a clinic, after you drove there, is weaker evidence than three readings at home, so one reading carries roughly sixty percent of the weight a series does. The reading, its grade and the reasoning appear in your report, and a genuinely elevated pressure is raised as a key finding rather than buried in a table.
Most markers get graded by how far they sit outside their reference range. HbA1c doesn't work that way. It's read on a fixed ladder of absolute values, because its diagnostic thresholds are only a few percent apart and a curve built for wide-ranging markers simply can't see them. Under the previous model, an HbA1c sitting at the diabetes threshold contributed a severity of 0.10, while a fasting glucose of 7.0 mmol/L contributed just 0.026. The metabolic domain held at a median of 100 across every panel we have.
The HbA1c ladder
| Marker | HbA1c | Most the metabolic domain can score |
|---|---|---|
| Genuinely good | 5.4% or below | 100 — nothing is deducted |
| Creeping | 5.5% | 90 |
| Creeping | 5.6% | 80 |
| Prediabetic range | 5.7% | 70 |
| Prediabetic range | 5.9% | 50 |
| Prediabetic range | 6.1% | 30 |
| Top of prediabetes | 6.4% and above | 0 |
Ten points per additional 0.1%. This is deliberately stricter than clinical convention: the domain reaches zero at the top of the prediabetic range rather than at the 6.5% diagnosis, because by the time a diagnosis is available the thing worth catching happened years earlier.
A cystatin C of 86 mg/L is sixty-five times the upper bound of the reference range. It is not a kidney in trouble; it is a unit confusion or a transcription slip. The model used to grade values like that at maximum severity, which meant a data-entry error could tell a healthy reader their kidneys had failed. A haemoglobin of 0.35 mmol/L and a haematocrit of 1.00, a hundred percent packed cells, were doing the same thing elsewhere in the fleet.
Readings outside what a living person can produce are now set aside. They show as received, get marked as a reporting error, get excluded from the score, and stay invisible to every finding rule. The bounds sit at the edge of survivability, not at the edge of unusual, because the failure mode in the other direction is far worse. A haematocrit of 0.70 on a heavy blast, a potassium of 6.8, a glucose of 30 in ketoacidosis, and a white count of 150 are all real, all urgent, and all keep their full weight. eGFR is deliberately left out of the check entirely. An eGFR of 3 is survivable on dialysis and must never be dismissed as noise.
A score is only as good as the yardstick underneath it, and this is exactly where most general-purpose tools come up short for an enhanced athlete.
Lab reference ranges come from the central 95% of a reference population. They tell you what's common, not what's healthy, and that population isn't you. Build a range from sedentary adults and it'll flag a lifter's creatinine as abnormal just because he carries more muscle. The same range will call a testosterone level of 8 nmol/L perfectly acceptable, since plenty of the reference population sits right there.
GearCheck maintains its own medical logic, with target ranges built for athletes and for people on hormonal protocols. That document takes precedence over whatever the lab printed. If our logic has no specific target for a marker, the lab range is the fallback. And if you've set your own range with a licensed medical professional because you have a reason to, yours wins over both.
Reference range precedence
| Marker | Source | When it applies |
|---|---|---|
| Your custom range | Highest | Whenever you have set one. A range you and a licensed medical professional chose is not overridden by anything. |
| GearCheck medical logic | Next | Athlete- and protocol-adjusted targets, applied wherever we have a defensible one. |
| Lab reference range | Fallback | Only where neither of the above has a target for that marker. |
Take HDL cholesterol as one example of why this matters. Until recently, our engine scored it against a floor of 1.5 mmol/L. That number came from an optimisation target, not a risk threshold, so a perfectly workable HDL of 1.1 read as suppressed in every report it appeared in. The floor is now 1.0, matching the level at which risk actually starts to rise.
A split runs through the entire pipeline. Understanding that split is the single most important thing about how GearCheck reports are produced.
The model decides what is wrong. The code decides how much risk that represents.
Rules can't cover everything. Medicine has more patterns than any rule table can encode, and a domain with three unusual-looking markers and no matching rule shouldn't be silently reported as clear. So for domains where the deterministic engine produced no finding, a language model gets the measured values, the athletic target band, and the clinical normal band, and gives an assessment.
The output is hard-constrained. The system must pick a severity from the same closed four-level vocabulary, and it has to cite specific measured values as evidence. Every citation gets checked against the actual panel. If an assessment references a marker that was never measured, it's discarded rather than displayed. And where a deterministic rule already covers something in that domain, the model's severity gets capped at the rule's severity. It can agree or soften, but it can never escalate past the rule.
A second pass looks across domains for patterns connecting findings that already exist: the elevated liver enzymes, the lipid shift, and the insulin resistance together suggest one metabolic story rather than three unrelated ones. It can only connect findings the engine already produced, and only across at least two domains that already carry findings. It cannot introduce a new problem through the back door of a pattern claim.
When this model went live, scores dropped across the board. The median in our user base is now 62, and the ceiling sits at 97. Four changes explain nearly all of that movement.
Coverage now caps the maximum
Thin panels used to get away with a lot by simply not measuring anything that could go wrong. Now they score for what they actually are: incomplete. That single factor drives more of the change than anything else, and it hits the panels that used to top the charts the hardest.
The worst domain now constrains the total
With a 35-point ceiling, a single struggling system shows up clearly in the headline number instead of getting buried in the average.
Unmeasured is no longer treated as fine
Think about a domain with no markers. It used to contribute a perfect sub-score. Now it contributes nothing at all, and it reduces your coverage instead.
Athlete ranges cut in both directions
Tighter targets than the lab's mean some values that read as normal now read as suboptimal. The same correction moves other markers the other way, and the HDL floor above is an example where the change was in your favour.
Reports generated before the change keep the number they were issued with. We don't retroactively restate a report you've already read and possibly discussed with a licensed medical professional. If you want an old panel scored under the current model, regenerating it will do that, and the report will say which model produced it.
Now that you understand what that number actually represents, there are a few things worth internalising.
Publishing the reasoning means publishing the limits too.
The domain weights are a judgement, not a measurement. They come from the literature on irreversibility and outcome prediction plus clinical reasoning, and another defensible model would choose slightly different numbers. They are not derived from an outcome dataset, because no outcome dataset for this population exists at the scale required.
Single panels have limited resolution. One measurement cannot separate a genuine trend from assay variation. The model treats changes below roughly 10% between panels as noise for exactly this reason, but a single panel has no trend to draw on at all. Your third panel is meaningfully more informative than your first.
Rules cover the known patterns. The language model assessment exists to cover the gaps, and it is constrained precisely because it is the least predictable part of the pipeline. Unusual presentations remain the hardest case for any automated system, including this one.
Some markers still lack athlete-specific targets. Where our medical logic has no defensible target, the lab's range is used: and for enhanced athletes that range is frequently wrong. We are working through these marker by marker. It is slow because each one requires a defensible source rather than a guess.
