← Tepna preprints

Treatment-response detection from overnight wearables: change-point recovery of the CPAP-start night from the ODI-4 and rMSSD trajectory

Michal Planicka  ·  corresponding author — Tepna Project

OxyDex · PulseDex nodes, Tepna physiological-signal suite

Draft v2 · July 2026 · Analysis tool: treatment-response-analysis.html · Detectors: real oxydex-dsp.js · pulsedex-dsp.js (two-pool Web Workers) · generator synth-gen 2.1 / cohort-gen 1.9 · 100% local

Revision note (2026-10-27, re-cut on current code): re-run on commit 39cfafdc4, after 86 commits to the *-dsp.js detectors since the 2026-09-22 re-cut, 71 of them fixes (driver tools/analysis-rerun.mjs --paper-scale). The run reproduces the committed record analysis/published-numbers/treatment-response-2026-09-22.json cell for cell, so no CLAIM marker and no record changes. At the paper’s 900 patients and its ≥10-night floor: 233 intervention and 239 flat-control patients; ODI localization exact 99.1 %; rMSSD exact 88.4 %, within-one-night 95.3 %; fused exact 99.1 %, within-one-night 100 %; detection AUC 0.996 (ODI), 0.970 (rMSSD), 0.998 (fused). ⚠ The historical 912/918 yield does NOT reproduce and is not restated — 233/239 is the yield at this floor, now measured twice five weeks apart. Figures were not regenerated; the yield they draw is the one re-measured here.

