Skip to content

True daily steps from the RingConn record stream - #37

Merged
kenblizzardcaron merged 4 commits into
mainfrom
feat/ringconn-steps
Jul 9, 2026
Merged

True daily steps from the RingConn record stream#37
kenblizzardcaron merged 4 commits into
mainfrom
feat/ringconn-steps

Conversation

@kenblizzardcaron

Copy link
Copy Markdown
Owner

Summary

Replaces the live-bout counter (shipped in #36 / v0.33.0, wrong at rest) with the ring's true daily step total, computed by summing its stored 2.5-minute activity records — the same records the official app uses.

Protocol (reverse-engineered + hardware-verified on Gen2)

  • Record frames are fixed-width, XOR-trailed: <id> 00 <remaining> + n records; 4c = activity (steps u8 at body[14]), 47 = wellness. Timestamps are u32 BE seconds since 2020-01-01 UTC+8.
  • The ring replays records since a shared per-stream ack cursor — there is no fetch-since command (02 00 <ts> is a time-sync).
  • Sleep-flagged buckets (body[6:11] all 01) are phantom sleep-movement steps and are excluded (product decision).

Ack architecture (the hard-won part)

  • Acking 4c frames permanently steals activity records from the official app (shared cursor — verified on device, at the cost of one day's RingConn history).
  • Never acking stalls after one read: the ring re-sends the pending 47 frame forever and gates the 4c stream behind it.
  • Final policy: ack 47/11 (c7/91), never cc. Activity records replay idempotently to us (persisted watermark dedupes) while the official app keeps receiving and acking everything — verified at btsnoop payload level across three consecutive reads plus a subsequent official-app sync.

Implementation

  • RingRecords — pure frame parser + ack builder (11 tests on real capture vectors)
  • RingDailySteps — persisted daily sum + replay watermark, local-midnight rollover (7 tests)
  • AndroidRingStepsSource — write queue, record replay, quiet-timer completion, time-sync; returns today's persisted total. Merge semantics stay max(ring, HC).

Verification

  • 630 unit tests, detekt, lint all green
  • On-device (Pixel 7 + Gen2 ring): three consecutive reads banked +138/+181/+53 with exact watermark dedupe; official app subsequently received the identical records — coexistence proven

Before merging (cuts release v0.34.0)

  • Hard-run capture to settle u8 step-field saturation (protocol in plans/2026-07-08-ringconn-hardrun-capture.md)
  • Optional: next-morning sleep-exclusion parity check vs the official app on a clean day

🤖 Generated with Claude Code

kenblizzardcaron and others added 4 commits July 8, 2026 20:18
…ve-bout counter

Protocol (reassembly re-analysis of the 11.4h capture, plan doc updated):
records replay since the last acked frame as fixed-width 4c/47 frames
(XOR-trailed, b2 = remaining, ack = id|0x80); 02 is time-sync, not
fetch-since; sleep-flagged buckets (body[6:11] all 01) are phantom steps
and excluded per product decision.

- RingRecords: pure frame parser + ack builder (11 tests, real capture
  vectors)
- RingDailySteps: persisted daily sum + replay watermark, local-midnight
  rollover (7 tests; fixed a watermark-regression double-count bug)
- AndroidRingStepsSource: write queue, record replay + persist-then-ack,
  drain/quiet completion, official-app post-auth sequence (d0, time-sync,
  07 poll); returns today's persisted total

Pending hardware verification: does the ring replay records to our
client, ack-cursor behavior vs the official app, u8 step-field width
under a hard run.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…fied coexistence

Pure per-frame acking consumed the day's records away from the official
app (shared per-stream cursor); pure no-ack stalled after one read (the
ring gates the 4c stream behind the pending un-acked 47 frame). Final
policy, payload-verified in a full btsnoop: c7/91 acks unblock the
session, no cc ever — activity records replay idempotently to us from
the shared cursor (RingDailySteps watermark dedupes) while the official
app still receives and acks every record afterwards. Verified over three
consecutive reads (+138/+181/+53, exact dedupe) plus an official-app
sync receiving the identical window.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@kenblizzardcaron
kenblizzardcaron merged commit f7bba25 into main Jul 9, 2026
4 checks passed
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