Repository navigation
hrv: sample the densest second on an over-count night (#1008) - #1117
Merged
Merged
Conversation
The always-on `hrv diag` line says THAT a night is R-R over-counted (coverage>1) and whether the extra beats straddle second boundaries, but not WHY. A WHOOP 4.0 report (#1008) shows measured 9.3.1 nights still at coverage 2.1-2.4 / crossSecondOverCount — and the #1071 srcChannel filter is Oura-only, so those untagged beats pass through and the mechanism is unknown. Add `densestSecondWindowSample`, a pure, integer-formatted twin on both platforms that dumps the raw rows around the densest second — emitted ONLY on an over-count verdict (clean nights stay quiet). The row shape is the diagnosis: near-equal values (`[1200,1199]`) mean the same beat stored twice (de-dupable); a full interval beside a partial one (`[1200,600]`) means two distinct trains; `src=none` confirms the beats are untagged. Deliberately statistics-free: at second-resolution ts a genuine consecutive beat and a duplicate both look like a near-equal beat ~1s away, so a derived de-dup number would be unreliable (the #550 trap) — raw rows carry no such inference. Instrumentation only; no shipped value changes. Exact-string tests pin byte-parity across Kotlin and Swift.
Add tie / truncation / short-srcCodes / half-value-rounding fixtures to both test suites asserting the SAME literal output, so byte-parity across Kotlin and Swift is pinned for the cases the three headline shapes don't exercise (densest-second tie → earliest, equal-rrMs index tie-break, +K truncation marker, index-guarded short srcCodes). Verified: the Kotlin suite and an independent Swift run produce identical strings.
This was referenced Aug 7, 2026
ryanbr
added a commit
that referenced
this pull request
Aug 9, 2026
…ery) (#1192) A testing-build capture showed ~186 full 18-day analyzeRecent sweeps in 7.5 hours on a flapping WHOOP 4.0 link — but the strap log never said WHY each ran or whether new data drove it, so the empty-offload re-score waste (#1005/#1146) couldn't be measured. The post-offload pass re-scores with force:true on BOTH platforms, so a completed but EMPTY/duplicate offload (rows=0, common on a flapping link) still folds the whole raw store for zero new data. This logs, at that forced re-score, whether the pre-run HR fingerprint (rowCount:maxTs) still equals the watermark the last successful run advanced: re-score: trigger=post-offload newData=no (empty/duplicate offload — nothing changed) `newData=no` lines are the wasted re-scores — turning "186 sweeps" into a measured count of how many folded 18M rows for nothing. - Android: at the WhoopBleClient post-offload trigger (compares to NoopPrefs watermark). - Swift: inside analyzeRecent, gated on `force`, at the fingerprint it already computes. Log-only, no behaviour change (the pass still runs). NOT touching the re-score/reconnect logic — measuring first, per the instrument-first pattern (#1117, #688). The reconnect backoff-reset half is already legible in the existing `attempt N, held Xs` line by design (the linkUpSinceMs comment), so no new logging there.
simoncad7
pushed a commit
to simoncad7/noop
that referenced
this pull request
Aug 17, 2026
…yanbr#1117) * hrv: sample the densest second on an over-count night (ryanbr#1008) The always-on `hrv diag` line says THAT a night is R-R over-counted (coverage>1) and whether the extra beats straddle second boundaries, but not WHY. A WHOOP 4.0 report (ryanbr#1008) shows measured 9.3.1 nights still at coverage 2.1-2.4 / crossSecondOverCount — and the ryanbr#1071 srcChannel filter is Oura-only, so those untagged beats pass through and the mechanism is unknown. Add `densestSecondWindowSample`, a pure, integer-formatted twin on both platforms that dumps the raw rows around the densest second — emitted ONLY on an over-count verdict (clean nights stay quiet). The row shape is the diagnosis: near-equal values (`[1200,1199]`) mean the same beat stored twice (de-dupable); a full interval beside a partial one (`[1200,600]`) means two distinct trains; `src=none` confirms the beats are untagged. Deliberately statistics-free: at second-resolution ts a genuine consecutive beat and a duplicate both look like a near-equal beat ~1s away, so a derived de-dup number would be unreliable (the ryanbr#550 trap) — raw rows carry no such inference. Instrumentation only; no shipped value changes. Exact-string tests pin byte-parity across Kotlin and Swift. * hrv: pin densest-second sample parity edge cases (ryanbr#1008) Add tie / truncation / short-srcCodes / half-value-rounding fixtures to both test suites asserting the SAME literal output, so byte-parity across Kotlin and Swift is pinned for the cases the three headline shapes don't exercise (densest-second tie → earliest, equal-rrMs index tie-break, +K truncation marker, index-guarded short srcCodes). Verified: the Kotlin suite and an independent Swift run produce identical strings.
simoncad7
pushed a commit
to simoncad7/noop
that referenced
this pull request
Aug 17, 2026
…ery) (ryanbr#1192) A testing-build capture showed ~186 full 18-day analyzeRecent sweeps in 7.5 hours on a flapping WHOOP 4.0 link — but the strap log never said WHY each ran or whether new data drove it, so the empty-offload re-score waste (ryanbr#1005/ryanbr#1146) couldn't be measured. The post-offload pass re-scores with force:true on BOTH platforms, so a completed but EMPTY/duplicate offload (rows=0, common on a flapping link) still folds the whole raw store for zero new data. This logs, at that forced re-score, whether the pre-run HR fingerprint (rowCount:maxTs) still equals the watermark the last successful run advanced: re-score: trigger=post-offload newData=no (empty/duplicate offload — nothing changed) `newData=no` lines are the wasted re-scores — turning "186 sweeps" into a measured count of how many folded 18M rows for nothing. - Android: at the WhoopBleClient post-offload trigger (compares to NoopPrefs watermark). - Swift: inside analyzeRecent, gated on `force`, at the fingerprint it already computes. Log-only, no behaviour change (the pass still runs). NOT touching the re-score/reconnect logic — measuring first, per the instrument-first pattern (ryanbr#1117, ryanbr#688). The reconnect backoff-reset half is already legible in the existing `attempt N, held Xs` line by design (the linkUpSinceMs comment), so no new logging there.
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.
What
Instrumentation for the R-R over-count surfaced by #1008. The always-on
hrv diagline already reports THAT a night is over-counted (coverage>1) and whether the excess beats are same- or cross-second, but not WHY. The #1008 strap log shows a WHOOP 4.0 on 9.3.1 whosemeasured(live-captured) nights still readcoverage=2.1-2.4/crossSecondOverCount— and the #1071srcChannelfilter is Oura-only, so those untagged WHOOP beats pass straight through. The mechanism is unknown.Add
densestSecondWindowSample— a pure, integer-formatted twin on both platforms that dumps the raw R-R rows around the densest second, emitted only on an over-count verdict (clean nights stay quiet). The row shape is the diagnosis:[1200,1199]) → the same beat stored twice (de-dupable / channel-taggable),[1200,600]) → two distinct interval trains (a genuine second stream, not a duplicate),@Nsuffix → a non-nullsrcChannel;src=noneconfirms the beats are untagged, so the Oura [oura][hrv]rrIntervalmixes two optical channels, so every beat is stored twice #1071 path does not apply and a WHOOP over-count is a different mechanism.Example line:
Why statistics-free
At second-resolution
ts, a genuine consecutive beat and a duplicate both look like "a near-equal beat ~1 s away", so any derived de-dup number would be unreliable — the #550 trap. Raw rows carry no such inference; the reader sees the actual duplication and picks the fix (seq/write-path de-dup vs channel tag vs "it's real dense capture").Scope
avgHrv, RMSSD, SDNN, gates all untouched.HrvAnalyzer.densestSecondWindowSample(Kotlin) andHRVAnalyzer.densestSecondWindowSample(Swift) use integer-only formatting; exact-string tests on both platforms assert identical output.Verification
testFullDebugUnitTest --tests HrvRrCoverageTestpasses (4 new tests) + module compiles.HRVAnalyzerTestscover it (runs inswift-packages.yml).Strand/Data/IntelligenceEngine.swift) is compile-validated viaapp-build.yml(CI does not compile app targets by default).Groundwork for #1008: a fresh strap log on this build makes the WHOOP 4.0 over-count's mechanism readable, which decides the actual fix (write-path de-dup vs channel tag vs RMSSD gate).