Skip to content

Sleep rescue (manual entry + HR-led fallback) + wear record-presence fix; release v0.6.0 - #33

Merged
abdulsaheel merged 2 commits into
mainfrom
feat/sleep-rescue-and-wear-fix
Jun 30, 2026
Merged

Sleep rescue (manual entry + HR-led fallback) + wear record-presence fix; release v0.6.0#33
abdulsaheel merged 2 commits into
mainfrom
feat/sleep-rescue-and-wear-fix

Conversation

@abdulsaheel

Copy link
Copy Markdown
Collaborator

Summary

Closes the v0.6.0 release. Builds on the merged v25 work (coach read-only SQL, 24/7 irregular-rhythm screen, HRR, BRV, auto-workout suggestions) with two sleep/wear improvements.

Sleep rescue

  • Manual sleep entry — user can assert onset/wake when detection missed a night. Stored in a new sleep_override table (keyed by day_id, separate from day_result), so it survives finalization and kAlgoVersion bumps (queried fresh per derive, never cached). Guarded against clobber when the day's raw is already pruned (≥14d).
  • HR-led fallback — when accel-led detection finds nothing, a conservative nocturnal HR-dip detector proposes a window, staged through the same segmentSleep(forcedWindow:) code (single-source invariant held), surfaced as low-confidence with an "is this right?" confirm/edit prompt.

Wear fix

Coverage now counts record presence (a 1 Hz record exists) rather than hr > 0. PPG only locks HR on a still wrist, so a 24h-worn day previously showed only ~7–8h. Off-wrist = >120s record gap.

Analytics (OpenStrap/analytics@main, already merged)

