Releases: pointbreaklab-hub/Heart
Heart v1.0.20 — Silent gym auto-start, overnight fix, battery alerts, tile-aware backups
What's new
Gym auto-start (no confirmation) — arrive at your saved gym, stay 2 minutes, a Gym session starts automatically. Configurable radius (100–500 m) and a live status row in Settings → Gym tells you exactly what the detector sees.
Overnight reliability fix — the background BLE service now detects 'zombie' GATT connections (link alive, no packets) and forces a clean reconnect within 5 minutes. The band keeps recording through the night.
Battery alerts — gentle notifications at 15% and 5% band battery. Re-arm only after charging back above 20%, so a hovering low battery never spams you.
Full-backup with map tiles — backups (and QR device-to-device sync) now bundle your offline map tiles. A full migration to a new phone reproduces offline maps without re-downloading. Backup schema v2.
PointBreakLab credit in Settings footer.
APK
arm64-v8a split (28.6 MB) — covers ~98% of Android devices.
SHA-256: 48f5ca7246d45c2ba9a5efc0cea3b6ef453800482d7210caedde8c043235e26b
Heart v1.0.19 — Post-workout analysis, gym auto-detection, GPS fix
What's new
Post-workout analysis — when you end a session, Heart shows a full summary: HR zone breakdown, peak/avg BPM, active calories, compare-to-last-session row, and estimated overnight HRV impact.
Gym auto-detection — Settings → Gym: pin your gym's location, pick a detection radius (100–500 m). Heart offers to start a Gym session after 10 minutes of dwell.
GPS map fix — 'Waiting for GPS…' stuck state resolved. Map now seeds from cached location instantly, falls back to network fix in <2 s.
Sleep detection after workouts — nights following a workout no longer missed due to post-exercise HR elevation.
APK
arm64-v8a split (28.6 MB) — covers ~98% of Android devices.
SHA-256: 760b5eff18872dce6183dd241fb05d21bd90b64a79382a2a36d5da90a604868d
Heart v1.0.18 — Post-workout analysis, gym auto-detection, GPS fix
What's new
Post-workout analysis — when you end a session, Heart shows a full summary: HR zone breakdown, peak/avg BPM, active calories, compare-to-last-session row, and an estimated overnight HRV impact.
Gym auto-detection — Settings → Gym: pin your gym's location, pick a detection radius (100–500 m). Heart offers to start a Gym session after 10 minutes of dwell at that location.
GPS map fix — 'Waiting for GPS…' stuck state on Walk/Run sessions resolved. The map now seeds from the device's cached location instantly, falls back to a network fix in < 2 s, and applies a more lenient accuracy gate so early satellite fixes aren't discarded.
Sleep detection after workouts — nights following a workout were missed when post-exercise HR elevation pushed the detection baseline above the hard gate. Fixed with a per-night threshold boost when a session ended within 3 hours of the night window.
Heart v1.0.16 — Session analysis, battery banner, BLE fix
What's new
- Session analysis — every session in Trends now has a Detail button. Tap it to see an interactive HR trace with zone-boundary overlays, a stacked zone-time breakdown, a stats grid (avg / max / min HR, duration, load, active kcal), a GPS map for outdoor sessions, and next-night sleep context.
- Battery optimisation banner — on Android, a one-tap amber banner on the home screen alerts you when battery optimisation is blocking overnight recording. Tap "Fix it" to grant the exemption without digging through Settings.
- BLE scanning fix — a missing ProGuard keep rule for
flutter_blue_pluscaused device scanning to silently fail in release builds. Fixed. - Duration display — sessions under 1 minute now show "< 1m" instead of "0m" in both the session list and the analysis screen.
Heart v1.0.15 — On-device ML: rhythm, readiness, personalization
What's new
Three on-device prediction features land in this release. Every algorithm is closed-form maths running purely on the user's device — no model artifact, no telemetry, no remote inference, no account. Open the source on GitHub and every threshold and weight is right there in plain Dart.
Phase 1 — Rhythm anomaly hints
Live, unsupervised detector flags windows of unusually high beat-to-beat variability (pNN50 > 30%, CoV > 10%, RMSSD > 100 ms, RR range > 300 ms). A window is flagged irregular when ≥ 3 of 4 thresholds cross. Sustained irregularity (≥ 30 s) is recorded as an episode and surfaced in Insights with its peak features.
- Home: rhythm-status chip on the Live HR card (Normal / Borderline / Irregular)
- Tap the chip for an explanation + wellness disclaimer
- Insights: "Rhythm" card with the episode list, peak feature breakdown, and embedded "not a diagnosis" framing
Wellness hint, never medical advice. If episodes recur — especially with palpitations, dizziness, or shortness of breath — see a clinician.
Phase 2 — Tomorrow's readiness forecast
One-step-ahead prediction of tomorrow's overnight RMSSD using Holt linear exponential smoothing (α = 0.45, β = 0.20) over the user's last 7–14 nights, with small modifiers for last night's sleep (±5%) and recent training load (±5%). Confidence band sized from in-sample MAE.
- Insights: top card with predicted RMSSD + range + delta vs your personal baseline
- Trend pill: Likely up / Stable / Likely down
- "Building forecast…" until 5 nights of overnight data exist
Phase 3 — Personalized sleep correction
Pragmatic per-user offset layer on the rule-based sleep stager. Once the user logs ≥ 7 paired diary nights, mean bedtime / wake offsets are computed and applied to the detected window — without any per-user model artifact.
- Insights sleep snapshot card now shows a "Personalized · N diary nights" badge when correction is active
- Defensive cap: offsets > 90 min are rejected (fall back to raw stager)
Why this design
Consumer wellness apps usually ship opaque "AI" models that nobody — including the developer — can audit after the fact. Heart goes the other way: every formula is pinned in Dart source, cited to the published literature (Holt 1957, Keytel 2005, classical HRV thresholds), and runs entirely on the device that captured the data. You can read it, you can reproduce it, you can disagree with it. The differentiator isn't "AI inside" — it's "maths you can inspect."
Engineering
- 102 / 102 unit tests pass — 16 new tests cover the ML pipeline (5 rhythm + 7 readiness + 4 personalization)
flutter analyze: 0 issues- No new runtime dependencies; APK size unchanged from v1.0.13
Build
heart-android.apk— arm64-v8a, 21 MB. SHA-256:691fe24acaae8aec1d7911d3fcefcf1fa978a710b64e23a927c094026ac04e03heart-android-universal.apk— fat APK, 61 MB. SHA-256:2e5f10c080f74389c3ccaa711205773264158a5a9aadfaf4427d9c9910561fb8- Same release certificate as every prior version — clean upgrade.
Heart v1.0.13 — Active calories on Home
What's new
Home screen — active calories today
- New card under the Live HR hero showing today's running active-calorie total + the live kcal/min rate.
- Total = Σ kcal from the last 24h of HR samples, gated to HR ≥ 90 bpm so the resting band doesn't contribute phantom calories.
- Updates whenever a new HR sample arrives — no polling timer, the card reflects the live BPM stream.
- Hides itself on sedentary days (< 5 kcal accumulated) so the home screen doesn't show "3 kcal" front and centre.
- Tap the (i) for the methodology and the Keytel-formula caveats.
No algorithm changes since v1.0.12. The compute infrastructure (todaysCaloriesProvider, liveCalorieRateProvider, CalorieEstimator) was already in place — this release just surfaces it on the home screen.
Build
heart-android.apk— arm64-v8a, 22 MB. SHA-256:d71fa93a930eb69a3b588764e9bd09d065768d302cfe97630afc7597d9304abbheart-android-universal.apk— fat APK, 62 MB. SHA-256:d0b9def3e506bb977a7f616e3b38cc924a0f6296641fa7d08ba7b2653a51d040- Same release certificate as every prior version — clean upgrade.
Heart v1.0.12 — Sleep stager verified against realistic data
What's verified
This release is the same Dart stager-constants fix as v1.0.11, but now backed by a synthetic-noise regression test that mirrors real Coospo HW9 data quality. The test fails on the pre-v1.0.11 constants and passes on the new ones — guarantees the fix doesn't regress.
Cross-check before build
- Algorithm hand-traced with realistic numbers:
restingBpm=64, sleep mean=70, std=5, coverage=0.7 → score ≈ 0.84, clears the new 0.7 onset gate. Old constants gave ≈ 0.55, never opened. - New
detects 7-hour sleep with realistic noise (std≈5 bpm, 1 Hz)test added totest/sleep_staging_test.dart— generates a triangle-wave BPM around mean 65 with ±9 bpm swing (std ≈ 5.2) at 1 Hz coverage, expects detection to find ≥ 6 hours. - All 86 tests pass.
- Provider chain confirmed: Trends → Sleep reads
resolvedSleepMinutesProvider→jsonlSleepStagingProvider(runs the fixed stager fresh, no stale cache involved).
Stager constants (unchanged from v1.0.11, now test-locked)
_hrStdMax: 4.0 → 8.0_sleepOnsetThreshold: 0.85 → 0.7_minDurationMinutes: 180 → 120
Build
heart-android.apk— arm64-v8a, 22 MB. SHA-256:fa208e0f46385b1032b067fbb0c9b1c31ecfd3568f3fb5ecb8a0bbdbae906af6heart-android-universal.apk— fat APK, 62 MB. SHA-256:f89e49d9d504369b5b93b39dab1f5554e359d03ea019b7c572bf3cc3d4b1dca6- Same release certificate as every prior version.
Heart v1.0.11 — Sleep tab actually shows last week
What's fixed
Trends → Sleep tab empty even with HR data on disk
The Dart sleep stager had three constants set far too tight for real-world Coospo HW9 data quality:
_hrStdMax = 4.0— required heart-rate std-deviation < 4 bpm in every 5-min window. Real overnight traces have std around 4–6 bpm even during deep sleep; the stability score collapsed to 0 on most windows._sleepOnsetThreshold = 0.85— to OPEN a sleep period, a single window had to score ≥ 0.85. Under realistic data quality (BLE coverage ~0.5 sample/sec, std 4–6 bpm) the maximum achievable score for a clean sleep window was ~0.85 itself. The gate effectively never opened — Trends → Sleep stayed empty for entire weeks even with 60k samples per night on disk._minDurationMinutes = 180— rejected anything under 3 hours. Disturbed-sleep nights (2.5 h with multiple awakenings) had nothing to show.
Fix:
_hrStdMax→ 8.0 (matches Kotlin'sSLEEP_STD_MAX_BPM = 8.0so Dart and native paths agree)_sleepOnsetThreshold→ 0.7 (still rejects quiet pre-sleep wakefulness, which scores ~0.65 with the level-score component dragging it down)_minDurationMinutes→ 120 (shows 2-hour-plus blocks instead of erasing them)
After upgrading, open the app once. The Trends → Sleep chart will populate with the last week's nights within seconds.
Build
heart-android.apk— arm64-v8a split, 22 MB. SHA-256:710897fa8bca37cfcd5f0088818b2f200ce0eeec25f1ae5e0b2db5bac954c3baheart-android-universal.apk— fat APK, 62 MB. SHA-256:41947c6f0c9de28a723869f98f53faa22add04d22473492e2a6f2683f03faca5- Same release certificate as every prior version — clean upgrade.
Heart v1.0.10 — Stale sleep summaries auto-recompute
What's fixed
Sleep card empty for past nights, even though raw HR was recorded
Root cause: SleepSummaryStore (the SharedPreferences cache the UI reads from) was only ever written by the Android native service, which used a different and historically buggier HR-threshold formula (p15 + 12 with no cap). When v1.0.6 fixed the Dart JsonlSleepStager, that fix never propagated to cached summaries — the Dart stager wasn't a writer of the cache. Result: nights computed by the legacy native formula stayed stuck at 0 minutes even after the app was upgraded.
Two-part fix
- New
SleepSummaryRefresherruns at app launch and on resume. For each of the last 7 nights it executes the (now-correct) DartJsonlSleepStagerdirectly against the rawheart_samples/*.jsonlfiles and overwrites whatever was cached. The dependent providers (yesterdaySleepProvider) are invalidated so the UI redraws immediately. Cost: ~7 stager runs at launch — bounded by sample-file size, sub-second on a phone. - Native Kotlin
computeSleepSummarynow uses the Dart-equivalent formula:min(p15, max(restingBpm, 75)) + 8instead ofp15 + 12. Also reads the personalised resting BPM from prefs (default 64) instead of treating every user the same. Future nights computed by the background service while the app is closed will now match what the Dart stager would produce.
After upgrading, open the app once — the missing nights will appear within seconds.
Build
heart-android.apk— arm64-v8a split, 22 MB. SHA-256:c0e99b7cedcc9b9bbe028e4d907ff3b2548344305d20eeb3512a1091a5a7b6d2heart-android-universal.apk— fat APK, 62 MB. SHA-256:7b191b42ebecd3f797ce74d85aae3cfb29b4012add98913a62ac3a32e7d53d1b- Same release certificate as every prior version — clean upgrade.
Heart v1.0.9 — Sleep diary removed, detection-quality indicator instead
What's new
No more manual sleep validation
- The morning sleep-diary prompt and the Insights diary-validation card are gone. Asking users to recall last night's bedtime/wake-time is unrealistic — most people don't remember accurately, and the prompt was friction without a payoff.
- Replaced with a Detection quality indicator on the Sleep snapshot card in Insights. It's a labelled bar (Low / Medium / High + percentage) that shows how confidently the rule-based stager classified the night. No user input required.
- High — clean overnight HR signal, sustained low BPM, low variance: scores are solid.
- Medium — some noise (band off-body briefly, fragmented sleep, late activity).
- Low — atypical night: travel, illness, broken sleep, off-body for long stretches. Treat the detail as directional.
- Tap the (i) on the bar for the full explanation.
Files removed
lib/src/core/sleep_diary.dart(store)lib/src/features/sleep_diary/(morning prompt + bottom-sheet entry form)lib/src/features/insights/cards/diary_validation_card.dartSleepDiaryStore.initialize()frommain.dartstartupsleep_diaryfield from data export schema and import logic
Build
heart-android.apk— arm64-v8a split, 22 MB. SHA-256:f92c4b1f1f612f936c7ca13fa49d36767216b69ae2f8150e498cb7952885bd9eheart-android-universal.apk— fat APK with all ABIs, 62 MB. SHA-256:75e821c953e2a93f9749e200e4ce186b580a242ef9a1691e88bb141fc8d42c43- Same release certificate as every prior version — clean upgrade from v1.0.8 / v1.0.6.