Skip to content

avgSdnn/sdnnIndex: Swift-only metric whose doc comment claims a nonexistent Kotlin twin #18

Closed
ryanbr/noop
#1535

Description

@bhelm

Part of the drift-control plan in #17 (plan step 2); split out because it needs a scope decision, not just a fix.

The claim vs. the tree

HRVAnalyzer.swift:304 documents sdnnIndex with "Kotlin twin: HrvAnalyzer.sdnnIndex" — that function does not exist. sdnnIndex / avgSdnn have zero matches under android/.

This is not a dead helper on the Swift side. The value is production surface:

  • computed per day in AnalyticsEngine (avgSdnn: at AnalyticsEngine.swift:822);
  • persisted through WhoopStore (Database.swift, MetricsCache.swift);
  • consumed by the macOS app layer (Strand/Data/Repository.swift, Strand/Data/IntelligenceEngine.swift) and the iOS HealthKit bridge (StrandiOS/Health/HealthKitBridge.swift).

So Android users simply don't have the metric, and the stored-data surface of the two platforms differs — the exact class of drift docs/CROSS_PLATFORM.md promises can't happen.

The decision needed

Two honest ways to close this, and the choice is a maintainer call because it touches the Android schema:

  1. Port it: implement sdnnIndex/avgSdnn in Kotlin, including the Room storage for the persisted daily value — i.e. a versioned Room migration, pinned by a migration test, with column order matching the entity (CLAUDE.md rules).
  2. Declare it platform-specific: keep it Swift-only, record it as an explicit non-twin entry in the parity twin map (drift/01-twin-ledger) so the ledger stops flagging it — visible and deliberate instead of silently divergent.

Until decided, drift/02b-avgsdnn only corrects the false twin claim in the Swift doc comment so the tree stops asserting a twin that isn't there. The twin ledger (#17, plan step 1) catches this class mechanically from now on (a declared twin reference must resolve on the other side).

Activity

  1. bhelm commented on Aug 21, 2026

    @bhelm
    OwnerAuthor

    Decision (2026-08-22): port sdnnIndex / persisted avgSdnn to Android rather than declaring the metric permanently Swift-only.

    The implementation must be a complete product port, not a ledger waiver:

    • mirror the Swift algorithm, units, nullability, cleaning rules, and segment-boundary behavior in Kotlin;
    • compute the value in the Android daily analytics path;
    • persist it through the Room daily-metric surface with a versioned, lossless migration;
    • cover algorithm vectors, migration, DAO/cache round-trips, and the production call path;
    • prove Swift/Kotlin agreement on boundary cases;
    • remove the temporary governance exemption once the Android declaration exists.

    The change will be independently reviewed and fixed until no P0/P1 findings remain before an upstream PR is opened. This issue stays open until the complete port is merged and verified.

  2. bhelm commented on Aug 21, 2026

    @bhelm
    OwnerAuthor

    Portierung ist nach zwei unabhängigen Abschlussreviews mit P0=0/P1=0 als Upstream-PR veröffentlicht: ryanbr#1535. Das Issue bleibt bis zum Merge offen.

  3. bhelm commented on Aug 22, 2026

    @bhelm
    OwnerAuthor

    Integration verification (2026-08-22): tested end to end on Android staging after merging the reviewed port into bhelm/integration (74807ae9). A newly exported .noopbak reports Android schema version 32; the embedded Room database passes PRAGMA quick_check and integrity_check, contains trailing nullable dailyMetric.avgSdnn, and has three recent nights with non-null, distinct avgHrv (RMSSD) and avgSdnn values. This verifies the production calculation, persistence, and backup/export path on real app data. Algorithmic correctness remains covered by the mirrored vectors, full test suites, and the two P0/P1=0 reviews on ryanbr#1535. The issue should remain open until the upstream PR is merged.

  4. bhelm commented on Sep 7, 2026

    @bhelm
    OwnerAuthor

    Fixed upstream by ryanbr#1535 (merged), which took option 1 and ported the SDNN index to
    Android: HrvAnalyzer.sdnnIndex, wired into AnalyticsEngine, with the avgSdnn Room column,
    its migration and mirrored tests. The comment now describes a twin that exists. Closing.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions