Methodology

Everything on this page is generated when the site is built, from the metric registry in packages/protocol and the method notes that sit beside the kernel code. If the code changes, this page changes with it. It describes the method. It never shows anyone's data.

Sensor Court: sensor-court 1.5.0, court-calibration 1.3.0, court-noise-3ch 1.5.0, own-baseline 1.0.0. Forecast: forecast-local-level 1.0.0, forecast-settlement 1.0.0, forecast-scoreboard 1.1.0. Déjà Vu: analogs-deja-vu 1.1.0.

Metric definitions and units

Engines store and compute in SI units. Transcoding happens only at display. A range names its unit on both ends. Nightly metrics are keyed by wake date in the athlete's time zone at the time. A metric a source lacks is absent, never zero.

Overnight HRV (RMSSD) HRV

Root mean square of successive RR-interval differences during sleep. Vendors window it differently (night average vs slow-wave weighted); Sensor Court translates between them.

Identifier
hrv_rmssd_night
Engine unit (SI)
ms
Shown as
ms (metric), ms (imperial), 0 decimals
Scale
ratio
Translation
log_ratio: multiplicative bias, estimated as a median log ratio; fused on the natural log
Plausible range
5 ms to 250 ms; shown as 5 ms to 250 ms
Widest useful 80% band
20 ms
Cross-vendor fusion
Allowed: readings from different vendors are translated and fused.

Resting heart rate RHR

Lowest sustained heart rate for the night, as each vendor defines it. Stored as beats per minute (count/min), not Hz.

Identifier
resting_hr
Engine unit (SI)
count/min
Shown as
bpm (metric), bpm (imperial), 0 decimals
Scale
ratio
Translation
log_ratio: multiplicative bias, estimated as a median log ratio; fused on the natural log
Plausible range
25 count/min to 120 count/min; shown as 25 bpm to 120 bpm
Widest useful 80% band
8 count/min
Cross-vendor fusion
Allowed: readings from different vendors are translated and fused.

Sleep duration Sleep

Total time asleep in the main sleep period ending on the wake date (excludes awake time in bed).

Identifier
sleep_duration
Engine unit (SI)
s
Shown as
h (metric), h (imperial), 1 decimal
Scale
ratio
Translation
log_ratio: multiplicative bias, estimated as a median log ratio; fused on the natural log
Plausible range
0 s to 64800 s; shown as 0 h to 18 h
Widest useful 80% band
full log width 0.17 (−8.1% / +8.9% of the value)
Cross-vendor fusion
Allowed: readings from different vendors are translated and fused.

Sleep efficiency Efficiency

Time asleep divided by time in bed for the main sleep period, as a ratio from 0 to 1.

Identifier
sleep_efficiency
Engine unit (SI)
1 (dimensionless ratio)
Shown as
% (metric), % (imperial), 0 decimals
Scale
ratio
Translation
difference: additive bias, estimated as a median difference; fused in SI units
Plausible range
0 (ratio) to 1 (ratio); shown as 0 % to 100 %
Widest useful 80% band
0.1 (ratio)
Cross-vendor fusion
Not allowed: vendors define the denominator differently (Garmin: its own sleep window; Oura and WHOOP: time in bed) and their co-worn readings barely rank-correlate, so a bias translation would be invented. Nights with two or more vendors are refused as incommensurable_definitions.

Skin temperature deviation Skin temp

Night skin temperature minus the vendor's own personal baseline. A temperature difference, so kelvin and degrees Celsius are numerically equal.

Identifier
skin_temp_deviation
Engine unit (SI)
K
Shown as
Δ°C (metric), Δ°F (imperial), 2 decimals
Scale
interval
Translation
difference: additive bias, estimated as a median difference; fused in SI units
Plausible range
−5 K to 5 K; shown as −5 Δ°C to 5 Δ°C
Widest useful 80% band
1 K
Cross-vendor fusion
Allowed: readings from different vendors are translated and fused.

Overnight respiratory rate Resp. rate

Average breaths per minute during sleep.

Identifier
respiratory_rate_night
Engine unit (SI)
count/min
Shown as
br/min (metric), br/min (imperial), 1 decimal
Scale
ratio
Translation
log_ratio: multiplicative bias, estimated as a median log ratio; fused on the natural log
Plausible range
4 count/min to 40 count/min; shown as 4 br/min to 40 br/min
Widest useful 80% band
3 count/min
Cross-vendor fusion
Allowed: readings from different vendors are translated and fused.

How Sensor Court judges a night

For each metric and wake date, every source that reported the metric is a witness. The court translates the witnesses onto one scale, weighs them by how noisy each source is, fuses them into one number with an 80% band, overrules a witness that disagrees too much, and refuses (with a typed reason) when it cannot give a useful answer.

Scales and admissibility

Translate: bias per source and era

A vendor's reading is modelled as

y[n, g] = c[n] + b[g] + e[n, g]

where n is a co-worn night (two or more vendors), g is a (vendor, era) group, c[n] is the consensus that night, b[g] the group's systematic bias and e its noise. Era is part of the group because firmware and hardware changes move the bias (the old SpO₂ "finding" was an era artefact).

Estimation, robust. Start with b = 0 and repeat until no bias moves by more than 1e-9:

r[n, g]  = y[n, g] − median over the OTHER vendors that night of ( y[n, h] − b[h] )
b[g]    ← ( b[g] + median over n of r[n, g] ) / 2
b       ← b − Σ_g N_g b[g] / Σ_g N_g          (N_g = co-worn nights of g)

In words: a group's bias is the median of how far it sits above the other sources on the nights they were worn together. For log-ratio metrics this is a median log ratio; for difference metrics a median difference. The last line fixes the scale: biases average to zero, weighted by nights, so the consensus scale is "the average co-worn source". Only differences between biases are truly identifiable; the centring is a convention.

Noise per source: the three-cornered hat

If three sources A, B, C measure the same thing with independent errors, the variance of a pairwise difference is the sum of the two sources' variances, V_AB = σ²_A + σ²_B. Three pairs, three unknowns:

σ²_A = ( V_AB + V_AC − V_BC ) / 2

Each V is a robust variance of the translated pairwise differences over the window:

V_AB = ( 1.4826 × MAD( y'_A − y'_B ) )²

where MAD is the median absolute deviation about the median and 1.4826 makes it match the standard deviation for normal data. A few wild nights therefore do not inflate the noise.

Strength and fallback. Nothing is silently clamped; every fallback writes a note built from the numbers, and the noise claim's receipt carries the raw 3CH variance and an outcome code.

The hat assumes the sources' errors are independent. Two devices that share a sensing principle or an algorithm look closer together than they are; the negative-variance fallback catches the extreme case, not the milder one.

Fusion and dissent

With k usable witnesses (translated y_i, noise σ_i):

w_i  = 1 / σ_i²
ȳ    = Σ w_i y_i / Σ w_i                     fixed-effect mean
Q    = Σ w_i (y_i − ȳ)²                      Cochran's Q
C    = Σ w_i − Σ w_i² / Σ w_i
τ²   = max( 0, (Q − (k − 1)) / C )           between-source variance (0 when k = 1)
w*_i = 1 / (σ_i² + τ²)
μ    = Σ w*_i y_i / Σ w*_i                   the verdict (fusion scale)
SE   = √( 1 / Σ w*_i )
band = μ ± q · SE,  q = Φ⁻¹(0.9) = 1.2816     80% band

In words: each source counts in proportion to its precision. If the sources disagree more than their own noise explains, the excess becomes τ², which is added to every source's variance: weights even out and the band widens. τ² before the max(0, ·) is kept in the receipt (tau2InitialRaw, tau2FinalRaw); truncation at zero is part of the DerSimonian–Laird estimator, not a hidden clamp. Weights reported are w*_i / Σ w* and sum to 1 over witnesses that were fused.

Dissent: leave-one-out residuals

For each witness i (when k ≥ 2), fit section 3's model to the other witnesses, giving μ₋ᵢ, τ²₋ᵢ and SE²₋ᵢ, and compute

z_i = ( y_i − μ₋ᵢ ) / √( σ_i² + τ²₋ᵢ + SE²₋ᵢ )

A witness whose |z| is above the bar is overruled: its weight drops to zero, and the reason on the card is assembled from the readings, the consensus of the others and the bar it crossed. The verdict is then recomputed once, without it. Leaving the witness out of its own consensus matters: an outlier included in the mean drags the mean towards itself and inflates the between-source variance until its own residual looks ordinary.

Two witnesses. With k = 2 both residuals have the same size, |y₁ − y₂| / √(σ₁² + σ₂²), so the court cannot tell which one is wrong. When that exceeds 2.5 both are overruled and the court refuses with all_witnesses_overruled, saying the disagreement cannot be attributed.

Student-t bands

Real pairwise differences between devices have heavier tails than a normal distribution: integer-valued readings, the occasional bad night. A Gaussian band and a fixed |z| > 2.5 rule would then overrule honest witnesses too often. The court fits the tails instead.

Model. The court's leave-one-out residual is modelled as a scaled Student-t, z ≈ s · T_ν, fitted per noise-model epoch (vendor, era, calibration epoch) and per night class: pair (exactly two usable witnesses: z is one difference) and multi (three or more: τ² and the others' mean enter). Both fits travel on the noise model as tail: {pair, multi} with df, scale, source, residuals and residualKind.

Held-out residuals. The noise stage replays the court's arithmetic on every history night with two or more usable witnesses (same translation, same σ, same leaveOneOutResiduals code as the court): each witness's z is computed against the consensus of the others, so it never judges itself. Each z goes to its own epoch's class list (a pair night's two residuals have the same size; the metric-pooled list takes one).

Fit. Maximum likelihood with the location fixed at 0: for each ν on a 49-point log grid in [1, 1000], the scale solves the EM fixed point s² = Σ wᵢ zᵢ² / n, wᵢ = (ν + 1)/(ν + zᵢ²/s²); the best ν is refined by golden section on ln ν. An epoch needs 100 residuals in a class for its own fit (source: epoch); with fewer it takes the metric's pooled fit (pooled); with fewer than 100 anywhere, or on a metric the registry never fuses across vendors, the documented prior ν = 4, s = 1 (prior, heavier than Gaussian, so it can only widen). Every fit writes a note with ν, s, the residual count, and the t and Gaussian log-likelihoods.

Band. band = μ ± q · SE with

fused witnessesq
1max(Φ⁻¹(0.9), s·Q_ν(0.9)) of its pair tail: the tail may widen a lone band, never narrow it (a pair's scale cannot be attributed to one source)
2the larger s·Q_ν(0.9) of the two pair tails
3 or moremax(Φ⁻¹(0.9), the largest s·Q_ν(0.9) of their multi tails): never below Gaussian, because τ² already absorbs part of the spread z measures

Dissent. The Gaussian rule promised a false-dissent probability α = P(|Z| > 2.5) = 1.24%. A witness is overruled when |zᵢ| > s · Q_ν(1 − α/2), which has that same probability under the fitted tail. Pair nights use the larger of the two witnesses' pair thresholds (neither witness's tail may lower the bar for an unattributable disagreement); three or more use each witness's own multi tail. dissentThreshold (default 2.5) keeps its meaning as the Gaussian-equivalent bar; Infinity still disables dissent. The reason string quotes the bar in the form |z| = <z> > <bar> (Student-t ν = <ν>, scale <s>, <source>: the same 1.24% false-dissent rate as |Z| > 2.5). Receipts carry tailRule, nominalFalseDissentRate, bandQuantile and per witness witnessTails[{class, tail, zThreshold}].

The proportional sleep band

Every verdict has a widest useful 80% band in the registry. Wider than that, and the court refuses with band_wider_than_useful rather than show a number that cannot support a decision.