Revision note: re-run on synth-gen 2.1 / cohort-gen 1.9 (the earlier draft was on cohort-gen 1.5). Fusion is still the best detector (exact CLAIM trExactFused4 = 99 FROM analysis/published-numbers/treatment-response-2026-09-22.json#claims/exactFused %, AUC CLAIM trAucFused4 = 1.00 FROM analysis/published-numbers/treatment-response-2026-09-22.json#claims/aucFused ) and localization is still median-0. The “ODI-4's localization fell” change this note reported is WITHDRAWN by the 2026-09-22 correction below (it read exact 95 %→73 %; on the current tree ODI-4 localizes exactly in CLAIM trExactOdi4 = 99 FROM analysis/published-numbers/treatment-response-2026-09-22.json#claims/exactOdi %), as is the mechanism it offered — that the AHI-ceiling revision since v1.5 made the respiratory step shallower, so the autonomic channel (rMSSD, exact 87%, stable) now localizes better than the respiratory one — a reversal that strengthens the paper's point that oximetry is not required. Cohort is smaller here (912 tx / 918 flat) as this run was time-bounded; the ≥≤10-night population attrits heavily on per-night coverage.

Abstract

Background. When a sleep-apnea patient starts CPAP, their overnight physiology should step: respiratory events fall and autonomic tone recovers. If a multi-night wearable record can pinpoint when that step happened — and flag that it happened at all — the device becomes a passive therapy-response monitor. We test whether a vanilla change-point detector on the production metrics can do it. Methods. For intervention-arc synthetic patients with a planted CPAP-start night (restricted to ≥2 pre- and ≥2 post-treatment nights), we measured per-night ODI-4 (OxyDex) and rMSSD (PulseDex) with the real detectors. A single change-point (minimum within-segment SSE) localized the planted night for each metric and for a fused respiratory+autonomic index; the step-model R² gave a detection statistic, scored against flat-arc controls by ROC. Results. Across CLAIM trNIntervention = 233 FROM analysis/published-numbers/treatment-response-2026-09-22.json#claims/nIntervention intervention and CLAIM trNFlat = 239 FROM analysis/published-numbers/treatment-response-2026-09-22.json#claims/nFlatControl flat-control patients (records of ≥10 nights), change-point localization recovered the CPAP-start night with a median error of 0 nights and within ±1 night in CLAIM trWithin1Rmssd = 95 FROM analysis/published-numbers/treatment-response-2026-09-22.json#claims/within1Rmssd–CLAIM trWithin1Fused = 100 FROM analysis/published-numbers/treatment-response-2026-09-22.json#claims/within1Fused% of patients. Fusing the respiratory and autonomic channels was best — exact CLAIM trExactFused = 99 FROM analysis/published-numbers/treatment-response-2026-09-22.json#claims/exactFused%, within ±1 night CLAIM trWithin1Fused2 = 100 FROM analysis/published-numbers/treatment-response-2026-09-22.json#claims/within1Fused%, detection AUC CLAIM trAucFused = 1.00 FROM analysis/published-numbers/treatment-response-2026-09-22.json#claims/aucFused — at least as good as either channel alone (ODI-4 AUC CLAIM trAucOdi = 1.00 FROM analysis/published-numbers/treatment-response-2026-09-22.json#claims/aucOdi, rMSSD CLAIM trAucRmssd = 0.97 FROM analysis/published-numbers/treatment-response-2026-09-22.json#claims/aucRmssd). The reversal this abstract reported is WITHDRAWN by the 2026-09-22 correction below and is not restated: on the current tree the respiratory channel is the stronger localizer again (ODI-4 exact CLAIM trExactOdi = 99 FROM analysis/published-numbers/treatment-response-2026-09-22.json#claims/exactOdi% vs rMSSD CLAIM trExactRmssd = 88 FROM analysis/published-numbers/treatment-response-2026-09-22.json#claims/exactRmssd%). Conclusion. A treatment response that produces a clean physiological step is recoverable and well-localized by a simple detector, and the two single-signal channels carry partly independent evidence that fusion exploits. This is synthetic ground truth with a known, fairly clean step: it certifies the pipeline and method, not real-world CPAP-response detection, which is noisier, adherence-dependent, and confounded.

Keywords: change-point detection · CPAP · treatment response · obstructive sleep apnea · oximetry · heart-rate variability · sensor fusion · longitudinal monitoring

0. Layman overview (delete before submission)

When someone with sleep apnea starts CPAP therapy, their body changes overnight: breathing interruptions drop and the heart's “rest-and-recover” signal improves. If a wearable worn across several nights could spot which night therapy started — and confirm it started at all — it would act as a passive check that the treatment is working.

We tested this on simulated patients where we planted a known “therapy-start” night, then used the real app's two detectors (a breathing one and a heart-rhythm one) to measure each night. A standard “where did the trend change?” method found the right night almost exactly — typically the correct night, nearly always within one night — and combining the breathing and heart signals worked best of all. One honest caveat we quantified: the method can “find” a fake change even in steady patients, so it must always be compared against people who didn't change. Because the step is clean and known here, this proves the method and software work; real CPAP responses are messier, so it isn't yet a claim about real patients.

1. Introduction

Adherence and response to CPAP are usually assessed from the device's own residual-event log, not from the patient's broader physiology. Yet the response is physiologically broad: starting effective therapy lowers the apnea burden (fewer desaturations, lower ODI) and, over the same nights, relieves the autonomic stress of repeated arousals (higher short-term heart-rate variability). A wearable that records several nights spanning the therapy start therefore contains a step in two partly-independent channels — a respiratory one and an autonomic one. The analytic question is a textbook one: given a short, noisy multi-night series, can a change-point detector (i) decide that a step occurred and (ii) localize which night it occurred on? We answer it on synthetic patients where the change-point is planted and known, using the production single-signal detectors to produce the trajectories.

2. Methods

2.1 Cohort and planted change-point

Intervention-arc patients in the 1–12-night longitudinal lane carry a planted CPAP-start night (profile.interventionNight, the 0-based index of the first treated night). On and after that night the generator drops the apnea–hypopnea index sharply and lets rMSSD recover, so ODI-4 steps down and rMSSD steps up at the same boundary. We restricted the analysis to arcs with at least two pre- and two post-treatment nights (and, in this run, to records of at least 10 nights), so a single change-point is in principle recoverable. Flat-arc patients (a stable latent, no step) are the detection null. Per-metric attrition came only from per-night node missingness: a patient was used for a metric only if every night carried a valid value (no interpolation across gaps).

2.2 Per-night measurement

Each night was scored by the unmodified production detector, loaded alone in its own Web-Worker realm (OxyDex and PulseDex collide on bare globals, so each runs in a separate worker pool and the two per-night trajectories are joined by seed): ODI-4 from oxydex-dsp.js → processNight and time-domain rMSSD from pulsedex-dsp.js. Timestamps follow the suite Clock Contract so night ordering is viewer-timezone-independent.

2.3 Change-point localization and detection

For a per-night series x₀…x₍ₘ₋₁₎ we fit a single change-point by minimizing total within-segment sum-of-squares, requiring at least two nights on each side:

ĉ = argmin_k [ SSE(x₀…x₍ₖ₋₁₎) + SSE(x_k…x₍ₘ₋₁₎) ] , 2 ≤ k ≤ m−2

where ĉ is the estimated first post-step night, matching the planted convention. We ran this on ODI-4, on rMSSD, and on a fused index — each series z-scored, ODI-4 sign-flipped (so both step the same direction), then averaged. Localization was scored against the planted night as exact match, within ±1 night, and median absolute error. As a detection statistic we used the step-model coefficient of determination R² = 1 − SSE_split/SSE_total, and computed the rank (Mann–Whitney) AUC of intervention vs flat-control R².

3. Results

Table 1. Change-point localization and detection by metric (912 intervention, 918 flat-control patients; ≥10 nights; real detectors, synth-gen 2.1 / cohort-gen 1.9).
DetectorPatientsExactWithin ±1Median |err| (nights)Detection AUCtx median R²flat median R²
ODI-4 (OxyDex)91273%85%00.940.790.27
rMSSD (PulseDex)91287%96%00.970.760.24
Fused (respiratory + autonomic)91291%97%00.990.850.27

🔴 CORRECTION — 2026-09-22 (Table 1 re-cut at what the generator yields; owner ruling 2026-09-21, OWNER-DECISION-QUEUE D9.2). Table 1’s stated cohort — 912 intervention + 918 flat-control at ≥ 10 nights from “~900” per arm — is not recoverable from the repository: driving treatment-response-analysis.html at its stated configuration (nSubj 900, minN 10) yields a few hundred patients per arm, not nine hundred, identically under cohort-gen 1.9 and 2.0 (residues 2026-09-16-treatment-response-config-unreproducible · 2026-09-17-treatment-response-gap-is-not-the-generator · 2026-09-17-treatment-response-three-cohort-sizes). The ruling: restate the headline at the n the generator yields, with the interval that n supports, and do not reconfigure toward the published size. Table 1 above is left as published; this is the same table on the current tree, every cell a sourced claim against analysis/published-numbers/treatment-response-2026-09-22.json (run 2026-09-22 by tools/analysis-rerun.mjs --paper-scale, intervals by tools/treatment-response-recut.mjs: Wilson 95 % for the proportions, Hanley–McNeil 95 % for the AUC; medians carried as the page publishes them, without an interval).

The n moved again since the ruling. The rows measured 269 / 317 on 2026-09-16/17; the same configuration on 2026-09-22 yields CLAIM trNIntervention = 233 FROM analysis/published-numbers/treatment-response-2026-09-22.json#claims/nIntervention intervention and CLAIM trNFlat = 239 FROM analysis/published-numbers/treatment-response-2026-09-22.json#claims/nFlatControl flat-control patients at ≥ CLAIM trMinNights = 10 FROM analysis/published-numbers/treatment-response-2026-09-22.json#claims/minNights nights. The page and the generator inline the production detectors, and OxyDex moved between those dates (#2610 epoch HR as the mean of rates; #2745 computeStats over measured seconds only) — named as the candidates, not verified as the cause; the ruling’s figure was itself a dated measurement.

Table 1 (re-cut). Same statistic and same filter as Table 1, at the yielded n; brackets are 95 % intervals.
DetectorPatientsExactWithin ±1Median |err| (nights)Detection AUCtx median R²flat median R²
ODI-4 (OxyDex)CLAIM trOdiN = 233 FROM analysis/published-numbers/treatment-response-2026-09-22.json#claims/nOdiCLAIM trExactOdi = 99 FROM analysis/published-numbers/treatment-response-2026-09-22.json#claims/exactOdi % [CLAIM trExactLoOdi = 96.9 FROM analysis/published-numbers/treatment-response-2026-09-22.json#claims/exactLoOdi–CLAIM trExactHiOdi = 99.8 FROM analysis/published-numbers/treatment-response-2026-09-22.json#claims/exactHiOdi]CLAIM trW1Odi = 99 FROM analysis/published-numbers/treatment-response-2026-09-22.json#claims/within1Odi % [CLAIM trW1LoOdi = 96.9 FROM analysis/published-numbers/treatment-response-2026-09-22.json#claims/within1LoOdi–CLAIM trW1HiOdi = 99.8 FROM analysis/published-numbers/treatment-response-2026-09-22.json#claims/within1HiOdi]CLAIM trMedErrOdi = 0 FROM analysis/published-numbers/treatment-response-2026-09-22.json#claims/medErrOdiCLAIM trAucOdi = 1.00 FROM analysis/published-numbers/treatment-response-2026-09-22.json#claims/aucOdi [CLAIM trAucLoOdi = 0.991 FROM analysis/published-numbers/treatment-response-2026-09-22.json#claims/aucLoOdi–CLAIM trAucHiOdi = 1.000 FROM analysis/published-numbers/treatment-response-2026-09-22.json#claims/aucHiOdi]CLAIM trTxR2Odi = 0.98 FROM analysis/published-numbers/treatment-response-2026-09-22.json#claims/txR2OdiCLAIM trFlatR2Odi = 0.31 FROM analysis/published-numbers/treatment-response-2026-09-22.json#claims/flatR2Odi
rMSSD (PulseDex)CLAIM trRmssdN = 233 FROM analysis/published-numbers/treatment-response-2026-09-22.json#claims/nRmssdCLAIM trExactRmssd = 88 FROM analysis/published-numbers/treatment-response-2026-09-22.json#claims/exactRmssd % [CLAIM trExactLoRmssd = 83.7 FROM analysis/published-numbers/treatment-response-2026-09-22.json#claims/exactLoRmssd–CLAIM trExactHiRmssd = 91.9 FROM analysis/published-numbers/treatment-response-2026-09-22.json#claims/exactHiRmssd]CLAIM trW1Rmssd = 95 FROM analysis/published-numbers/treatment-response-2026-09-22.json#claims/within1Rmssd % [CLAIM trW1LoRmssd = 91.7 FROM analysis/published-numbers/treatment-response-2026-09-22.json#claims/within1LoRmssd–CLAIM trW1HiRmssd = 97.3 FROM analysis/published-numbers/treatment-response-2026-09-22.json#claims/within1HiRmssd]CLAIM trMedErrRmssd = 0 FROM analysis/published-numbers/treatment-response-2026-09-22.json#claims/medErrRmssdCLAIM trAucRmssd = 0.97 FROM analysis/published-numbers/treatment-response-2026-09-22.json#claims/aucRmssd [CLAIM trAucLoRmssd = 0.954 FROM analysis/published-numbers/treatment-response-2026-09-22.json#claims/aucLoRmssd–CLAIM trAucHiRmssd = 0.986 FROM analysis/published-numbers/treatment-response-2026-09-22.json#claims/aucHiRmssd]CLAIM trTxR2Rmssd = 0.77 FROM analysis/published-numbers/treatment-response-2026-09-22.json#claims/txR2RmssdCLAIM trFlatR2Rmssd = 0.23 FROM analysis/published-numbers/treatment-response-2026-09-22.json#claims/flatR2Rmssd
Fused (respiratory + autonomic)CLAIM trFusedN = 233 FROM analysis/published-numbers/treatment-response-2026-09-22.json#claims/nFusedCLAIM trExactFused = 99 FROM analysis/published-numbers/treatment-response-2026-09-22.json#claims/exactFused % [CLAIM trExactLoFused = 96.9 FROM analysis/published-numbers/treatment-response-2026-09-22.json#claims/exactLoFused–CLAIM trExactHiFused = 99.8 FROM analysis/published-numbers/treatment-response-2026-09-22.json#claims/exactHiFused]CLAIM trW1Fused = 100 FROM analysis/published-numbers/treatment-response-2026-09-22.json#claims/within1Fused % [CLAIM trW1LoFused = 98.4 FROM analysis/published-numbers/treatment-response-2026-09-22.json#claims/within1LoFused–CLAIM trW1HiFused = 100.0 FROM analysis/published-numbers/treatment-response-2026-09-22.json#claims/within1HiFused]CLAIM trMedErrFused = 0 FROM analysis/published-numbers/treatment-response-2026-09-22.json#claims/medErrFusedCLAIM trAucFused = 1.00 FROM analysis/published-numbers/treatment-response-2026-09-22.json#claims/aucFused [CLAIM trAucLoFused = 0.994 FROM analysis/published-numbers/treatment-response-2026-09-22.json#claims/aucLoFused–CLAIM trAucHiFused = 1.000 FROM analysis/published-numbers/treatment-response-2026-09-22.json#claims/aucHiFused]CLAIM trTxR2Fused = 0.93 FROM analysis/published-numbers/treatment-response-2026-09-22.json#claims/txR2FusedCLAIM trFlatR2Fused = 0.28 FROM analysis/published-numbers/treatment-response-2026-09-22.json#claims/flatR2Fused

What the re-cut changes. Localization is at or near the ceiling for every detector at this n — median error 0 nights everywhere, fused within ±1 in 100 % [98.4–100] — and the intervals say what 233 patients can: an exact-localization rate of 99 % is known to about ±1.5 points, an AUC of 1.00 to about ±0.006. The revision note’s reversal does not hold on this tree: it reports ODI-4’s exact localization falling to 73 % with rMSSD (87 %) localizing better; here ODI-4 localizes exactly in 99 % [96.9–99.8] and rMSSD in 88 % [83.7–91.9], so the respiratory channel is the stronger localizer again and the sentence that built a point on the reversal is withdrawn rather than restated. The conclusion that survives every version — the fused index is at least as good as either channel and a change-point estimator recovers the CPAP-start night with median error 0 — holds at this n with the intervals shown. Table 2’s “This run” row (912 tx + 918 flat) is superseded by the counts above. Synthetic ground truth, as §4 states; nothing here is a field result.

Every detector localized the planted CPAP-start night with a median error of 0 nights. The fused respiratory+autonomic index was best, recovering the exact night in CLAIM trExactFused2 = 99 FROM analysis/published-numbers/treatment-response-2026-09-22.json#claims/exactFused% of patients and landing within ±1 night in CLAIM trWithin1Fused3 = 100 FROM analysis/published-numbers/treatment-response-2026-09-22.json#claims/within1Fused%, with a detection AUC of CLAIM trAucFused2 = 1.00 FROM analysis/published-numbers/treatment-response-2026-09-22.json#claims/aucFused . The single-channel reversal this paragraph reported is WITHDRAWN by the 2026-09-22 correction below and is not restated. It read "rMSSD localizes better than ODI-4" (exact 87 % vs 73 %) against the pre-correction cut; on the current tree ODI-4 localizes exactly in CLAIM trExactOdi2 = 99 FROM analysis/published-numbers/treatment-response-2026-09-22.json#claims/exactOdi% [CLAIM trExactLoOdi = 96.9 FROM analysis/published-numbers/treatment-response-2026-09-22.json#claims/exactLoOdi–CLAIM trExactHiOdi = 99.8 FROM analysis/published-numbers/treatment-response-2026-09-22.json#claims/exactHiOdi] and rMSSD in CLAIM trExactRmssd2 = 88 FROM analysis/published-numbers/treatment-response-2026-09-22.json#claims/exactRmssd% [CLAIM trExactLoRmssd = 83.7 FROM analysis/published-numbers/treatment-response-2026-09-22.json#claims/exactLoRmssd–CLAIM trExactHiRmssd = 91.9 FROM analysis/published-numbers/treatment-response-2026-09-22.json#claims/exactHiRmssd], so the respiratory channel is the stronger localizer again. The mechanism the paragraph offered for the reversal (a shallower, noisier respiratory step degrading ODI-4's AUC) explained an effect that is not present on this tree and is withdrawn with it. Because the two channels carry partly independent evidence of the same response, fusing them still beats either alone on both localization and detection.

Example intervention trajectory with planted/detected change-point, localization accuracy bars, and detection ROC
Figure 1. Treatment-response recovery (live output of treatment-response-analysis.html, synth-gen 2.1 / cohort-gen 1.9). Top: one intervention patient — ODI-4 (blue) collapses and rMSSD (amber) rises at the planted CPAP-start night (green band); the fused detector's estimate (teal dashed) coincides. Bottom-left: localization accuracy — solid = exact night, light = within ±1 night, for ODI-4 / rMSSD / fused (rMSSD now leads the single channels). Bottom-right: detection ROC (intervention vs flat controls) by step-R²; all three curves hug the top-left, fused highest (AUC CLAIM trAucFused3 = 1.00 FROM analysis/published-numbers/treatment-response-2026-09-22.json#claims/aucFused (current tree; the figure image is the pre-correction render)). Dark theme is the tool's native rendering.

3.1 The naive step-R² is inflated under the null

The detection statistic must be read against the null, not absolutely. Fitting a free single change-point to a flat control series still "explained" a median ~24–27% of its variance (R²≈0.24–0.27) purely by overfitting the best of many candidate splits to noise. Intervention patients sat far above this (median R²≈0.76–0.85), which is why detection separates so cleanly — but it also means a fixed R² cutoff read in isolation would over-call change in stable patients. The flat-control comparison (or an equivalent permutation/penalized threshold) is therefore not optional; it is what turns the inflated raw statistic into a usable decision.

4. Discussion

When a treatment produces a genuine physiological step, recovering it is easy: a one-line change-point estimator localizes the CPAP-start night to the correct night (median error 0) and usually within a single night, and detects the response with high AUC. The practical messages are three. First, the claim that autonomic recovery is more informative than the respiratory drop is WITHDRAWN by the 2026-09-22 correction below — it rested on the reversal, and on this tree ODI-4 is the stronger localizer (exact CLAIM trExactOdi3 = 99 FROM analysis/published-numbers/treatment-response-2026-09-22.json#claims/exactOdi% vs CLAIM trExactRmssd3 = 88 FROM analysis/published-numbers/treatment-response-2026-09-22.json#claims/exactRmssd%). What survives every version is that the fused index is at least as good as either channel alone here (exact 87% vs 73%), so a device without oximetry is not only not blind to therapy response, it may be the stronger single channel. Second, fusion helps: the two channels are not redundant, and combining them is the most accurate and most robust option (exact 91%, AUC 0.99). Third, the detection threshold must account for the null, because the best-split R² is inflated by the search over candidate change-points.

Limitations. This is synthetic ground truth, and the planted step is deliberate, single, and fairly clean — exactly one change-point per patient, a large AHI drop, and a coherent rMSSD recovery. Real CPAP responses are partial, gradual, adherence-dependent (good nights interleaved with non-adherent ones), and confounded by illness, alcohol, and weight change; multiple or no change-points are common. The cohort restriction to ≥2 pre- and ≥2 post-treatment nights selects recoverable cases by construction; per-metric n here is moderate (CLAIM trNIntervention3 = 233 FROM analysis/published-numbers/treatment-response-2026-09-22.json#claims/nIntervention ⁄ CLAIM trNFlat3 = 239 FROM analysis/published-numbers/treatment-response-2026-09-22.json#claims/nFlatControl per the 2026-09-22 correction above, not the 912/918 this paragraph published), so the intervals the correction box carries are what these accuracies are known to — an exact-localization rate of CLAIM trExactFused3 = 99 FROM analysis/published-numbers/treatment-response-2026-09-22.json#claims/exactFused % to about ±1.5 points — rather than the ±2–3 % estimated here. These results certify the pipeline and the change-point method; they motivate, but do not establish, real-world therapy-response monitoring, which needs a labelled pre/post-CPAP wearable cohort.

5. Reproducibility

6. Sample size & statistical power

Patients are independent, so the two arms can be grown to any size; accuracy estimates (exact %, within-±1 %, AUC) are proportions whose standard error scales as √(p(1−p)/N), and the detection AUC's SE falls as ~1/√N. The qualitative result — near-perfect localization, fusion best, null-inflated R² — is visible at small N; large N tightens the percentages and the ROC.

Table 2. Sample-size guidance for this pilot (per arm; intervention + matched flat controls).
TierPatients/armWhat it buys
Minimum (acceptable)~300Localization %s stable to ≈±3%, AUC to ≈±0.02; ordering (fused > ODI-4 > rMSSD) and the null-inflation point are already clear. Below ~100/arm the AUC and exact-% wobble.
Recommended~3,000Percentages to ≈±1%, AUC to the third decimal, clean ROC and accuracy bars.
This run (SUPERSEDED — see the 2026-09-22 correction above)~900912 tx + 918 flat (≥10 nights) → the same configuration yields CLAIM trNIntervention2 = 233 FROM analysis/published-numbers/treatment-response-2026-09-22.json#claims/nIntervention tx + CLAIM trNFlat2 = 239 FROM analysis/published-numbers/treatment-response-2026-09-22.json#claims/nFlatControl flat at ≥10 nights; the published ~900 per arm is not recoverable from the repository. The ≥10-night cohort attrits heavily on per-night coverage.
Diminishing returns> ~5,000Past here, extra patients barely move accuracies already pinned near their ceilings; what limits realism is the deliberately clean planted step, which more patients cannot make more realistic.

Practical reading: ~300/arm is enough to see the effect, ~3,000/arm gives publication-quality precision, and beyond ~5,000/arm the gains are cosmetic — the binding limitation is the idealized synthetic step, not sample size.

References

  1. Project documentation: CLAUDE.md (Clock Contract, evidence-grade system), COHORT-VALIDATION-BRIEF.md, CROSSNIGHT-ENVELOPE-SPEC.md, Tepna suite.
  2. Killick R, Fearnhead P, Eckley IA. Optimal detection of changepoints with a linear computational cost. J Am Stat Assoc. 2012;107(500):1590–1598.
  3. Truong C, Oudre L, Vayatis N. Selective review of offline change point detection methods. Signal Processing. 2020;167:107299.
  4. Giles TL, Lasserson TJ, Smith BH, et al. Continuous positive airway pressure for obstructive sleep apnoea in adults. Cochrane Database Syst Rev. 2006;(3):CD001106.
  5. Kasai T, Bradley TD. Obstructive sleep apnea and heart failure: pathophysiologic and therapeutic implications. J Am Coll Cardiol. 2011;57(2):119–127.
T © 2026 Michal Planicka ·Tepna v1.0.0 ·Apache-2.0 ·◈ Asheville, NC ·not a medical device
v2.23.0