Skip to content

Document // Engine lab

How accurate is the adaptive estimate?

calibration.json · schema v2 · seed 20261103

The Track tab's adaptive engine turns daily weigh-ins and logged calories into an estimate of expenditure as logged: the calories per day that make what you log match your weight trend. It was tested on 5,000 synthetic people from a simulator that is deliberately messier than the model: their expenditure adapts as they diet, their water weight swings for days at a time, and they under-log, skip days and mistype weigh-ins. None of it follows the filter's assumptions. By day 56 its median error is 68 kcal/day against the formula's 189, and its 80% band holds the true value for 81% of people.

Median error, day 56, kcal
68
formula 189 · 64% less
Inside the 80% band, day 56
81%
50/80/95: 52/81/94
Posterior SD, day 56, kcal
105
286 at day 7
Within 150 kcal by day 56
85%
median from day 35

Accuracy over time

Median absolute error by day across the realistic cohort. The engine starts from its prior, the formula lowered 10% for typical under-logging, and learns from there. It pulls below the prior for good from day 20. By day 28 its error is 109 kcal against the prior's 121 and the formula's 185; by day 56, 68 against 113 and 189.

050100150200kcal071428day 56formulapriorengine
Median absolute error, kcal per day. Solid: the engine. Dashed: the raw formula. Dotted: the prior, the engine's starting point. Neither baseline is ever updated. Dots mark the checkpoint days in the table.
Median absolute error at the checkpoint days, kcal per day
DayEngineFormulaPrior
7125185131
14132184127
28109185121
5668189113
Every day (57 rows)
Median absolute error on every day, kcal per day
DayEngineFormulaPrior
0141185141
1138185140
2132184139
3128184137
4127184136
5125185134
6124185133
7125185131
8128185131
9129184130
10130184129
11130184128
12131184128
13132184128
14132184127
15131184127
16130184126
17129184125
18128183125
19126184124
20123184124
21122184124
22120184124
23117184123
24114185123
25114185122
26112184122
27112185122
28109185121
29107185120
30105184121
31102185120
32100185120
3399185120
3497185119
3597186119
3692186119
3790187119
3888187119
3987187119
4087186118
4185187118
4284186118
4382187117
4480187117
4580187116
4678187116
4776187115
4875187115
4974187115
5072188115
5172187115
5273188114
5371189114
5470189113
5569189113
5668189113

Calibration

A band is honest when it holds the true value as often as it claims. By day 56 the 50/80/95% bands hold 52/81/94%. Early on they hold more, because they are still mostly the prior's: at day 7 the prior alone would hold 69/94/100%. For people who log accurately the bands are on target once data arrive: 51/81/96% at day 28 and 49/82/95% at day 56.

50%6960535280%9489828195%99979594day 7day 14day 28day 56
Dashed line: the share a band claims to hold. Dot: the share of people whose true value was inside it. A dot above its line means the band was wider than it needed to be; below, narrower than it claimed.
Observed coverage at each checkpoint day, percent, with points from nominal
Day50% band80% band95% band
769 +1994 +1499 +4
1460 +1089 +997 +2
2853 +382 +295 0
5652 +281 +194 −1

Robustness to under-logging

The prior assumes people under-log by 10% on average. To see what happens when they log better or worse, the sweep reruns 2,000 realistic people at each mean logging bias. Across every level and day the bands are at most 2.6 points narrower than they claim (50% band, 20% bias, day 7), and at most 17.5 points wider (50% band, 10% bias, day 7). Each cohort's measured logging gap was within 0.5 points of its level.

