Repository navigation
Healthspan v2 (1/3): target-anchored Body Age engine, SRI, projected pace - #12
Merged
Merged
Conversation
SRI = 200 · P(same sleep/wake state at t and t + 24 h) − 100 over 30-second epochs, from sleep sessions and their wake stretches. Local noon-to-noon days with no session drop out, so an unworn night is not scored as irregular. Per-pair agreement is exposed so a caller can compute it once and re-window it.
…model) - Referent moves from "average for your age" to "meeting health targets", WHOOP's anchor; years are 10 · ln(HR) (Spiegelhalter 2016). - Device-scale targets and curves: SRI hinge (Windred 2024), asymmetric sleep duration down-weighted beside SRI, %HRR zone 1–3 / 4–5 minutes (Ekelund, Ahmadi), strength ≥ 40 min/wk, age-dependent steps (Paluch), VO₂max age/sex target, resting HR 60 / 64, lean-mass percentage. - HRV is no longer scored (non-causal, U-shaped); the norm stays for context. - A strap-derived VO₂max folds into resting HR; an external one scores alone. - Adds biggestLever, the unlock gate (21 scored days in 31, age 18+) and Inputs.restricted(to:). - The cross-domain shrink is calibrated to 0.9 so the average US 30-year-old man / woman read +5.9 / +7.4 (WHOOP white paper Table 2: +6 / +7.5).
PaceOfAgingEngine.project holds the last-30-day averages for six months: pace = 1 + (Δrecent − Δsix-month) / 0.5 y, clamped −1…3×, with both windows compared over the drivers they share. The ±margin comes from the spread of the monthly windows (a prior until three exist). The legacy OLS fit stays until the pipeline moves off it.
…acle healthspan_v2.json is produced by compiling the three engines standalone with Tools/oracle-twins/healthspan_v2_twin.swift: every curve over its domain, at-target people (Δ = 0), the average US 30 M / 30 F calibration people, SRI on synthetic schedules and pace-projection edge cases. It replaces the v1 oracle, which pinned the retired population referent.
Lean mass now needs body weight rather than height, and HRV / the duration-CV regularity no longer feed Body Age. Sleep regularity (SRI) and %HRR zones are wired in by the pipeline change that follows.
HRZones.heartRateReserveZones builds the Karvonen 50/60/70/80/90 % HRR zone set, the model the Healthspan zone targets are stated in and the one StrainScorer already uses.
SleepRegularity.session reads the wake segments of a computed staging array; an imported minute dictionary keeps its span with no wake stretches.
…nsaction replaceMetricSeries deletes the named keys in [from, to] and upserts the new rows atomically, so a recomputed window that drops a key cannot leave the old row behind or expose an empty window between two writes.
…ears, daily - One resolver builds the 182-day, 30-day and monthly windows from stored history. - The day scan banks %HRR zone 1–3 / 4–5 minutes (zone_min_hrr_*). - Sleep regularity is the SRI from stored sleep sessions; VO₂max comes from the strap estimate or an import (tagged external); lean mass is a percentage of body weight. - Unlocks at 21 scored days in the last 31. Each unlocked day persists body_age, vitality, pace_of_aging (+ margin), body_age_projected and, per driver, hs_years/value/target/recent. - A healthspan_model marker triggers a one-shot, idempotent re-derivation of two years of history under the v2 model, clearing the Saturday-keyed v1 rows.
Nothing calls it since the pipeline moved to PaceOfAgingEngine.project.
…line HealthspanDrivers.latest reads the hs_* rows written for the same day as the stored Body Age, replacing the 7-day recomputation, so the Healthspan rows and the Health hub's helping-most / holding-back line use exactly the shares the headline was summed from.
- Hero: six-month Body Age vs calendar age with its ± band, and a 21-of-31-scored-days countdown until it unlocks. - Pace dial: −1…3× in four bands (reversing / slowing / steady / accelerating), the margin, and the projected Body Age in six months; "holding steady" whenever the margin covers 1×. - Biggest lever: the years reaching that driver's target would take off. - Drivers: value, target, a signed years chip and a 30-day-vs-6-month arrow; tapping opens the driver's hazard-ratio curve and its source. - Six-month Body Age and pace trend charts, HRV as unscored context, and a method-and-references sheet. - Every readout comes from one snapshot of the persisted rows for the newest day, so the chips, lever, dial and chart cannot disagree with the headline.
This was referenced Sep 23, 2026
Healthspan v2 (3/3): rebuilt Healthspan tab
Healthspan v2 (2/3): six-month windows, %HRR zones, SRI, persisted per-driver years
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
PR 1 of 3 for the Healthspan v2 plan (
docs/superpowers/plans/2026-09-23-healthspan-v2.md, added here). This PR changes the engine. The pipeline and tab PRs are stacked on top of it.What changes
VitalityEngineis upgraded in place, so it can be compared with WHOOP's Healthspan white paper (rev. 2025-09-04):biggestLeverInputs.restricted(to:)Result.unclampedBodyAgeSleepRegularity. A new pure helper for the timing-based Sleep Regularity Index, computed over 30-second epochs. Local noon-to-noon days with no session drop out.PaceOfAgingEngine.project. WHOOP's definition: hold the last 30 days for six months, so pace = 1 + (Δ30d − Δ6mo) / 0.5 y, clamped to −1…3×.The one calibrated constant
The cross-domain overlap shrink is raised from 0.75 to 0.9. This makes the average US 30-year-old man read +5.9 y and woman +7.4 y. WHOOP's Table 2 gives +6 / +7.5. At 0.75 they read +4.9 / +6.2.
Verification
Packages/StrandAnalytics/Tests/StrandAnalyticsTests/oracles/healthspan_v2.jsonis generated by compiling the three engines standalone withTools/oracle-twins/healthspan_v2_twin.swift(swiftc -O). It covers:VitalityEngineTests,PaceOfAgingEngineTestsandHealthspanOracleTestswere updated on purpose. The reason for each change is written in the tests. The v1 oracle is replaced, not edited.swift testinPackages/StrandAnalytics: 2,119 tests, 0 failures.xcodebuildsucceeds forStrand(macOS) andNOOPiOS(built without the embedded watch app, because the watchOS runtime is not installed locally). The HealthspanStrandTestspass.No BLE, schema-migration or UI-copy changes.