Sleep duration is refused when ln(upper / lower) > 0.17, a full log width of 0.17, about −8.1% / +8.9% of the value. Its band is built on the log scale, so a lone reading's band is a fixed fraction of the value, and the cap is a fixed fraction too.

Two nights from the same device with the same measured noise get the same verdict whatever their length. An absolute cap (say, one hour) would refuse long lone nights and admit short ones, so anything that averages admitted nights would see a sample censored from above.

Display unit h. Generated from maxUsefulBand in the registry.

Refusal reasons

A refusal is a typed answer, with a receipt listing every reading that was looked at. The court checks in this order:

ReasonWhen
no_witnessno reading of this metric for this wake date was supplied
unit_mismatchreadings exist but every one has the wrong unit
implausible_inputreadings exist but none is plausible (or positive on the log scale)
single_witness_no_noise_modelexactly one witness and it has no usable noise model
insufficient_historytwo or more witnesses and none has a noise model
all_witnesses_overruledevery fused witness was overruled (always the case for a disagreeing pair)
band_wider_than_usefulthe 80% band is wider than the registry's maxUsefulBand: upper − lower (SI) above an absolute width, or ln(upper / lower) above a full log width

What the athlete reads

Each reason has one plain-language lead sentence, shared by the web and iPhone apps. Placeholders in italics are filled from the verdict's own fields.

ReasonLead sentence
no_witnessNo device reported noun last night.
single_witness_no_noise_modelToo uncertain to show: only witnesses reported noun, with nothing yet to check it against.
band_wider_than_usefulToo uncertain to show: witnesses, and pronoun likely range (lower to upper) is wider than the maxBand Intero allows for noun.
implausible_inputToo uncertain to show: every reading of noun last night was outside the range Intero trusts.
insufficient_historyToo uncertain to show: witnesses reported noun, but none yet has enough shared history to judge how reliable it is.
unit_mismatchToo uncertain to show: every reading of noun last night used units Intero doesn't expect.
zone_unknownToo uncertain to show: Intero couldn't tell which night this reading of noun belongs to.
all_witnesses_overruledToo uncertain to show: witnesses measuring noun disagreed too much with each other to be trusted.
incommensurable_definitionswitnesses reported noun, but they define it too differently to combine into one number.
settling_windownounCap is withheld until the settling window after the event closes.

Own baseline and effective sample size

Parameters

ParameterValue
band level0.80
dissent threshold|z| > 2.5 (Gaussian-equivalent; 1.3.0 bar = s·Q_ν(1 − α/2), α = 1.24%)
tail modelsStudent-t by maximum likelihood, ν ∈ [1, 1000]; own fit ≥ 100 residuals per class, else pooled, else prior ν = 4, s = 1; leave-one-out residuals, no time cross-fitting
calibration: min co-worn nights14
widest useful band (1.5.0)registry maxUsefulBand: absolute SI width, or full log width (sleep duration 0.17)
placement eras (calibration 1.3.0, noise 1.5.0)athlete device_placement events split a (vendor, era) with readings on both sides of the date, before the changepoint search
noise: window / min three-source nights / floor365 nights / 60 / ¼ prior
single-witness transfer (1.4.0)never-co-worn eras only; nearest measured era of the same vendor; every reading between with one known device and firmware; carried model weak
baseline: window / min estimates / min n_eff / min pairs per lag60 days / 14 / 10 / 3

What doesn't work yet

Intero publishes its misses. This list is partly written by hand and partly pulled from the "known limits" in the method notes.

Déjà Vu is mostly a null result

"The last ten nights most resemble these earlier windows; here is what happened next." Descriptive only. Every number is a mission ledger claim receipted by analogs-deja-vu 1.1.0 (1.0.0 claims stay on record, superseded).

In backtests so far, the analogs mostly fail to beat two simple references: the last value seen, and the athlete's own seasonal average. For most metrics the honest answer is "no better than persistence". The page says so, shows how often it answered, and is never used as advice.

Sensor Court

Forecast

Drift Radar

Elsewhere