Coverage of the 50, 80 and 95% bands by mean logging bias and day, percent. Bias levels from 0 to 15% are in the gated range.
BiasBandDay 7Day 14Day 28Day 56
0%gatedmeasured gap 0.5%50%57545253
80%88858182
95%98969595
5%gatedmeasured gap 5.0%50%66615253
80%93888382
95%99979595
10%gatedmeasured gap 10.1%50%68605252
80%94898380
95%99979594
15%gatedmeasured gap 14.8%50%62615653
80%91888381
95%99979594
20%not gatedmeasured gap 20.1%50%47515249
80%80818279
95%96969593
  • more than 6 points too narrow (past the gate's floor)
  • 3–6 points too narrow
  • within 3 points of nominal
  • 3–12 points too wide
  • more than 12 points too wide

GatedCI asserts mean bias from 0 to 15%: at days 7 and 14 no band may fall more than 6 points under nominal. At day 56 every level, 20% included, must sit within 6 points under and 12 over. Other days are reported, not gated.

Limit20% mean under-logging is the limit. At 20% the early bands sit at the edge, 47/80/96% at day 7, and nothing asserts them. Above 20% they will be too narrow until the weigh-ins catch up.

Why this prior: the same people were also run under a prior centred on the raw formula (widen only). Its worst distance from nominal was 33.5 points, against 17.5 for the prior that ships, lowered 10% from the formula (widen and recentre).

Edge cohorts

The same engine on people the realistic cohort under-represents. Errors are median absolute errors in kcal per day; coverage is the share inside the 50/80/95% bands.

Accurate loggers

1,000 people

The realistic population, logging exactly what they eat.

Error, day 56
72 kcalformula 113
Coverage, day 56
49/82/95of 50/80/95%
Within 150 kcal
86%median from day 35

The prior assumes some under-logging, so for them it starts 213 kcal low on average. The engine only beats the raw formula from day 30. By day 56 its error is 72 kcal against 113.

Missing weeks

1,000 people

As realistic, with days 14–27 missing: no weigh-ins and no calories.

Error, day 56
70 kcalformula 182
Coverage, day 56
56/84/96of 50/80/95%
Within 150 kcal
84%median from day 38

With nothing to learn from, its error goes from 124 kcal on day 13 to 130 on day 27. It then falls to 70 by day 56, against 182 for the formula.

Maintainers

1,000 people

Eat at their true expenditure, so tissue weight stays flat. They still under-log.

Error, day 56
46 kcalformula 186
Coverage, day 56
70/93/98of 50/80/95%
Within 150 kcal
94%median from day 29

Their expenditure does not adapt, so the drift the engine allows for dieters leaves their bands wide: 70/93/98% at day 56 against 50/80/95. The error still falls to 46 kcal, against 186 for the formula.

No logs

1,000 people

Weigh-ins only. No calories are ever logged.

Error, day 56
119 kcalformula 190
Coverage, day 56
78/97/100of 50/80/95%
Within 150 kcal
60%median from day 17

Weight change alone cannot separate intake from expenditure, so the estimate stays exactly on the prior: its error matches the prior's at every checkpoint (119 kcal at day 56).

Known limits

  • It estimates expenditure as logged, not true TDEE. A scale and a food log cannot tell a steady under-logging habit from a lower expenditure, because the two only ever show up as their sum, so the engine never estimates the bias itself.
  • The prior is lowered 10% for typical under-logging, which costs people who log honestly: for them it starts about 213 kcal low, and the engine only beats the raw formula from day 30.
  • The gate's margins are thin. Its tightest check on this run is that the realistic cohort's 80% band at day 7 may sit at most 3 points further from nominal than the prior alone; it passes by 3.3 points. Sampling noise on a coverage share has a standard deviation of up to 0.7 points at this cohort size, and CI runs a smaller cohort on another seed, so a change that costs a few points of early coverage will fail it.
  • The gate covers mean under-logging of 0–15%. At 20% the early bands sit at the edge (47/80/96% at day 7), and beyond it they will be too narrow until the weigh-ins catch up.
  • A day without logged calories is filled in from the 14-day average of what was logged. Skipping the days you overeat hides those calories: your weight rises more than the log explains, so the estimate reads low, by about the skipped days' surplus over your usual intake, spread over every day, much as under-logging does.

Reproduce it

Every number on this page is read at build time from calibration.json, which one command regenerates byte for byte.

npm ci
npm run calibrate
npm test
Seed
20261103
Cohorts
realistic 5,000; accurate loggers 1,000; missing weeks 1,000; maintainers 1,000; no logs 1,000
Bias sweep
2,000 people at each of 0%, 5%, 10%, 15% and 20% mean bias, the same people under each of the 2 priors
Horizon
56 days, checkpoints at days 7, 14, 28 and 56
Prior
mean formula × 0.90, SD 14.1% of the formula
Schema
version 2
Engine parameters
Engine parameters used for every cohort
ParameterValue
kcalPerKg7700
trendSdKg0.02
expenditureDriftKcal12
waterPersistence0.85
waterSdKg0.45
scaleSdKg0.35
missingIntakeSdKcal800
intakeMemoryDays14
outlierGateSd3
initialWeightSdKg10
plausibleWeightKg25–350
plausibleIntakeKcal0–12000

CI runs npm test on every push and pull request. The gate in calibration.test.ts reruns a smaller seeded cohort and fails the build if coverage or error regresses past its tolerances, and a second check fails if this file no longer matches the engine's parameters or schema.