segmentSleep(forcedWindow:), AdvancedSleepStager.stageWindow, and hrLedSleepWindow (#14).

Versioning

kAlgoVersion → 28 (v27 wear fix, v28 sleep rescue); db → v20 (sleep_override). Finalized days recompute on next pass.

Tests

edge flutter test --concurrency=1 → 102 green; analyze clean. analytics dart test → 231 green.

🤖 Generated with Claude Code

Sleep rescue (Approaches 1 & 2) for nights auto-detection misses:
- sleep_override table (db v19->v20): durable manual/confirmed windows, stored
  separately from derived output so they survive finalization AND algo bumps.
- thread override + HR-led fallback + sleep_source through calendarDays ->
  prepareDerivationPayload -> prepareSleepSessionCandidate -> engine.
- finalization override: force re-derive an overridden day even when locked;
  skip the auto cache for it; no-raw clobber guard keeps a good manual result
  once raw is pruned (>14d).
- app_state setSleepOverride / confirmSleep / clearSleepOverride.
- Sleep screen: manual-entry card (no-sleep night), fallback confirm banner,
  manual badge (edit / use auto), and an edit affordance on auto nights.

Wear fix:
- worn-time / coverage / on-off segments were defined as hr>0, but PPG only
  locks on a still wrist with good contact (~sleep), so a 24h-worn day showed
  ~7-8h. Wear is now RECORD presence with gap detection. Fixed in the worn_min
  scalar, _wearBlock, and the repo fallback.

kAlgoVersion 26 -> 28 so affected days restage.
Bump version for the v0.6.0 release: coach read-only SQL, 24/7 irregular-rhythm screen, HRR, BRV, auto-workout suggestions, manual sleep entry + HR-led fallback staging, and the wear record-presence fix.
@abdulsaheel
abdulsaheel merged commit 025ed38 into main Jun 30, 2026
@abdulsaheel
abdulsaheel deleted the feat/sleep-rescue-and-wear-fix branch July 12, 2026 05:54
Pablodvs added a commit to Pablodvs/edge that referenced this pull request Aug 22, 2026
…col at OpenStrap#33's head

The docs told a mechanism the evidence no longer supports: the rich form
executes on at least one other WHOOP 4 (PR OpenStrap#265 review, 2026-08-11 export),
and short/rev-1 pad4 to byte-identical frames at haptic-mode 0 — so every
behavioural claim now carries its firmware (41.17.4) and provenance, and the
"silent-alarm root cause" / "two bytes are the whole difference" wording is
gone. pubspec pins protocol OpenStrap#33's rebased head 4ce8f02: the old pin b7990e1
does not export alarmRev1Payload, so a fresh checkout failed analysis
(CodeRabbit). kProtocolPin moves with it; kAlgoVersion holds at 76 — the hop
is command builders only, no decoder line moves. gen5's composed 21-byte
body gets one exact-bytes vector, crescendo=1 included.
abdulsaheel added a commit that referenced this pull request Aug 23, 2026
the pin said d9362a6 — analytics main — and every cadence fix lives on
d6ba41c. pubspec_overrides is gitignored, so my phone build resolved
path: ../analytics and got them; CI has no overrides and would have
built v77's changelog against analytics without a single one of the
analytics-side fixes in it.

that's the v42 shape the comment at the top of this file already warns
about: edge v43 documented the MAD fallback, the pinned sha never had
it, and the bug stayed live through 0.9.15.

pubspec, kAnalyticsPin and the lockfile all say d6ba41c now, and the
lock is regenerated with the overrides moved out of the way so CI
resolves the same bytes.

protocol stays on 4ce8f02 — that's #33's head, which is the fix itself;
main's f01ad07 is the merge plus a docs commit and moves no decoder.
DropTabl added a commit to DropTabl/edge that referenced this pull request Aug 26, 2026
…ntics; flag the pending OpenStrap#35 repin

Three follow-ups on the bootstrap review:

A Memfault chunk is real inbound traffic on the link, so it now advances
_lastRx like every other notification — a strap volunteering crash data
must not look silent to the staleness fuse and get its link bounced.

New regression test for the SET_CLOCK result split the contract implies:
a FAILURE result inside a non-null response object still satisfies
readiness (only a null result fails, one write,
no resend) — but the strap did NOT take the write, so the phone-suspect
history deferral computed off the pre-correction reading stays live;
clearing it is reserved for an accepted correction.

The protocol pin stays at 4ce8f02 (OpenStrap#33's tree, whose parser still nulls
any non-1 hello revision — under the mandatory hello that means a future
revision bump cannot connect). OpenStrap/protocol#35 lifts that gate; the
pending repin is now documented at BOTH pin locations — pubspec.yaml's
ref and kProtocolPin in derivation_engine.dart — with the rule that every
pin location moves together to the main merge commit (the pin-equality
test fails a partial repin) and the kAlgoVersion no-bump reasoning to
re-verify against the actual merge diff.
DropTabl added a commit to DropTabl/edge that referenced this pull request Aug 26, 2026
…ntics; flag the pending OpenStrap#35 repin

Three follow-ups on the bootstrap review:

A Memfault chunk is real inbound traffic on the link, so it now advances
_lastRx like every other notification — a strap volunteering crash data
must not look silent to the staleness fuse and get its link bounced.

New regression test for the SET_CLOCK result split the contract implies:
a FAILURE result inside a non-null response object still satisfies
readiness (only a null result fails, one write,
no resend) — but the strap did NOT take the write, so the phone-suspect
history deferral computed off the pre-correction reading stays live;
clearing it is reserved for an accepted correction.

The protocol pin stays at 4ce8f02 (OpenStrap#33's tree, whose parser still nulls
any non-1 hello revision — under the mandatory hello that means a future
revision bump cannot connect). OpenStrap/protocol#35 lifts that gate; the
pending repin is now documented at BOTH pin locations — pubspec.yaml's
ref and kProtocolPin in derivation_engine.dart — with the rule that every
pin location moves together to the main merge commit (the pin-equality
test fails a partial repin) and the kAlgoVersion no-bump reasoning to
re-verify against the actual merge diff.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant