feat(whoop): per-resource cursors, by-id refresh, and full-sync backfill

Give each WHOOP collection its own incremental cursor in a resource_cursors
map so a slow or rejecting collection no longer drags the sync window forward
for its siblings; legacy connections fall back to the shared last-synced
timestamp. The update webhook now carries the record id and triggers a
targeted single-record refresh instead of re-walking the collection, and a
full sync anchors at a fixed deep start so a backfill covers the span an
incremental tick skips. Cursor advances are a single atomic update guarded by
GREATEST so the independent resource queues cannot race each other backward.

Ingest row shape, source tagging, and upsert keys are unchanged.
This commit is contained in:
Marc-André Bombeck committed 2026-06-14 17:25:36 +02:00
commit cbde0d573f
16 files changed
+958 -125

No files matched your search

@@ -162,8 +162,11 @@ describe("POST /api/whoop/webhook/[token]", () => {
where: { whoopUserId: "42" },
select: { userId: true },
});
// v1.16.16 (iOS #17) — the resource id rides through so the worker can do
// a targeted fetch-by-id refresh instead of re-walking the collection.
expect(send).toHaveBeenCalledWith("whoop-recovery-sync", {
userId: "user-1",
resourceId: "abc",
});
});