mirror of
https://github.com/MBombeck/HealthLog.git
synced 2026-11-07 04:12:04 +00:00
test(kit): record route parity snapshots, starting with the batch ingest
tests/kit/parity.ts pins what a route answers, stores and reports for a fixed walk of cases, so the code behind it can move under a byte-for-byte comparison: the response, the rows read back, the request's wide event and the queue and arrival tails it asked for, with generated ids, server timestamps and request ids replaced by stable placeholders. The first walk covers POST /api/measurements/batch: a mixed first sync with every per-entry refusal, the same sync again, a background day total, the manual and HealthKit mirror merge, a backfill, both whole-batch refusals and a narrow bridge token. The clock is pinned, so the snapshot holds on any day.
This commit is contained in:
1 parent
08403a93b4
commit
3df80389ab
11 files changed
+4537
No files matched your search
+512
@@ -0,0 +1,512 @@
|
||||
{
|
||||
"status": 200,
|
||||
"body": {
|
||||
"data": {
|
||||
"processed": 21,
|
||||
"inserted": 14,
|
||||
"updated": 0,
|
||||
"duplicates": 2,
|
||||
"failed": 0,
|
||||
"skipped": [
|
||||
{
|
||||
"index": 12,
|
||||
"reason": "unmappable_identifier"
|
||||
},
|
||||
{
|
||||
"index": 13,
|
||||
"reason": "value_out_of_range"
|
||||
},
|
||||
{
|
||||
"index": 14,
|
||||
"reason": "implausible_timestamp"
|
||||
},
|
||||
{
|
||||
"index": 15,
|
||||
"reason": "malformed_hr_bucket_id"
|
||||
},
|
||||
{
|
||||
"index": 16,
|
||||
"reason": "unstable_external_id"
|
||||
}
|
||||
],
|
||||
"entries": [
|
||||
{
|
||||
"index": 0,
|
||||
"status": "inserted"
|
||||
},
|
||||
{
|
||||
"index": 1,
|
||||
"status": "inserted"
|
||||
},
|
||||
{
|
||||
"index": 2,
|
||||
"status": "inserted"
|
||||
},
|
||||
{
|
||||
"index": 3,
|
||||
"status": "inserted"
|
||||
},
|
||||
{
|
||||
"index": 4,
|
||||
"status": "inserted"
|
||||
},
|
||||
{
|
||||
"index": 5,
|
||||
"status": "inserted"
|
||||
},
|
||||
{
|
||||
"index": 6,
|
||||
"status": "inserted"
|
||||
},
|
||||
{
|
||||
"index": 7,
|
||||
"status": "inserted"
|
||||
},
|
||||
{
|
||||
"index": 8,
|
||||
"status": "inserted"
|
||||
},
|
||||
{
|
||||
"index": 9,
|
||||
"status": "inserted"
|
||||
},
|
||||
{
|
||||
"index": 10,
|
||||
"status": "inserted"
|
||||
},
|
||||
{
|
||||
"index": 11,
|
||||
"status": "inserted"
|
||||
},
|
||||
{
|
||||
"index": 12,
|
||||
"status": "skipped",
|
||||
"reason": "unmappable_identifier"
|
||||
},
|
||||
{
|
||||
"index": 13,
|
||||
"status": "skipped",
|
||||
"reason": "value_out_of_range",
|
||||
"convertedValue": 900,
|
||||
"range": {
|
||||
"min": 20,
|
||||
"max": 300,
|
||||
"unit": "bpm"
|
||||
}
|
||||
},
|
||||
{
|
||||
"index": 14,
|
||||
"status": "skipped",
|
||||
"reason": "implausible_timestamp"
|
||||
},
|
||||
{
|
||||
"index": 15,
|
||||
"status": "skipped",
|
||||
"reason": "malformed_hr_bucket_id"
|
||||
},
|
||||
{
|
||||
"index": 16,
|
||||
"status": "skipped",
|
||||
"reason": "unstable_external_id"
|
||||
},
|
||||
{
|
||||
"index": 17,
|
||||
"status": "inserted"
|
||||
},
|
||||
{
|
||||
"index": 18,
|
||||
"status": "duplicate"
|
||||
},
|
||||
{
|
||||
"index": 19,
|
||||
"status": "duplicate",
|
||||
"reason": "superseded_in_batch"
|
||||
},
|
||||
{
|
||||
"index": 20,
|
||||
"status": "inserted"
|
||||
}
|
||||
]
|
||||
},
|
||||
"error": null
|
||||
},
|
||||
"events": [
|
||||
{
|
||||
"status": 200,
|
||||
"action": {
|
||||
"name": "measurement.batch.ingest"
|
||||
},
|
||||
"meta": {
|
||||
"write_bucket": "own",
|
||||
"external_id_rejected": 1,
|
||||
"external_id_shapes": "object_description",
|
||||
"external_id_surface": "measurement.batch",
|
||||
"attempted": 3,
|
||||
"inserted": 12,
|
||||
"updated": 0,
|
||||
"processed": 21,
|
||||
"duplicate": 0,
|
||||
"skipped": 5,
|
||||
"failed": 0,
|
||||
"pr_detection_enqueued": true,
|
||||
"pr_detection_silent": false,
|
||||
"stats_unchanged": 0,
|
||||
"duplicates": 2,
|
||||
"skipped_by_reason": {
|
||||
"unmappable_identifier": 1,
|
||||
"value_out_of_range": 1,
|
||||
"implausible_timestamp": 1,
|
||||
"malformed_hr_bucket_id": 1,
|
||||
"unstable_external_id": 1
|
||||
},
|
||||
"syncTrigger": "foreground",
|
||||
"folded_window": 0,
|
||||
"set_inserted": 10
|
||||
},
|
||||
"warnings": null,
|
||||
"error": null
|
||||
}
|
||||
],
|
||||
"effects": [
|
||||
{
|
||||
"effect": "enqueueReminderSatisfy",
|
||||
"args": [
|
||||
"<id:1>"
|
||||
]
|
||||
},
|
||||
{
|
||||
"effect": "enqueuePrDetection",
|
||||
"args": [
|
||||
"<id:1>",
|
||||
{
|
||||
"silent": false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"effect": "maybeEnqueueMorningRefresh",
|
||||
"args": [
|
||||
"<id:1>",
|
||||
[
|
||||
"2026-10-14T01:00:00.000Z",
|
||||
"2026-10-14T02:30:00.000Z"
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"effect": "emitDataArrival",
|
||||
"args": [
|
||||
{
|
||||
"userId": "<id:1>",
|
||||
"kind": "weight",
|
||||
"newestSampleAt": "2026-10-14T06:30:00.000Z",
|
||||
"insertedCount": 1,
|
||||
"source": "batch"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"stored": {
|
||||
"measurements": [
|
||||
{
|
||||
"id": "<id:2>",
|
||||
"type": "WEIGHT",
|
||||
"value": 80.4,
|
||||
"valueMin": null,
|
||||
"valueMax": null,
|
||||
"unit": "kg",
|
||||
"source": "APPLE_HEALTH",
|
||||
"measuredAt": "2026-10-14T06:30:00.000Z",
|
||||
"externalId": "uuid-mass-1",
|
||||
"externalSourceVersion": null,
|
||||
"sleepStage": null,
|
||||
"rhythmClassification": null,
|
||||
"deviceType": "scale",
|
||||
"aggregationProvenance": null,
|
||||
"deletedAt": null
|
||||
},
|
||||
{
|
||||
"id": "<id:3>",
|
||||
"type": "PULSE",
|
||||
"value": 62,
|
||||
"valueMin": null,
|
||||
"valueMax": null,
|
||||
"unit": "bpm",
|
||||
"source": "APPLE_HEALTH",
|
||||
"measuredAt": "2026-10-14T07:00:00.000Z",
|
||||
"externalId": "uuid-hr-1",
|
||||
"externalSourceVersion": null,
|
||||
"sleepStage": null,
|
||||
"rhythmClassification": null,
|
||||
"deviceType": "watch",
|
||||
"aggregationProvenance": null,
|
||||
"deletedAt": null
|
||||
},
|
||||
{
|
||||
"id": "<id:4>",
|
||||
"type": "PULSE",
|
||||
"value": 64,
|
||||
"valueMin": null,
|
||||
"valueMax": null,
|
||||
"unit": "bpm",
|
||||
"source": "APPLE_HEALTH",
|
||||
"measuredAt": "2026-10-14T07:05:00.000Z",
|
||||
"externalId": "uuid-hr-2",
|
||||
"externalSourceVersion": null,
|
||||
"sleepStage": null,
|
||||
"rhythmClassification": null,
|
||||
"deviceType": null,
|
||||
"aggregationProvenance": null,
|
||||
"deletedAt": null
|
||||
},
|
||||
{
|
||||
"id": "<id:5>",
|
||||
"type": "PULSE",
|
||||
"value": 65,
|
||||
"valueMin": null,
|
||||
"valueMax": null,
|
||||
"unit": "bpm",
|
||||
"source": "APPLE_HEALTH",
|
||||
"measuredAt": "2026-10-14T07:25:00.000Z",
|
||||
"externalId": "uuid-hr-twice",
|
||||
"externalSourceVersion": null,
|
||||
"sleepStage": null,
|
||||
"rhythmClassification": null,
|
||||
"deviceType": null,
|
||||
"aggregationProvenance": null,
|
||||
"deletedAt": null
|
||||
},
|
||||
{
|
||||
"id": "<id:6>",
|
||||
"type": "PULSE",
|
||||
"value": 71,
|
||||
"valueMin": 66,
|
||||
"valueMax": 79,
|
||||
"unit": "bpm",
|
||||
"source": "APPLE_HEALTH",
|
||||
"measuredAt": "2026-10-14T08:10:00.000Z",
|
||||
"externalId": "stats:HKQuantityTypeIdentifierHeartRate:2026-10-14T08:10:00.000Z",
|
||||
"externalSourceVersion": null,
|
||||
"sleepStage": null,
|
||||
"rhythmClassification": null,
|
||||
"deviceType": null,
|
||||
"aggregationProvenance": "HEALTHKIT_STATISTICS",
|
||||
"deletedAt": null
|
||||
},
|
||||
{
|
||||
"id": "<id:7>",
|
||||
"type": "PULSE",
|
||||
"value": 70,
|
||||
"valueMin": null,
|
||||
"valueMax": null,
|
||||
"unit": "bpm",
|
||||
"source": "APPLE_HEALTH",
|
||||
"measuredAt": "2026-10-14T08:20:00.000Z",
|
||||
"externalId": "stats:HKQuantityTypeIdentifierHeartRate:2026-10-14T08:20:00.000Z",
|
||||
"externalSourceVersion": null,
|
||||
"sleepStage": null,
|
||||
"rhythmClassification": null,
|
||||
"deviceType": null,
|
||||
"aggregationProvenance": "HEALTHKIT_STATISTICS",
|
||||
"deletedAt": null
|
||||
},
|
||||
{
|
||||
"id": "<id:8>",
|
||||
"type": "SLEEP_DURATION",
|
||||
"value": 0,
|
||||
"valueMin": null,
|
||||
"valueMax": null,
|
||||
"unit": "minutes",
|
||||
"source": "APPLE_HEALTH",
|
||||
"measuredAt": "2026-10-14T01:00:00.000Z",
|
||||
"externalId": "uuid-sleep-1",
|
||||
"externalSourceVersion": null,
|
||||
"sleepStage": "CORE",
|
||||
"rhythmClassification": null,
|
||||
"deviceType": null,
|
||||
"aggregationProvenance": null,
|
||||
"deletedAt": null
|
||||
},
|
||||
{
|
||||
"id": "<id:9>",
|
||||
"type": "SLEEP_DURATION",
|
||||
"value": 0,
|
||||
"valueMin": null,
|
||||
"valueMax": null,
|
||||
"unit": "minutes",
|
||||
"source": "APPLE_HEALTH",
|
||||
"measuredAt": "2026-10-14T02:30:00.000Z",
|
||||
"externalId": "uuid-sleep-2",
|
||||
"externalSourceVersion": null,
|
||||
"sleepStage": "DEEP",
|
||||
"rhythmClassification": null,
|
||||
"deviceType": null,
|
||||
"aggregationProvenance": null,
|
||||
"deletedAt": null
|
||||
},
|
||||
{
|
||||
"id": "<id:10>",
|
||||
"type": "ACTIVITY_STEPS",
|
||||
"value": 7250,
|
||||
"valueMin": null,
|
||||
"valueMax": null,
|
||||
"unit": "steps",
|
||||
"source": "APPLE_HEALTH",
|
||||
"measuredAt": "2026-10-12T18:00:00.000Z",
|
||||
"externalId": "stats:HKQuantityTypeIdentifierStepCount:2026-10-12",
|
||||
"externalSourceVersion": null,
|
||||
"sleepStage": null,
|
||||
"rhythmClassification": null,
|
||||
"deviceType": null,
|
||||
"aggregationProvenance": "HEALTHKIT_STATISTICS",
|
||||
"deletedAt": null
|
||||
},
|
||||
{
|
||||
"id": "<id:11>",
|
||||
"type": "ACTIVITY_STEPS",
|
||||
"value": 8400,
|
||||
"valueMin": null,
|
||||
"valueMax": null,
|
||||
"unit": "steps",
|
||||
"source": "APPLE_HEALTH",
|
||||
"measuredAt": "2026-10-13T18:00:00.000Z",
|
||||
"externalId": "stats:HKQuantityTypeIdentifierStepCount:2026-10-13",
|
||||
"externalSourceVersion": null,
|
||||
"sleepStage": null,
|
||||
"rhythmClassification": null,
|
||||
"deviceType": "phone",
|
||||
"aggregationProvenance": "HEALTHKIT_STATISTICS",
|
||||
"deletedAt": null
|
||||
},
|
||||
{
|
||||
"id": "<id:12>",
|
||||
"type": "ACTIVITY_STEPS",
|
||||
"value": 5100,
|
||||
"valueMin": null,
|
||||
"valueMax": null,
|
||||
"unit": "steps",
|
||||
"source": "APPLE_HEALTH",
|
||||
"measuredAt": "2026-10-14T18:00:00.000Z",
|
||||
"externalId": "stats:HKQuantityTypeIdentifierStepCount:2026-10-14",
|
||||
"externalSourceVersion": null,
|
||||
"sleepStage": null,
|
||||
"rhythmClassification": null,
|
||||
"deviceType": null,
|
||||
"aggregationProvenance": "HEALTHKIT_STATISTICS",
|
||||
"deletedAt": null
|
||||
},
|
||||
{
|
||||
"id": "<id:13>",
|
||||
"type": "OXYGEN_SATURATION",
|
||||
"value": 97,
|
||||
"valueMin": null,
|
||||
"valueMax": null,
|
||||
"unit": "%",
|
||||
"source": "APPLE_HEALTH",
|
||||
"measuredAt": "2026-10-14T07:10:00.000Z",
|
||||
"externalId": "uuid-spo2-1",
|
||||
"externalSourceVersion": null,
|
||||
"sleepStage": null,
|
||||
"rhythmClassification": null,
|
||||
"deviceType": null,
|
||||
"aggregationProvenance": null,
|
||||
"deletedAt": null
|
||||
}
|
||||
],
|
||||
"hours": [
|
||||
{
|
||||
"id": "<id:14>",
|
||||
"userId": "<id:1>",
|
||||
"type": "ACTIVITY_STEPS",
|
||||
"dateKey": "2026-10-14",
|
||||
"hourlyCumulative": [],
|
||||
"dayTotal": 0,
|
||||
"sampleCount": 0,
|
||||
"hourlyIncrements": [
|
||||
-1,
|
||||
-1,
|
||||
-1,
|
||||
-1,
|
||||
-1,
|
||||
-1,
|
||||
-1,
|
||||
-1,
|
||||
900,
|
||||
1300,
|
||||
-1,
|
||||
-1,
|
||||
-1,
|
||||
-1,
|
||||
-1,
|
||||
-1,
|
||||
-1,
|
||||
-1,
|
||||
-1,
|
||||
-1,
|
||||
-1,
|
||||
-1,
|
||||
-1,
|
||||
-1
|
||||
],
|
||||
"basis": "PER_SAMPLE",
|
||||
"bucketCount": 2,
|
||||
"timezone": "UTC",
|
||||
"createdAt": "<createdAt>",
|
||||
"updatedAt": "<updatedAt>"
|
||||
}
|
||||
],
|
||||
"user": {
|
||||
"lastSyncedAt": "<now>",
|
||||
"healthKitLastSyncedAt": "<now>",
|
||||
"healthKitLastSyncTrigger": "foreground",
|
||||
"healthKitLastBackgroundSyncAt": null
|
||||
},
|
||||
"typeSync": [
|
||||
{
|
||||
"userId": "<id:1>",
|
||||
"type": "ACTIVITY_STEPS",
|
||||
"lastReceivedAt": "<now>",
|
||||
"lastTrigger": "foreground",
|
||||
"lastNewSampleAt": "<now>",
|
||||
"lastBackgroundAt": null,
|
||||
"lastSeenDuplicateAt": null
|
||||
},
|
||||
{
|
||||
"userId": "<id:1>",
|
||||
"type": "OXYGEN_SATURATION",
|
||||
"lastReceivedAt": "<now>",
|
||||
"lastTrigger": "foreground",
|
||||
"lastNewSampleAt": "<now>",
|
||||
"lastBackgroundAt": null,
|
||||
"lastSeenDuplicateAt": null
|
||||
},
|
||||
{
|
||||
"userId": "<id:1>",
|
||||
"type": "PULSE",
|
||||
"lastReceivedAt": "<now>",
|
||||
"lastTrigger": "foreground",
|
||||
"lastNewSampleAt": "<now>",
|
||||
"lastBackgroundAt": null,
|
||||
"lastSeenDuplicateAt": null
|
||||
},
|
||||
{
|
||||
"userId": "<id:1>",
|
||||
"type": "SLEEP_DURATION",
|
||||
"lastReceivedAt": "<now>",
|
||||
"lastTrigger": "foreground",
|
||||
"lastNewSampleAt": "<now>",
|
||||
"lastBackgroundAt": null,
|
||||
"lastSeenDuplicateAt": null
|
||||
},
|
||||
{
|
||||
"userId": "<id:1>",
|
||||
"type": "WEIGHT",
|
||||
"lastReceivedAt": "<now>",
|
||||
"lastTrigger": "foreground",
|
||||
"lastNewSampleAt": "<now>",
|
||||
"lastBackgroundAt": null,
|
||||
"lastSeenDuplicateAt": null
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
+497
@@ -0,0 +1,497 @@
|
||||
{
|
||||
"status": 200,
|
||||
"body": {
|
||||
"data": {
|
||||
"processed": 21,
|
||||
"inserted": 0,
|
||||
"updated": 7,
|
||||
"duplicates": 9,
|
||||
"failed": 0,
|
||||
"skipped": [
|
||||
{
|
||||
"index": 12,
|
||||
"reason": "unmappable_identifier"
|
||||
},
|
||||
{
|
||||
"index": 13,
|
||||
"reason": "value_out_of_range"
|
||||
},
|
||||
{
|
||||
"index": 14,
|
||||
"reason": "implausible_timestamp"
|
||||
},
|
||||
{
|
||||
"index": 15,
|
||||
"reason": "malformed_hr_bucket_id"
|
||||
},
|
||||
{
|
||||
"index": 16,
|
||||
"reason": "unstable_external_id"
|
||||
}
|
||||
],
|
||||
"entries": [
|
||||
{
|
||||
"index": 0,
|
||||
"status": "duplicate"
|
||||
},
|
||||
{
|
||||
"index": 1,
|
||||
"status": "duplicate"
|
||||
},
|
||||
{
|
||||
"index": 2,
|
||||
"status": "duplicate"
|
||||
},
|
||||
{
|
||||
"index": 3,
|
||||
"status": "duplicate"
|
||||
},
|
||||
{
|
||||
"index": 4,
|
||||
"status": "updated"
|
||||
},
|
||||
{
|
||||
"index": 5,
|
||||
"status": "updated"
|
||||
},
|
||||
{
|
||||
"index": 6,
|
||||
"status": "updated"
|
||||
},
|
||||
{
|
||||
"index": 7,
|
||||
"status": "updated"
|
||||
},
|
||||
{
|
||||
"index": 8,
|
||||
"status": "duplicate"
|
||||
},
|
||||
{
|
||||
"index": 9,
|
||||
"status": "duplicate"
|
||||
},
|
||||
{
|
||||
"index": 10,
|
||||
"status": "updated"
|
||||
},
|
||||
{
|
||||
"index": 11,
|
||||
"status": "updated"
|
||||
},
|
||||
{
|
||||
"index": 12,
|
||||
"status": "skipped",
|
||||
"reason": "unmappable_identifier"
|
||||
},
|
||||
{
|
||||
"index": 13,
|
||||
"status": "skipped",
|
||||
"reason": "value_out_of_range",
|
||||
"convertedValue": 900,
|
||||
"range": {
|
||||
"min": 20,
|
||||
"max": 300,
|
||||
"unit": "bpm"
|
||||
}
|
||||
},
|
||||
{
|
||||
"index": 14,
|
||||
"status": "skipped",
|
||||
"reason": "implausible_timestamp"
|
||||
},
|
||||
{
|
||||
"index": 15,
|
||||
"status": "skipped",
|
||||
"reason": "malformed_hr_bucket_id"
|
||||
},
|
||||
{
|
||||
"index": 16,
|
||||
"status": "skipped",
|
||||
"reason": "unstable_external_id"
|
||||
},
|
||||
{
|
||||
"index": 17,
|
||||
"status": "duplicate"
|
||||
},
|
||||
{
|
||||
"index": 18,
|
||||
"status": "duplicate"
|
||||
},
|
||||
{
|
||||
"index": 19,
|
||||
"status": "duplicate",
|
||||
"reason": "superseded_in_batch"
|
||||
},
|
||||
{
|
||||
"index": 20,
|
||||
"status": "updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
"error": null
|
||||
},
|
||||
"events": [
|
||||
{
|
||||
"status": 200,
|
||||
"action": {
|
||||
"name": "measurement.batch.ingest"
|
||||
},
|
||||
"meta": {
|
||||
"write_bucket": "own",
|
||||
"external_id_rejected": 1,
|
||||
"external_id_shapes": "object_description",
|
||||
"external_id_surface": "measurement.batch",
|
||||
"attempted": 3,
|
||||
"inserted": 0,
|
||||
"updated": 5,
|
||||
"processed": 21,
|
||||
"duplicate": 0,
|
||||
"skipped": 5,
|
||||
"failed": 0,
|
||||
"pr_detection_enqueued": true,
|
||||
"pr_detection_silent": false,
|
||||
"stats_unchanged": 4,
|
||||
"duplicates": 9,
|
||||
"skipped_by_reason": {
|
||||
"unmappable_identifier": 1,
|
||||
"value_out_of_range": 1,
|
||||
"implausible_timestamp": 1,
|
||||
"malformed_hr_bucket_id": 1,
|
||||
"unstable_external_id": 1
|
||||
},
|
||||
"syncTrigger": "foreground",
|
||||
"folded_window": 0,
|
||||
"set_inserted": 0
|
||||
},
|
||||
"warnings": null,
|
||||
"error": null
|
||||
}
|
||||
],
|
||||
"effects": [
|
||||
{
|
||||
"effect": "enqueueReminderSatisfy",
|
||||
"args": [
|
||||
"<id:1>"
|
||||
]
|
||||
},
|
||||
{
|
||||
"effect": "enqueuePrDetection",
|
||||
"args": [
|
||||
"<id:1>",
|
||||
{
|
||||
"silent": false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"effect": "maybeEnqueueMorningRefresh",
|
||||
"args": [
|
||||
"<id:1>",
|
||||
[]
|
||||
]
|
||||
}
|
||||
],
|
||||
"stored": {
|
||||
"measurements": [
|
||||
{
|
||||
"id": "<id:2>",
|
||||
"type": "WEIGHT",
|
||||
"value": 80.4,
|
||||
"valueMin": null,
|
||||
"valueMax": null,
|
||||
"unit": "kg",
|
||||
"source": "APPLE_HEALTH",
|
||||
"measuredAt": "2026-10-14T06:30:00.000Z",
|
||||
"externalId": "uuid-mass-1",
|
||||
"externalSourceVersion": null,
|
||||
"sleepStage": null,
|
||||
"rhythmClassification": null,
|
||||
"deviceType": "scale",
|
||||
"aggregationProvenance": null,
|
||||
"deletedAt": null
|
||||
},
|
||||
{
|
||||
"id": "<id:3>",
|
||||
"type": "PULSE",
|
||||
"value": 62,
|
||||
"valueMin": null,
|
||||
"valueMax": null,
|
||||
"unit": "bpm",
|
||||
"source": "APPLE_HEALTH",
|
||||
"measuredAt": "2026-10-14T07:00:00.000Z",
|
||||
"externalId": "uuid-hr-1",
|
||||
"externalSourceVersion": null,
|
||||
"sleepStage": null,
|
||||
"rhythmClassification": null,
|
||||
"deviceType": "watch",
|
||||
"aggregationProvenance": null,
|
||||
"deletedAt": null
|
||||
},
|
||||
{
|
||||
"id": "<id:4>",
|
||||
"type": "PULSE",
|
||||
"value": 64,
|
||||
"valueMin": null,
|
||||
"valueMax": null,
|
||||
"unit": "bpm",
|
||||
"source": "APPLE_HEALTH",
|
||||
"measuredAt": "2026-10-14T07:05:00.000Z",
|
||||
"externalId": "uuid-hr-2",
|
||||
"externalSourceVersion": null,
|
||||
"sleepStage": null,
|
||||
"rhythmClassification": null,
|
||||
"deviceType": null,
|
||||
"aggregationProvenance": null,
|
||||
"deletedAt": null
|
||||
},
|
||||
{
|
||||
"id": "<id:5>",
|
||||
"type": "PULSE",
|
||||
"value": 65,
|
||||
"valueMin": null,
|
||||
"valueMax": null,
|
||||
"unit": "bpm",
|
||||
"source": "APPLE_HEALTH",
|
||||
"measuredAt": "2026-10-14T07:25:00.000Z",
|
||||
"externalId": "uuid-hr-twice",
|
||||
"externalSourceVersion": null,
|
||||
"sleepStage": null,
|
||||
"rhythmClassification": null,
|
||||
"deviceType": null,
|
||||
"aggregationProvenance": null,
|
||||
"deletedAt": null
|
||||
},
|
||||
{
|
||||
"id": "<id:6>",
|
||||
"type": "PULSE",
|
||||
"value": 71,
|
||||
"valueMin": 66,
|
||||
"valueMax": 79,
|
||||
"unit": "bpm",
|
||||
"source": "APPLE_HEALTH",
|
||||
"measuredAt": "2026-10-14T08:10:00.000Z",
|
||||
"externalId": "stats:HKQuantityTypeIdentifierHeartRate:2026-10-14T08:10:00.000Z",
|
||||
"externalSourceVersion": null,
|
||||
"sleepStage": null,
|
||||
"rhythmClassification": null,
|
||||
"deviceType": null,
|
||||
"aggregationProvenance": "HEALTHKIT_STATISTICS",
|
||||
"deletedAt": null
|
||||
},
|
||||
{
|
||||
"id": "<id:7>",
|
||||
"type": "PULSE",
|
||||
"value": 70,
|
||||
"valueMin": null,
|
||||
"valueMax": null,
|
||||
"unit": "bpm",
|
||||
"source": "APPLE_HEALTH",
|
||||
"measuredAt": "2026-10-14T08:20:00.000Z",
|
||||
"externalId": "stats:HKQuantityTypeIdentifierHeartRate:2026-10-14T08:20:00.000Z",
|
||||
"externalSourceVersion": null,
|
||||
"sleepStage": null,
|
||||
"rhythmClassification": null,
|
||||
"deviceType": null,
|
||||
"aggregationProvenance": "HEALTHKIT_STATISTICS",
|
||||
"deletedAt": null
|
||||
},
|
||||
{
|
||||
"id": "<id:8>",
|
||||
"type": "SLEEP_DURATION",
|
||||
"value": 0,
|
||||
"valueMin": null,
|
||||
"valueMax": null,
|
||||
"unit": "minutes",
|
||||
"source": "APPLE_HEALTH",
|
||||
"measuredAt": "2026-10-14T01:00:00.000Z",
|
||||
"externalId": "uuid-sleep-1",
|
||||
"externalSourceVersion": null,
|
||||
"sleepStage": "CORE",
|
||||
"rhythmClassification": null,
|
||||
"deviceType": null,
|
||||
"aggregationProvenance": null,
|
||||
"deletedAt": null
|
||||
},
|
||||
{
|
||||
"id": "<id:9>",
|
||||
"type": "SLEEP_DURATION",
|
||||
"value": 0,
|
||||
"valueMin": null,
|
||||
"valueMax": null,
|
||||
"unit": "minutes",
|
||||
"source": "APPLE_HEALTH",
|
||||
"measuredAt": "2026-10-14T02:30:00.000Z",
|
||||
"externalId": "uuid-sleep-2",
|
||||
"externalSourceVersion": null,
|
||||
"sleepStage": "DEEP",
|
||||
"rhythmClassification": null,
|
||||
"deviceType": null,
|
||||
"aggregationProvenance": null,
|
||||
"deletedAt": null
|
||||
},
|
||||
{
|
||||
"id": "<id:10>",
|
||||
"type": "ACTIVITY_STEPS",
|
||||
"value": 7250,
|
||||
"valueMin": null,
|
||||
"valueMax": null,
|
||||
"unit": "steps",
|
||||
"source": "APPLE_HEALTH",
|
||||
"measuredAt": "2026-10-12T18:00:00.000Z",
|
||||
"externalId": "stats:HKQuantityTypeIdentifierStepCount:2026-10-12",
|
||||
"externalSourceVersion": null,
|
||||
"sleepStage": null,
|
||||
"rhythmClassification": null,
|
||||
"deviceType": null,
|
||||
"aggregationProvenance": "HEALTHKIT_STATISTICS",
|
||||
"deletedAt": null
|
||||
},
|
||||
{
|
||||
"id": "<id:11>",
|
||||
"type": "ACTIVITY_STEPS",
|
||||
"value": 8400,
|
||||
"valueMin": null,
|
||||
"valueMax": null,
|
||||
"unit": "steps",
|
||||
"source": "APPLE_HEALTH",
|
||||
"measuredAt": "2026-10-13T18:00:00.000Z",
|
||||
"externalId": "stats:HKQuantityTypeIdentifierStepCount:2026-10-13",
|
||||
"externalSourceVersion": null,
|
||||
"sleepStage": null,
|
||||
"rhythmClassification": null,
|
||||
"deviceType": "phone",
|
||||
"aggregationProvenance": "HEALTHKIT_STATISTICS",
|
||||
"deletedAt": null
|
||||
},
|
||||
{
|
||||
"id": "<id:12>",
|
||||
"type": "ACTIVITY_STEPS",
|
||||
"value": 5100,
|
||||
"valueMin": null,
|
||||
"valueMax": null,
|
||||
"unit": "steps",
|
||||
"source": "APPLE_HEALTH",
|
||||
"measuredAt": "2026-10-14T18:00:00.000Z",
|
||||
"externalId": "stats:HKQuantityTypeIdentifierStepCount:2026-10-14",
|
||||
"externalSourceVersion": null,
|
||||
"sleepStage": null,
|
||||
"rhythmClassification": null,
|
||||
"deviceType": null,
|
||||
"aggregationProvenance": "HEALTHKIT_STATISTICS",
|
||||
"deletedAt": null
|
||||
},
|
||||
{
|
||||
"id": "<id:13>",
|
||||
"type": "OXYGEN_SATURATION",
|
||||
"value": 97,
|
||||
"valueMin": null,
|
||||
"valueMax": null,
|
||||
"unit": "%",
|
||||
"source": "APPLE_HEALTH",
|
||||
"measuredAt": "2026-10-14T07:10:00.000Z",
|
||||
"externalId": "uuid-spo2-1",
|
||||
"externalSourceVersion": null,
|
||||
"sleepStage": null,
|
||||
"rhythmClassification": null,
|
||||
"deviceType": null,
|
||||
"aggregationProvenance": null,
|
||||
"deletedAt": null
|
||||
}
|
||||
],
|
||||
"hours": [
|
||||
{
|
||||
"id": "<id:14>",
|
||||
"userId": "<id:1>",
|
||||
"type": "ACTIVITY_STEPS",
|
||||
"dateKey": "2026-10-14",
|
||||
"hourlyCumulative": [],
|
||||
"dayTotal": 0,
|
||||
"sampleCount": 0,
|
||||
"hourlyIncrements": [
|
||||
-1,
|
||||
-1,
|
||||
-1,
|
||||
-1,
|
||||
-1,
|
||||
-1,
|
||||
-1,
|
||||
-1,
|
||||
900,
|
||||
1300,
|
||||
-1,
|
||||
-1,
|
||||
-1,
|
||||
-1,
|
||||
-1,
|
||||
-1,
|
||||
-1,
|
||||
-1,
|
||||
-1,
|
||||
-1,
|
||||
-1,
|
||||
-1,
|
||||
-1,
|
||||
-1
|
||||
],
|
||||
"basis": "PER_SAMPLE",
|
||||
"bucketCount": 2,
|
||||
"timezone": "UTC",
|
||||
"createdAt": "<createdAt>",
|
||||
"updatedAt": "<updatedAt>"
|
||||
}
|
||||
],
|
||||
"user": {
|
||||
"lastSyncedAt": "<now>",
|
||||
"healthKitLastSyncedAt": "<now>",
|
||||
"healthKitLastSyncTrigger": "foreground",
|
||||
"healthKitLastBackgroundSyncAt": null
|
||||
},
|
||||
"typeSync": [
|
||||
{
|
||||
"userId": "<id:1>",
|
||||
"type": "ACTIVITY_STEPS",
|
||||
"lastReceivedAt": "<now>",
|
||||
"lastTrigger": "foreground",
|
||||
"lastNewSampleAt": "<now>",
|
||||
"lastBackgroundAt": null,
|
||||
"lastSeenDuplicateAt": null
|
||||
},
|
||||
{
|
||||
"userId": "<id:1>",
|
||||
"type": "OXYGEN_SATURATION",
|
||||
"lastReceivedAt": "<now>",
|
||||
"lastTrigger": "foreground",
|
||||
"lastNewSampleAt": "<now>",
|
||||
"lastBackgroundAt": null,
|
||||
"lastSeenDuplicateAt": "<now>"
|
||||
},
|
||||
{
|
||||
"userId": "<id:1>",
|
||||
"type": "PULSE",
|
||||
"lastReceivedAt": "<now>",
|
||||
"lastTrigger": "foreground",
|
||||
"lastNewSampleAt": "<now>",
|
||||
"lastBackgroundAt": null,
|
||||
"lastSeenDuplicateAt": "<now>"
|
||||
},
|
||||
{
|
||||
"userId": "<id:1>",
|
||||
"type": "SLEEP_DURATION",
|
||||
"lastReceivedAt": "<now>",
|
||||
"lastTrigger": "foreground",
|
||||
"lastNewSampleAt": "<now>",
|
||||
"lastBackgroundAt": null,
|
||||
"lastSeenDuplicateAt": "<now>"
|
||||
},
|
||||
{
|
||||
"userId": "<id:1>",
|
||||
"type": "WEIGHT",
|
||||
"lastReceivedAt": "<now>",
|
||||
"lastTrigger": "foreground",
|
||||
"lastNewSampleAt": "<now>",
|
||||
"lastBackgroundAt": null,
|
||||
"lastSeenDuplicateAt": "<now>"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
+382
@@ -0,0 +1,382 @@
|
||||
{
|
||||
"status": 200,
|
||||
"body": {
|
||||
"data": {
|
||||
"processed": 3,
|
||||
"inserted": 0,
|
||||
"updated": 3,
|
||||
"duplicates": 0,
|
||||
"failed": 0,
|
||||
"skipped": [],
|
||||
"entries": [
|
||||
{
|
||||
"index": 0,
|
||||
"status": "updated"
|
||||
},
|
||||
{
|
||||
"index": 1,
|
||||
"status": "updated"
|
||||
},
|
||||
{
|
||||
"index": 2,
|
||||
"status": "updated"
|
||||
}
|
||||
]
|
||||
},
|
||||
"error": null
|
||||
},
|
||||
"events": [
|
||||
{
|
||||
"status": 200,
|
||||
"action": {
|
||||
"name": "measurement.batch.ingest"
|
||||
},
|
||||
"meta": {
|
||||
"write_bucket": "own",
|
||||
"attempted": 1,
|
||||
"inserted": 0,
|
||||
"updated": 2,
|
||||
"processed": 3,
|
||||
"pr_detection_enqueued": true,
|
||||
"pr_detection_silent": false,
|
||||
"stats_unchanged": 1,
|
||||
"duplicates": 0,
|
||||
"skipped": 0,
|
||||
"skipped_by_reason": {},
|
||||
"failed": 0,
|
||||
"syncTrigger": "background",
|
||||
"folded_window": 0,
|
||||
"set_inserted": 0
|
||||
},
|
||||
"warnings": null,
|
||||
"error": null
|
||||
}
|
||||
],
|
||||
"effects": [
|
||||
{
|
||||
"effect": "enqueueReminderSatisfy",
|
||||
"args": [
|
||||
"<id:1>"
|
||||
]
|
||||
},
|
||||
{
|
||||
"effect": "enqueuePrDetection",
|
||||
"args": [
|
||||
"<id:1>",
|
||||
{
|
||||
"silent": false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"effect": "maybeEnqueueMorningRefresh",
|
||||
"args": [
|
||||
"<id:1>",
|
||||
[]
|
||||
]
|
||||
}
|
||||
],
|
||||
"stored": {
|
||||
"measurements": [
|
||||
{
|
||||
"id": "<id:2>",
|
||||
"type": "WEIGHT",
|
||||
"value": 80.4,
|
||||
"valueMin": null,
|
||||
"valueMax": null,
|
||||
"unit": "kg",
|
||||
"source": "APPLE_HEALTH",
|
||||
"measuredAt": "2026-10-14T06:30:00.000Z",
|
||||
"externalId": "uuid-mass-1",
|
||||
"externalSourceVersion": null,
|
||||
"sleepStage": null,
|
||||
"rhythmClassification": null,
|
||||
"deviceType": "scale",
|
||||
"aggregationProvenance": null,
|
||||
"deletedAt": null
|
||||
},
|
||||
{
|
||||
"id": "<id:3>",
|
||||
"type": "PULSE",
|
||||
"value": 62,
|
||||
"valueMin": null,
|
||||
"valueMax": null,
|
||||
"unit": "bpm",
|
||||
"source": "APPLE_HEALTH",
|
||||
"measuredAt": "2026-10-14T07:00:00.000Z",
|
||||
"externalId": "uuid-hr-1",
|
||||
"externalSourceVersion": null,
|
||||
"sleepStage": null,
|
||||
"rhythmClassification": null,
|
||||
"deviceType": "watch",
|
||||
"aggregationProvenance": null,
|
||||
"deletedAt": null
|
||||
},
|
||||
{
|
||||
"id": "<id:4>",
|
||||
"type": "PULSE",
|
||||
"value": 64,
|
||||
"valueMin": null,
|
||||
"valueMax": null,
|
||||
"unit": "bpm",
|
||||
"source": "APPLE_HEALTH",
|
||||
"measuredAt": "2026-10-14T07:05:00.000Z",
|
||||
"externalId": "uuid-hr-2",
|
||||
"externalSourceVersion": null,
|
||||
"sleepStage": null,
|
||||
"rhythmClassification": null,
|
||||
"deviceType": null,
|
||||
"aggregationProvenance": null,
|
||||
"deletedAt": null
|
||||
},
|
||||
{
|
||||
"id": "<id:5>",
|
||||
"type": "PULSE",
|
||||
"value": 65,
|
||||
"valueMin": null,
|
||||
"valueMax": null,
|
||||
"unit": "bpm",
|
||||
"source": "APPLE_HEALTH",
|
||||
"measuredAt": "2026-10-14T07:25:00.000Z",
|
||||
"externalId": "uuid-hr-twice",
|
||||
"externalSourceVersion": null,
|
||||
"sleepStage": null,
|
||||
"rhythmClassification": null,
|
||||
"deviceType": null,
|
||||
"aggregationProvenance": null,
|
||||
"deletedAt": null
|
||||
},
|
||||
{
|
||||
"id": "<id:6>",
|
||||
"type": "PULSE",
|
||||
"value": 71,
|
||||
"valueMin": 66,
|
||||
"valueMax": 79,
|
||||
"unit": "bpm",
|
||||
"source": "APPLE_HEALTH",
|
||||
"measuredAt": "2026-10-14T08:10:00.000Z",
|
||||
"externalId": "stats:HKQuantityTypeIdentifierHeartRate:2026-10-14T08:10:00.000Z",
|
||||
"externalSourceVersion": null,
|
||||
"sleepStage": null,
|
||||
"rhythmClassification": null,
|
||||
"deviceType": null,
|
||||
"aggregationProvenance": "HEALTHKIT_STATISTICS",
|
||||
"deletedAt": null
|
||||
},
|
||||
{
|
||||
"id": "<id:7>",
|
||||
"type": "PULSE",
|
||||
"value": 70,
|
||||
"valueMin": null,
|
||||
"valueMax": null,
|
||||
"unit": "bpm",
|
||||
"source": "APPLE_HEALTH",
|
||||
"measuredAt": "2026-10-14T08:20:00.000Z",
|
||||
"externalId": "stats:HKQuantityTypeIdentifierHeartRate:2026-10-14T08:20:00.000Z",
|
||||
"externalSourceVersion": null,
|
||||
"sleepStage": null,
|
||||
"rhythmClassification": null,
|
||||
"deviceType": null,
|
||||
"aggregationProvenance": "HEALTHKIT_STATISTICS",
|
||||
"deletedAt": null
|
||||
},
|
||||
{
|
||||
"id": "<id:8>",
|
||||
"type": "SLEEP_DURATION",
|
||||
"value": 0,
|
||||
"valueMin": null,
|
||||
"valueMax": null,
|
||||
"unit": "minutes",
|
||||
"source": "APPLE_HEALTH",
|
||||
"measuredAt": "2026-10-14T01:00:00.000Z",
|
||||
"externalId": "uuid-sleep-1",
|
||||
"externalSourceVersion": null,
|
||||
"sleepStage": "CORE",
|
||||
"rhythmClassification": null,
|
||||
"deviceType": null,
|
||||
"aggregationProvenance": null,
|
||||
"deletedAt": null
|
||||
},
|
||||
{
|
||||
"id": "<id:9>",
|
||||
"type": "SLEEP_DURATION",
|
||||
"value": 0,
|
||||
"valueMin": null,
|
||||
"valueMax": null,
|
||||
"unit": "minutes",
|
||||
"source": "APPLE_HEALTH",
|
||||
"measuredAt": "2026-10-14T02:30:00.000Z",
|
||||
"externalId": "uuid-sleep-2",
|
||||
"externalSourceVersion": null,
|
||||
"sleepStage": "DEEP",
|
||||
"rhythmClassification": null,
|
||||
"deviceType": null,
|
||||
"aggregationProvenance": null,
|
||||
"deletedAt": null
|
||||
},
|
||||
{
|
||||
"id": "<id:10>",
|
||||
"type": "ACTIVITY_STEPS",
|
||||
"value": 7250,
|
||||
"valueMin": null,
|
||||
"valueMax": null,
|
||||
"unit": "steps",
|
||||
"source": "APPLE_HEALTH",
|
||||
"measuredAt": "2026-10-12T18:00:00.000Z",
|
||||
"externalId": "stats:HKQuantityTypeIdentifierStepCount:2026-10-12",
|
||||
"externalSourceVersion": null,
|
||||
"sleepStage": null,
|
||||
"rhythmClassification": null,
|
||||
"deviceType": null,
|
||||
"aggregationProvenance": "HEALTHKIT_STATISTICS",
|
||||
"deletedAt": null
|
||||
},
|
||||
{
|
||||
"id": "<id:11>",
|
||||
"type": "ACTIVITY_STEPS",
|
||||
"value": 8400,
|
||||
"valueMin": null,
|
||||
"valueMax": null,
|
||||
"unit": "steps",
|
||||
"source": "APPLE_HEALTH",
|
||||
"measuredAt": "2026-10-13T18:00:00.000Z",
|
||||
"externalId": "stats:HKQuantityTypeIdentifierStepCount:2026-10-13",
|
||||
"externalSourceVersion": null,
|
||||
"sleepStage": null,
|
||||
"rhythmClassification": null,
|
||||
"deviceType": "phone",
|
||||
"aggregationProvenance": "HEALTHKIT_STATISTICS",
|
||||
"deletedAt": null
|
||||
},
|
||||
{
|
||||
"id": "<id:12>",
|
||||
"type": "ACTIVITY_STEPS",
|
||||
"value": 6300,
|
||||
"valueMin": null,
|
||||
"valueMax": null,
|
||||
"unit": "steps",
|
||||
"source": "APPLE_HEALTH",
|
||||
"measuredAt": "2026-10-14T18:00:00.000Z",
|
||||
"externalId": "stats:HKQuantityTypeIdentifierStepCount:2026-10-14",
|
||||
"externalSourceVersion": null,
|
||||
"sleepStage": null,
|
||||
"rhythmClassification": null,
|
||||
"deviceType": null,
|
||||
"aggregationProvenance": "HEALTHKIT_STATISTICS",
|
||||
"deletedAt": null
|
||||
},
|
||||
{
|
||||
"id": "<id:13>",
|
||||
"type": "OXYGEN_SATURATION",
|
||||
"value": 97,
|
||||
"valueMin": null,
|
||||
"valueMax": null,
|
||||
"unit": "%",
|
||||
"source": "APPLE_HEALTH",
|
||||
"measuredAt": "2026-10-14T07:10:00.000Z",
|
||||
"externalId": "uuid-spo2-1",
|
||||
"externalSourceVersion": null,
|
||||
"sleepStage": null,
|
||||
"rhythmClassification": null,
|
||||
"deviceType": null,
|
||||
"aggregationProvenance": null,
|
||||
"deletedAt": null
|
||||
}
|
||||
],
|
||||
"hours": [
|
||||
{
|
||||
"id": "<id:14>",
|
||||
"userId": "<id:1>",
|
||||
"type": "ACTIVITY_STEPS",
|
||||
"dateKey": "2026-10-14",
|
||||
"hourlyCumulative": [],
|
||||
"dayTotal": 0,
|
||||
"sampleCount": 0,
|
||||
"hourlyIncrements": [
|
||||
-1,
|
||||
-1,
|
||||
-1,
|
||||
-1,
|
||||
-1,
|
||||
-1,
|
||||
-1,
|
||||
-1,
|
||||
900,
|
||||
1450,
|
||||
-1,
|
||||
-1,
|
||||
-1,
|
||||
-1,
|
||||
-1,
|
||||
-1,
|
||||
-1,
|
||||
-1,
|
||||
-1,
|
||||
-1,
|
||||
-1,
|
||||
-1,
|
||||
-1,
|
||||
-1
|
||||
],
|
||||
"basis": "PER_SAMPLE",
|
||||
"bucketCount": 2,
|
||||
"timezone": "UTC",
|
||||
"createdAt": "<createdAt>",
|
||||
"updatedAt": "<updatedAt>"
|
||||
}
|
||||
],
|
||||
"user": {
|
||||
"lastSyncedAt": "<now>",
|
||||
"healthKitLastSyncedAt": "<now>",
|
||||
"healthKitLastSyncTrigger": "background",
|
||||
"healthKitLastBackgroundSyncAt": "<now>"
|
||||
},
|
||||
"typeSync": [
|
||||
{
|
||||
"userId": "<id:1>",
|
||||
"type": "ACTIVITY_STEPS",
|
||||
"lastReceivedAt": "<now>",
|
||||
"lastTrigger": "background",
|
||||
"lastNewSampleAt": "<now>",
|
||||
"lastBackgroundAt": "<now>",
|
||||
"lastSeenDuplicateAt": null
|
||||
},
|
||||
{
|
||||
"userId": "<id:1>",
|
||||
"type": "OXYGEN_SATURATION",
|
||||
"lastReceivedAt": "<now>",
|
||||
"lastTrigger": "foreground",
|
||||
"lastNewSampleAt": "<now>",
|
||||
"lastBackgroundAt": null,
|
||||
"lastSeenDuplicateAt": "<now>"
|
||||
},
|
||||
{
|
||||
"userId": "<id:1>",
|
||||
"type": "PULSE",
|
||||
"lastReceivedAt": "<now>",
|
||||
"lastTrigger": "foreground",
|
||||
"lastNewSampleAt": "<now>",
|
||||
"lastBackgroundAt": null,
|
||||
"lastSeenDuplicateAt": "<now>"
|
||||
},
|
||||
{
|
||||
"userId": "<id:1>",
|
||||
"type": "SLEEP_DURATION",
|
||||
"lastReceivedAt": "<now>",
|
||||
"lastTrigger": "foreground",
|
||||
"lastNewSampleAt": "<now>",
|
||||
"lastBackgroundAt": null,
|
||||
"lastSeenDuplicateAt": "<now>"
|
||||
},
|
||||
{
|
||||
"userId": "<id:1>",
|
||||
"type": "WEIGHT",
|
||||
"lastReceivedAt": "<now>",
|
||||
"lastTrigger": "foreground",
|
||||
"lastNewSampleAt": "<now>",
|
||||
"lastBackgroundAt": null,
|
||||
"lastSeenDuplicateAt": "<now>"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
+408
@@ -0,0 +1,408 @@
|
||||
{
|
||||
"status": 200,
|
||||
"body": {
|
||||
"data": {
|
||||
"processed": 2,
|
||||
"inserted": 1,
|
||||
"updated": 0,
|
||||
"duplicates": 1,
|
||||
"failed": 0,
|
||||
"skipped": [],
|
||||
"entries": [
|
||||
{
|
||||
"index": 0,
|
||||
"status": "inserted"
|
||||
},
|
||||
{
|
||||
"index": 1,
|
||||
"status": "duplicate",
|
||||
"reason": "cross_source_merge"
|
||||
}
|
||||
]
|
||||
},
|
||||
"error": null
|
||||
},
|
||||
"events": [
|
||||
{
|
||||
"status": 200,
|
||||
"action": {
|
||||
"name": "measurement.batch.ingest"
|
||||
},
|
||||
"meta": {
|
||||
"write_bucket": "own",
|
||||
"merged": 1,
|
||||
"processed": 2,
|
||||
"pr_detection_enqueued": true,
|
||||
"pr_detection_silent": false,
|
||||
"inserted": 1,
|
||||
"updated": 0,
|
||||
"stats_unchanged": 0,
|
||||
"duplicates": 1,
|
||||
"skipped": 0,
|
||||
"skipped_by_reason": {},
|
||||
"failed": 0,
|
||||
"syncTrigger": null,
|
||||
"folded_window": 0,
|
||||
"set_inserted": 1
|
||||
},
|
||||
"warnings": null,
|
||||
"error": null
|
||||
}
|
||||
],
|
||||
"effects": [
|
||||
{
|
||||
"effect": "enqueueReminderSatisfy",
|
||||
"args": [
|
||||
"<id:1>"
|
||||
]
|
||||
},
|
||||
{
|
||||
"effect": "enqueuePrDetection",
|
||||
"args": [
|
||||
"<id:1>",
|
||||
{
|
||||
"silent": false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"effect": "maybeEnqueueMorningRefresh",
|
||||
"args": [
|
||||
"<id:1>",
|
||||
[]
|
||||
]
|
||||
},
|
||||
{
|
||||
"effect": "emitDataArrival",
|
||||
"args": [
|
||||
{
|
||||
"userId": "<id:1>",
|
||||
"kind": "weight",
|
||||
"newestSampleAt": "2026-10-15T06:30:00.000Z",
|
||||
"insertedCount": 1,
|
||||
"source": "batch"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"stored": {
|
||||
"measurements": [
|
||||
{
|
||||
"id": "<id:2>",
|
||||
"type": "WEIGHT",
|
||||
"value": 80.4,
|
||||
"valueMin": null,
|
||||
"valueMax": null,
|
||||
"unit": "kg",
|
||||
"source": "APPLE_HEALTH",
|
||||
"measuredAt": "2026-10-14T06:30:00.000Z",
|
||||
"externalId": "uuid-mass-1",
|
||||
"externalSourceVersion": null,
|
||||
"sleepStage": null,
|
||||
"rhythmClassification": null,
|
||||
"deviceType": "scale",
|
||||
"aggregationProvenance": null,
|
||||
"deletedAt": null
|
||||
},
|
||||
{
|
||||
"id": "<id:3>",
|
||||
"type": "WEIGHT",
|
||||
"value": 80.1,
|
||||
"valueMin": null,
|
||||
"valueMax": null,
|
||||
"unit": "kg",
|
||||
"source": "MANUAL",
|
||||
"measuredAt": "2026-10-15T06:30:00.000Z",
|
||||
"externalId": "manual-1",
|
||||
"externalSourceVersion": null,
|
||||
"sleepStage": null,
|
||||
"rhythmClassification": null,
|
||||
"deviceType": null,
|
||||
"aggregationProvenance": null,
|
||||
"deletedAt": null
|
||||
},
|
||||
{
|
||||
"id": "<id:4>",
|
||||
"type": "PULSE",
|
||||
"value": 62,
|
||||
"valueMin": null,
|
||||
"valueMax": null,
|
||||
"unit": "bpm",
|
||||
"source": "APPLE_HEALTH",
|
||||
"measuredAt": "2026-10-14T07:00:00.000Z",
|
||||
"externalId": "uuid-hr-1",
|
||||
"externalSourceVersion": null,
|
||||
"sleepStage": null,
|
||||
"rhythmClassification": null,
|
||||
"deviceType": "watch",
|
||||
"aggregationProvenance": null,
|
||||
"deletedAt": null
|
||||
},
|
||||
{
|
||||
"id": "<id:5>",
|
||||
"type": "PULSE",
|
||||
"value": 64,
|
||||
"valueMin": null,
|
||||
"valueMax": null,
|
||||
"unit": "bpm",
|
||||
"source": "APPLE_HEALTH",
|
||||
"measuredAt": "2026-10-14T07:05:00.000Z",
|
||||
"externalId": "uuid-hr-2",
|
||||
"externalSourceVersion": null,
|
||||
"sleepStage": null,
|
||||
"rhythmClassification": null,
|
||||
"deviceType": null,
|
||||
"aggregationProvenance": null,
|
||||
"deletedAt": null
|
||||
},
|
||||
{
|
||||
"id": "<id:6>",
|
||||
"type": "PULSE",
|
||||
"value": 65,
|
||||
"valueMin": null,
|
||||
"valueMax": null,
|
||||
"unit": "bpm",
|
||||
"source": "APPLE_HEALTH",
|
||||
"measuredAt": "2026-10-14T07:25:00.000Z",
|
||||
"externalId": "uuid-hr-twice",
|
||||
"externalSourceVersion": null,
|
||||
"sleepStage": null,
|
||||
"rhythmClassification": null,
|
||||
"deviceType": null,
|
||||
"aggregationProvenance": null,
|
||||
"deletedAt": null
|
||||
},
|
||||
{
|
||||
"id": "<id:7>",
|
||||
"type": "PULSE",
|
||||
"value": 71,
|
||||
"valueMin": 66,
|
||||
"valueMax": 79,
|
||||
"unit": "bpm",
|
||||
"source": "APPLE_HEALTH",
|
||||
"measuredAt": "2026-10-14T08:10:00.000Z",
|
||||
"externalId": "stats:HKQuantityTypeIdentifierHeartRate:2026-10-14T08:10:00.000Z",
|
||||
"externalSourceVersion": null,
|
||||
"sleepStage": null,
|
||||
"rhythmClassification": null,
|
||||
"deviceType": null,
|
||||
"aggregationProvenance": "HEALTHKIT_STATISTICS",
|
||||
"deletedAt": null
|
||||
},
|
||||
{
|
||||
"id": "<id:8>",
|
||||
"type": "PULSE",
|
||||
"value": 70,
|
||||
"valueMin": null,
|
||||
"valueMax": null,
|
||||
"unit": "bpm",
|
||||
"source": "APPLE_HEALTH",
|
||||
"measuredAt": "2026-10-14T08:20:00.000Z",
|
||||
"externalId": "stats:HKQuantityTypeIdentifierHeartRate:2026-10-14T08:20:00.000Z",
|
||||
"externalSourceVersion": null,
|
||||
"sleepStage": null,
|
||||
"rhythmClassification": null,
|
||||
"deviceType": null,
|
||||
"aggregationProvenance": "HEALTHKIT_STATISTICS",
|
||||
"deletedAt": null
|
||||
},
|
||||
{
|
||||
"id": "<id:9>",
|
||||
"type": "SLEEP_DURATION",
|
||||
"value": 0,
|
||||
"valueMin": null,
|
||||
"valueMax": null,
|
||||
"unit": "minutes",
|
||||
"source": "APPLE_HEALTH",
|
||||
"measuredAt": "2026-10-14T01:00:00.000Z",
|
||||
"externalId": "uuid-sleep-1",
|
||||
"externalSourceVersion": null,
|
||||
"sleepStage": "CORE",
|
||||
"rhythmClassification": null,
|
||||
"deviceType": null,
|
||||
"aggregationProvenance": null,
|
||||
"deletedAt": null
|
||||
},
|
||||
{
|
||||
"id": "<id:10>",
|
||||
"type": "SLEEP_DURATION",
|
||||
"value": 0,
|
||||
"valueMin": null,
|
||||
"valueMax": null,
|
||||
"unit": "minutes",
|
||||
"source": "APPLE_HEALTH",
|
||||
"measuredAt": "2026-10-14T02:30:00.000Z",
|
||||
"externalId": "uuid-sleep-2",
|
||||
"externalSourceVersion": null,
|
||||
"sleepStage": "DEEP",
|
||||
"rhythmClassification": null,
|
||||
"deviceType": null,
|
||||
"aggregationProvenance": null,
|
||||
"deletedAt": null
|
||||
},
|
||||
{
|
||||
"id": "<id:11>",
|
||||
"type": "ACTIVITY_STEPS",
|
||||
"value": 7250,
|
||||
"valueMin": null,
|
||||
"valueMax": null,
|
||||
"unit": "steps",
|
||||
"source": "APPLE_HEALTH",
|
||||
"measuredAt": "2026-10-12T18:00:00.000Z",
|
||||
"externalId": "stats:HKQuantityTypeIdentifierStepCount:2026-10-12",
|
||||
"externalSourceVersion": null,
|
||||
"sleepStage": null,
|
||||
"rhythmClassification": null,
|
||||
"deviceType": null,
|
||||
"aggregationProvenance": "HEALTHKIT_STATISTICS",
|
||||
"deletedAt": null
|
||||
},
|
||||
{
|
||||
"id": "<id:12>",
|
||||
"type": "ACTIVITY_STEPS",
|
||||
"value": 8400,
|
||||
"valueMin": null,
|
||||
"valueMax": null,
|
||||
"unit": "steps",
|
||||
"source": "APPLE_HEALTH",
|
||||
"measuredAt": "2026-10-13T18:00:00.000Z",
|
||||
"externalId": "stats:HKQuantityTypeIdentifierStepCount:2026-10-13",
|
||||
"externalSourceVersion": null,
|
||||
"sleepStage": null,
|
||||
"rhythmClassification": null,
|
||||
"deviceType": "phone",
|
||||
"aggregationProvenance": "HEALTHKIT_STATISTICS",
|
||||
"deletedAt": null
|
||||
},
|
||||
{
|
||||
"id": "<id:13>",
|
||||
"type": "ACTIVITY_STEPS",
|
||||
"value": 6300,
|
||||
"valueMin": null,
|
||||
"valueMax": null,
|
||||
"unit": "steps",
|
||||
"source": "APPLE_HEALTH",
|
||||
"measuredAt": "2026-10-14T18:00:00.000Z",
|
||||
"externalId": "stats:HKQuantityTypeIdentifierStepCount:2026-10-14",
|
||||
"externalSourceVersion": null,
|
||||
"sleepStage": null,
|
||||
"rhythmClassification": null,
|
||||
"deviceType": null,
|
||||
"aggregationProvenance": "HEALTHKIT_STATISTICS",
|
||||
"deletedAt": null
|
||||
},
|
||||
{
|
||||
"id": "<id:14>",
|
||||
"type": "OXYGEN_SATURATION",
|
||||
"value": 97,
|
||||
"valueMin": null,
|
||||
"valueMax": null,
|
||||
"unit": "%",
|
||||
"source": "APPLE_HEALTH",
|
||||
"measuredAt": "2026-10-14T07:10:00.000Z",
|
||||
"externalId": "uuid-spo2-1",
|
||||
"externalSourceVersion": null,
|
||||
"sleepStage": null,
|
||||
"rhythmClassification": null,
|
||||
"deviceType": null,
|
||||
"aggregationProvenance": null,
|
||||
"deletedAt": null
|
||||
}
|
||||
],
|
||||
"hours": [
|
||||
{
|
||||
"id": "<id:15>",
|
||||
"userId": "<id:1>",
|
||||
"type": "ACTIVITY_STEPS",
|
||||
"dateKey": "2026-10-14",
|
||||
"hourlyCumulative": [],
|
||||
"dayTotal": 0,
|
||||
"sampleCount": 0,
|
||||
"hourlyIncrements": [
|
||||
-1,
|
||||
-1,
|
||||
-1,
|
||||
-1,
|
||||
-1,
|
||||
-1,
|
||||
-1,
|
||||
-1,
|
||||
900,
|
||||
1450,
|
||||
-1,
|
||||
-1,
|
||||
-1,
|
||||
-1,
|
||||
-1,
|
||||
-1,
|
||||
-1,
|
||||
-1,
|
||||
-1,
|
||||
-1,
|
||||
-1,
|
||||
-1,
|
||||
-1,
|
||||
-1
|
||||
],
|
||||
"basis": "PER_SAMPLE",
|
||||
"bucketCount": 2,
|
||||
"timezone": "UTC",
|
||||
"createdAt": "<createdAt>",
|
||||
"updatedAt": "<updatedAt>"
|
||||
}
|
||||
],
|
||||
"user": {
|
||||
"lastSyncedAt": "<now>",
|
||||
"healthKitLastSyncedAt": "<now>",
|
||||
"healthKitLastSyncTrigger": null,
|
||||
"healthKitLastBackgroundSyncAt": "<now>"
|
||||
},
|
||||
"typeSync": [
|
||||
{
|
||||
"userId": "<id:1>",
|
||||
"type": "ACTIVITY_STEPS",
|
||||
"lastReceivedAt": "<now>",
|
||||
"lastTrigger": "background",
|
||||
"lastNewSampleAt": "<now>",
|
||||
"lastBackgroundAt": "<now>",
|
||||
"lastSeenDuplicateAt": null
|
||||
},
|
||||
{
|
||||
"userId": "<id:1>",
|
||||
"type": "OXYGEN_SATURATION",
|
||||
"lastReceivedAt": "<now>",
|
||||
"lastTrigger": "foreground",
|
||||
"lastNewSampleAt": "<now>",
|
||||
"lastBackgroundAt": null,
|
||||
"lastSeenDuplicateAt": "<now>"
|
||||
},
|
||||
{
|
||||
"userId": "<id:1>",
|
||||
"type": "PULSE",
|
||||
"lastReceivedAt": "<now>",
|
||||
"lastTrigger": "foreground",
|
||||
"lastNewSampleAt": "<now>",
|
||||
"lastBackgroundAt": null,
|
||||
"lastSeenDuplicateAt": "<now>"
|
||||
},
|
||||
{
|
||||
"userId": "<id:1>",
|
||||
"type": "SLEEP_DURATION",
|
||||
"lastReceivedAt": "<now>",
|
||||
"lastTrigger": "foreground",
|
||||
"lastNewSampleAt": "<now>",
|
||||
"lastBackgroundAt": null,
|
||||
"lastSeenDuplicateAt": "<now>"
|
||||
},
|
||||
{
|
||||
"userId": "<id:1>",
|
||||
"type": "WEIGHT",
|
||||
"lastReceivedAt": "<now>",
|
||||
"lastTrigger": "foreground",
|
||||
"lastNewSampleAt": "<now>",
|
||||
"lastBackgroundAt": null,
|
||||
"lastSeenDuplicateAt": "<now>"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
+446
@@ -0,0 +1,446 @@
|
||||
{
|
||||
"status": 200,
|
||||
"body": {
|
||||
"data": {
|
||||
"processed": 2,
|
||||
"inserted": 2,
|
||||
"updated": 0,
|
||||
"duplicates": 0,
|
||||
"failed": 0,
|
||||
"skipped": [],
|
||||
"entries": [
|
||||
{
|
||||
"index": 0,
|
||||
"status": "inserted"
|
||||
},
|
||||
{
|
||||
"index": 1,
|
||||
"status": "inserted"
|
||||
}
|
||||
]
|
||||
},
|
||||
"error": null
|
||||
},
|
||||
"events": [
|
||||
{
|
||||
"status": 200,
|
||||
"action": {
|
||||
"name": "measurement.batch.ingest"
|
||||
},
|
||||
"meta": {
|
||||
"write_bucket": "own",
|
||||
"pr_detection_enqueued": true,
|
||||
"pr_detection_silent": false,
|
||||
"processed": 2,
|
||||
"inserted": 2,
|
||||
"updated": 0,
|
||||
"stats_unchanged": 0,
|
||||
"duplicates": 0,
|
||||
"skipped": 0,
|
||||
"skipped_by_reason": {},
|
||||
"failed": 0,
|
||||
"syncTrigger": "backfill",
|
||||
"folded_window": 0,
|
||||
"set_inserted": 2
|
||||
},
|
||||
"warnings": null,
|
||||
"error": null
|
||||
}
|
||||
],
|
||||
"effects": [
|
||||
{
|
||||
"effect": "enqueueReminderSatisfy",
|
||||
"args": [
|
||||
"<id:1>"
|
||||
]
|
||||
},
|
||||
{
|
||||
"effect": "enqueuePrDetection",
|
||||
"args": [
|
||||
"<id:1>",
|
||||
{
|
||||
"silent": false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"effect": "maybeEnqueueMorningRefresh",
|
||||
"args": [
|
||||
"<id:1>",
|
||||
[]
|
||||
]
|
||||
}
|
||||
],
|
||||
"stored": {
|
||||
"measurements": [
|
||||
{
|
||||
"id": "<id:2>",
|
||||
"type": "WEIGHT",
|
||||
"value": 80.4,
|
||||
"valueMin": null,
|
||||
"valueMax": null,
|
||||
"unit": "kg",
|
||||
"source": "APPLE_HEALTH",
|
||||
"measuredAt": "2026-10-14T06:30:00.000Z",
|
||||
"externalId": "uuid-mass-1",
|
||||
"externalSourceVersion": null,
|
||||
"sleepStage": null,
|
||||
"rhythmClassification": null,
|
||||
"deviceType": "scale",
|
||||
"aggregationProvenance": null,
|
||||
"deletedAt": null
|
||||
},
|
||||
{
|
||||
"id": "<id:3>",
|
||||
"type": "WEIGHT",
|
||||
"value": 80.1,
|
||||
"valueMin": null,
|
||||
"valueMax": null,
|
||||
"unit": "kg",
|
||||
"source": "MANUAL",
|
||||
"measuredAt": "2026-10-15T06:30:00.000Z",
|
||||
"externalId": "manual-1",
|
||||
"externalSourceVersion": null,
|
||||
"sleepStage": null,
|
||||
"rhythmClassification": null,
|
||||
"deviceType": null,
|
||||
"aggregationProvenance": null,
|
||||
"deletedAt": null
|
||||
},
|
||||
{
|
||||
"id": "<id:4>",
|
||||
"type": "PULSE",
|
||||
"value": 58,
|
||||
"valueMin": null,
|
||||
"valueMax": null,
|
||||
"unit": "bpm",
|
||||
"source": "APPLE_HEALTH",
|
||||
"measuredAt": "2026-09-01T07:00:00.000Z",
|
||||
"externalId": "uuid-hr-old-1",
|
||||
"externalSourceVersion": null,
|
||||
"sleepStage": null,
|
||||
"rhythmClassification": null,
|
||||
"deviceType": null,
|
||||
"aggregationProvenance": null,
|
||||
"deletedAt": null
|
||||
},
|
||||
{
|
||||
"id": "<id:5>",
|
||||
"type": "PULSE",
|
||||
"value": 62,
|
||||
"valueMin": null,
|
||||
"valueMax": null,
|
||||
"unit": "bpm",
|
||||
"source": "APPLE_HEALTH",
|
||||
"measuredAt": "2026-10-14T07:00:00.000Z",
|
||||
"externalId": "uuid-hr-1",
|
||||
"externalSourceVersion": null,
|
||||
"sleepStage": null,
|
||||
"rhythmClassification": null,
|
||||
"deviceType": "watch",
|
||||
"aggregationProvenance": null,
|
||||
"deletedAt": null
|
||||
},
|
||||
{
|
||||
"id": "<id:6>",
|
||||
"type": "PULSE",
|
||||
"value": 64,
|
||||
"valueMin": null,
|
||||
"valueMax": null,
|
||||
"unit": "bpm",
|
||||
"source": "APPLE_HEALTH",
|
||||
"measuredAt": "2026-10-14T07:05:00.000Z",
|
||||
"externalId": "uuid-hr-2",
|
||||
"externalSourceVersion": null,
|
||||
"sleepStage": null,
|
||||
"rhythmClassification": null,
|
||||
"deviceType": null,
|
||||
"aggregationProvenance": null,
|
||||
"deletedAt": null
|
||||
},
|
||||
{
|
||||
"id": "<id:7>",
|
||||
"type": "PULSE",
|
||||
"value": 65,
|
||||
"valueMin": null,
|
||||
"valueMax": null,
|
||||
"unit": "bpm",
|
||||
"source": "APPLE_HEALTH",
|
||||
"measuredAt": "2026-10-14T07:25:00.000Z",
|
||||
"externalId": "uuid-hr-twice",
|
||||
"externalSourceVersion": null,
|
||||
"sleepStage": null,
|
||||
"rhythmClassification": null,
|
||||
"deviceType": null,
|
||||
"aggregationProvenance": null,
|
||||
"deletedAt": null
|
||||
},
|
||||
{
|
||||
"id": "<id:8>",
|
||||
"type": "PULSE",
|
||||
"value": 71,
|
||||
"valueMin": 66,
|
||||
"valueMax": 79,
|
||||
"unit": "bpm",
|
||||
"source": "APPLE_HEALTH",
|
||||
"measuredAt": "2026-10-14T08:10:00.000Z",
|
||||
"externalId": "stats:HKQuantityTypeIdentifierHeartRate:2026-10-14T08:10:00.000Z",
|
||||
"externalSourceVersion": null,
|
||||
"sleepStage": null,
|
||||
"rhythmClassification": null,
|
||||
"deviceType": null,
|
||||
"aggregationProvenance": "HEALTHKIT_STATISTICS",
|
||||
"deletedAt": null
|
||||
},
|
||||
{
|
||||
"id": "<id:9>",
|
||||
"type": "PULSE",
|
||||
"value": 70,
|
||||
"valueMin": null,
|
||||
"valueMax": null,
|
||||
"unit": "bpm",
|
||||
"source": "APPLE_HEALTH",
|
||||
"measuredAt": "2026-10-14T08:20:00.000Z",
|
||||
"externalId": "stats:HKQuantityTypeIdentifierHeartRate:2026-10-14T08:20:00.000Z",
|
||||
"externalSourceVersion": null,
|
||||
"sleepStage": null,
|
||||
"rhythmClassification": null,
|
||||
"deviceType": null,
|
||||
"aggregationProvenance": "HEALTHKIT_STATISTICS",
|
||||
"deletedAt": null
|
||||
},
|
||||
{
|
||||
"id": "<id:10>",
|
||||
"type": "SLEEP_DURATION",
|
||||
"value": 0,
|
||||
"valueMin": null,
|
||||
"valueMax": null,
|
||||
"unit": "minutes",
|
||||
"source": "APPLE_HEALTH",
|
||||
"measuredAt": "2026-10-14T01:00:00.000Z",
|
||||
"externalId": "uuid-sleep-1",
|
||||
"externalSourceVersion": null,
|
||||
"sleepStage": "CORE",
|
||||
"rhythmClassification": null,
|
||||
"deviceType": null,
|
||||
"aggregationProvenance": null,
|
||||
"deletedAt": null
|
||||
},
|
||||
{
|
||||
"id": "<id:11>",
|
||||
"type": "SLEEP_DURATION",
|
||||
"value": 0,
|
||||
"valueMin": null,
|
||||
"valueMax": null,
|
||||
"unit": "minutes",
|
||||
"source": "APPLE_HEALTH",
|
||||
"measuredAt": "2026-10-14T02:30:00.000Z",
|
||||
"externalId": "uuid-sleep-2",
|
||||
"externalSourceVersion": null,
|
||||
"sleepStage": "DEEP",
|
||||
"rhythmClassification": null,
|
||||
"deviceType": null,
|
||||
"aggregationProvenance": null,
|
||||
"deletedAt": null
|
||||
},
|
||||
{
|
||||
"id": "<id:12>",
|
||||
"type": "ACTIVITY_STEPS",
|
||||
"value": 11200,
|
||||
"valueMin": null,
|
||||
"valueMax": null,
|
||||
"unit": "steps",
|
||||
"source": "APPLE_HEALTH",
|
||||
"measuredAt": "2026-09-01T18:00:00.000Z",
|
||||
"externalId": "stats:HKQuantityTypeIdentifierStepCount:2026-09-01",
|
||||
"externalSourceVersion": null,
|
||||
"sleepStage": null,
|
||||
"rhythmClassification": null,
|
||||
"deviceType": null,
|
||||
"aggregationProvenance": "HEALTHKIT_STATISTICS",
|
||||
"deletedAt": null
|
||||
},
|
||||
{
|
||||
"id": "<id:13>",
|
||||
"type": "ACTIVITY_STEPS",
|
||||
"value": 7250,
|
||||
"valueMin": null,
|
||||
"valueMax": null,
|
||||
"unit": "steps",
|
||||
"source": "APPLE_HEALTH",
|
||||
"measuredAt": "2026-10-12T18:00:00.000Z",
|
||||
"externalId": "stats:HKQuantityTypeIdentifierStepCount:2026-10-12",
|
||||
"externalSourceVersion": null,
|
||||
"sleepStage": null,
|
||||
"rhythmClassification": null,
|
||||
"deviceType": null,
|
||||
"aggregationProvenance": "HEALTHKIT_STATISTICS",
|
||||
"deletedAt": null
|
||||
},
|
||||
{
|
||||
"id": "<id:14>",
|
||||
"type": "ACTIVITY_STEPS",
|
||||
"value": 8400,
|
||||
"valueMin": null,
|
||||
"valueMax": null,
|
||||
"unit": "steps",
|
||||
"source": "APPLE_HEALTH",
|
||||
"measuredAt": "2026-10-13T18:00:00.000Z",
|
||||
"externalId": "stats:HKQuantityTypeIdentifierStepCount:2026-10-13",
|
||||
"externalSourceVersion": null,
|
||||
"sleepStage": null,
|
||||
"rhythmClassification": null,
|
||||
"deviceType": "phone",
|
||||
"aggregationProvenance": "HEALTHKIT_STATISTICS",
|
||||
"deletedAt": null
|
||||
},
|
||||
{
|
||||
"id": "<id:15>",
|
||||
"type": "ACTIVITY_STEPS",
|
||||
"value": 6300,
|
||||
"valueMin": null,
|
||||
"valueMax": null,
|
||||
"unit": "steps",
|
||||
"source": "APPLE_HEALTH",
|
||||
"measuredAt": "2026-10-14T18:00:00.000Z",
|
||||
"externalId": "stats:HKQuantityTypeIdentifierStepCount:2026-10-14",
|
||||
"externalSourceVersion": null,
|
||||
"sleepStage": null,
|
||||
"rhythmClassification": null,
|
||||
"deviceType": null,
|
||||
"aggregationProvenance": "HEALTHKIT_STATISTICS",
|
||||
"deletedAt": null
|
||||
},
|
||||
{
|
||||
"id": "<id:16>",
|
||||
"type": "OXYGEN_SATURATION",
|
||||
"value": 97,
|
||||
"valueMin": null,
|
||||
"valueMax": null,
|
||||
"unit": "%",
|
||||
"source": "APPLE_HEALTH",
|
||||
"measuredAt": "2026-10-14T07:10:00.000Z",
|
||||
"externalId": "uuid-spo2-1",
|
||||
"externalSourceVersion": null,
|
||||
"sleepStage": null,
|
||||
"rhythmClassification": null,
|
||||
"deviceType": null,
|
||||
"aggregationProvenance": null,
|
||||
"deletedAt": null
|
||||
}
|
||||
],
|
||||
"hours": [
|
||||
{
|
||||
"id": "<id:17>",
|
||||
"userId": "<id:1>",
|
||||
"type": "ACTIVITY_STEPS",
|
||||
"dateKey": "2026-10-14",
|
||||
"hourlyCumulative": [],
|
||||
"dayTotal": 0,
|
||||
"sampleCount": 0,
|
||||
"hourlyIncrements": [
|
||||
-1,
|
||||
-1,
|
||||
-1,
|
||||
-1,
|
||||
-1,
|
||||
-1,
|
||||
-1,
|
||||
-1,
|
||||
900,
|
||||
1450,
|
||||
-1,
|
||||
-1,
|
||||
-1,
|
||||
-1,
|
||||
-1,
|
||||
-1,
|
||||
-1,
|
||||
-1,
|
||||
-1,
|
||||
-1,
|
||||
-1,
|
||||
-1,
|
||||
-1,
|
||||
-1
|
||||
],
|
||||
"basis": "PER_SAMPLE",
|
||||
"bucketCount": 2,
|
||||
"timezone": "UTC",
|
||||
"createdAt": "<createdAt>",
|
||||
"updatedAt": "<updatedAt>"
|
||||
}
|
||||
],
|
||||
"user": {
|
||||
"lastSyncedAt": "<now>",
|
||||
"healthKitLastSyncedAt": "<now>",
|
||||
"healthKitLastSyncTrigger": null,
|
||||
"healthKitLastBackgroundSyncAt": "<now>"
|
||||
},
|
||||
"typeSync": [
|
||||
{
|
||||
"userId": "<id:1>",
|
||||
"type": "ACTIVITY_STEPS",
|
||||
"lastReceivedAt": "<now>",
|
||||
"lastTrigger": "background",
|
||||
"lastNewSampleAt": "<now>",
|
||||
"lastBackgroundAt": "<now>",
|
||||
"lastSeenDuplicateAt": null
|
||||
},
|
||||
{
|
||||
"userId": "<id:1>",
|
||||
"type": "OXYGEN_SATURATION",
|
||||
"lastReceivedAt": "<now>",
|
||||
"lastTrigger": "foreground",
|
||||
"lastNewSampleAt": "<now>",
|
||||
"lastBackgroundAt": null,
|
||||
"lastSeenDuplicateAt": "<now>"
|
||||
},
|
||||
{
|
||||
"userId": "<id:1>",
|
||||
"type": "PULSE",
|
||||
"lastReceivedAt": "<now>",
|
||||
"lastTrigger": "foreground",
|
||||
"lastNewSampleAt": "<now>",
|
||||
"lastBackgroundAt": null,
|
||||
"lastSeenDuplicateAt": "<now>"
|
||||
},
|
||||
{
|
||||
"userId": "<id:1>",
|
||||
"type": "SLEEP_DURATION",
|
||||
"lastReceivedAt": "<now>",
|
||||
"lastTrigger": "foreground",
|
||||
"lastNewSampleAt": "<now>",
|
||||
"lastBackgroundAt": null,
|
||||
"lastSeenDuplicateAt": "<now>"
|
||||
},
|
||||
{
|
||||
"userId": "<id:1>",
|
||||
"type": "WEIGHT",
|
||||
"lastReceivedAt": "<now>",
|
||||
"lastTrigger": "foreground",
|
||||
"lastNewSampleAt": "<now>",
|
||||
"lastBackgroundAt": null,
|
||||
"lastSeenDuplicateAt": "<now>"
|
||||
},
|
||||
{
|
||||
"userId": "<id:1>",
|
||||
"type": "backfill:ACTIVITY_STEPS",
|
||||
"lastReceivedAt": "<now>",
|
||||
"lastTrigger": null,
|
||||
"lastNewSampleAt": null,
|
||||
"lastBackgroundAt": null,
|
||||
"lastSeenDuplicateAt": null
|
||||
},
|
||||
{
|
||||
"userId": "<id:1>",
|
||||
"type": "backfill:PULSE",
|
||||
"lastReceivedAt": "<now>",
|
||||
"lastTrigger": null,
|
||||
"lastNewSampleAt": null,
|
||||
"lastBackgroundAt": null,
|
||||
"lastSeenDuplicateAt": null
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
+395
@@ -0,0 +1,395 @@
|
||||
{
|
||||
"status": 422,
|
||||
"body": {
|
||||
"data": null,
|
||||
"error": "Batch exceeds the 500-entry limit",
|
||||
"meta": {
|
||||
"errorCode": "measurement.batch.too_large",
|
||||
"requestId": "<requestId>"
|
||||
}
|
||||
},
|
||||
"events": [
|
||||
{
|
||||
"status": 422,
|
||||
"action": null,
|
||||
"meta": {
|
||||
"write_bucket": "own"
|
||||
},
|
||||
"warnings": null,
|
||||
"error": null
|
||||
}
|
||||
],
|
||||
"effects": [],
|
||||
"stored": {
|
||||
"measurements": [
|
||||
{
|
||||
"id": "<id:1>",
|
||||
"type": "WEIGHT",
|
||||
"value": 80.4,
|
||||
"valueMin": null,
|
||||
"valueMax": null,
|
||||
"unit": "kg",
|
||||
"source": "APPLE_HEALTH",
|
||||
"measuredAt": "2026-10-14T06:30:00.000Z",
|
||||
"externalId": "uuid-mass-1",
|
||||
"externalSourceVersion": null,
|
||||
"sleepStage": null,
|
||||
"rhythmClassification": null,
|
||||
"deviceType": "scale",
|
||||
"aggregationProvenance": null,
|
||||
"deletedAt": null
|
||||
},
|
||||
{
|
||||
"id": "<id:2>",
|
||||
"type": "WEIGHT",
|
||||
"value": 80.1,
|
||||
"valueMin": null,
|
||||
"valueMax": null,
|
||||
"unit": "kg",
|
||||
"source": "MANUAL",
|
||||
"measuredAt": "2026-10-15T06:30:00.000Z",
|
||||
"externalId": "manual-1",
|
||||
"externalSourceVersion": null,
|
||||
"sleepStage": null,
|
||||
"rhythmClassification": null,
|
||||
"deviceType": null,
|
||||
"aggregationProvenance": null,
|
||||
"deletedAt": null
|
||||
},
|
||||
{
|
||||
"id": "<id:3>",
|
||||
"type": "PULSE",
|
||||
"value": 58,
|
||||
"valueMin": null,
|
||||
"valueMax": null,
|
||||
"unit": "bpm",
|
||||
"source": "APPLE_HEALTH",
|
||||
"measuredAt": "2026-09-01T07:00:00.000Z",
|
||||
"externalId": "uuid-hr-old-1",
|
||||
"externalSourceVersion": null,
|
||||
"sleepStage": null,
|
||||
"rhythmClassification": null,
|
||||
"deviceType": null,
|
||||
"aggregationProvenance": null,
|
||||
"deletedAt": null
|
||||
},
|
||||
{
|
||||
"id": "<id:4>",
|
||||
"type": "PULSE",
|
||||
"value": 62,
|
||||
"valueMin": null,
|
||||
"valueMax": null,
|
||||
"unit": "bpm",
|
||||
"source": "APPLE_HEALTH",
|
||||
"measuredAt": "2026-10-14T07:00:00.000Z",
|
||||
"externalId": "uuid-hr-1",
|
||||
"externalSourceVersion": null,
|
||||
"sleepStage": null,
|
||||
"rhythmClassification": null,
|
||||
"deviceType": "watch",
|
||||
"aggregationProvenance": null,
|
||||
"deletedAt": null
|
||||
},
|
||||
{
|
||||
"id": "<id:5>",
|
||||
"type": "PULSE",
|
||||
"value": 64,
|
||||
"valueMin": null,
|
||||
"valueMax": null,
|
||||
"unit": "bpm",
|
||||
"source": "APPLE_HEALTH",
|
||||
"measuredAt": "2026-10-14T07:05:00.000Z",
|
||||
"externalId": "uuid-hr-2",
|
||||
"externalSourceVersion": null,
|
||||
"sleepStage": null,
|
||||
"rhythmClassification": null,
|
||||
"deviceType": null,
|
||||
"aggregationProvenance": null,
|
||||
"deletedAt": null
|
||||
},
|
||||
{
|
||||
"id": "<id:6>",
|
||||
"type": "PULSE",
|
||||
"value": 65,
|
||||
"valueMin": null,
|
||||
"valueMax": null,
|
||||
"unit": "bpm",
|
||||
"source": "APPLE_HEALTH",
|
||||
"measuredAt": "2026-10-14T07:25:00.000Z",
|
||||
"externalId": "uuid-hr-twice",
|
||||
"externalSourceVersion": null,
|
||||
"sleepStage": null,
|
||||
"rhythmClassification": null,
|
||||
"deviceType": null,
|
||||
"aggregationProvenance": null,
|
||||
"deletedAt": null
|
||||
},
|
||||
{
|
||||
"id": "<id:7>",
|
||||
"type": "PULSE",
|
||||
"value": 71,
|
||||
"valueMin": 66,
|
||||
"valueMax": 79,
|
||||
"unit": "bpm",
|
||||
"source": "APPLE_HEALTH",
|
||||
"measuredAt": "2026-10-14T08:10:00.000Z",
|
||||
"externalId": "stats:HKQuantityTypeIdentifierHeartRate:2026-10-14T08:10:00.000Z",
|
||||
"externalSourceVersion": null,
|
||||
"sleepStage": null,
|
||||
"rhythmClassification": null,
|
||||
"deviceType": null,
|
||||
"aggregationProvenance": "HEALTHKIT_STATISTICS",
|
||||
"deletedAt": null
|
||||
},
|
||||
{
|
||||
"id": "<id:8>",
|
||||
"type": "PULSE",
|
||||
"value": 70,
|
||||
"valueMin": null,
|
||||
"valueMax": null,
|
||||
"unit": "bpm",
|
||||
"source": "APPLE_HEALTH",
|
||||
"measuredAt": "2026-10-14T08:20:00.000Z",
|
||||
"externalId": "stats:HKQuantityTypeIdentifierHeartRate:2026-10-14T08:20:00.000Z",
|
||||
"externalSourceVersion": null,
|
||||
"sleepStage": null,
|
||||
"rhythmClassification": null,
|
||||
"deviceType": null,
|
||||
"aggregationProvenance": "HEALTHKIT_STATISTICS",
|
||||
"deletedAt": null
|
||||
},
|
||||
{
|
||||
"id": "<id:9>",
|
||||
"type": "SLEEP_DURATION",
|
||||
"value": 0,
|
||||
"valueMin": null,
|
||||
"valueMax": null,
|
||||
"unit": "minutes",
|
||||
"source": "APPLE_HEALTH",
|
||||
"measuredAt": "2026-10-14T01:00:00.000Z",
|
||||
"externalId": "uuid-sleep-1",
|
||||
"externalSourceVersion": null,
|
||||
"sleepStage": "CORE",
|
||||
"rhythmClassification": null,
|
||||
"deviceType": null,
|
||||
"aggregationProvenance": null,
|
||||
"deletedAt": null
|
||||
},
|
||||
{
|
||||
"id": "<id:10>",
|
||||
"type": "SLEEP_DURATION",
|
||||
"value": 0,
|
||||
"valueMin": null,
|
||||
"valueMax": null,
|
||||
"unit": "minutes",
|
||||
"source": "APPLE_HEALTH",
|
||||
"measuredAt": "2026-10-14T02:30:00.000Z",
|
||||
"externalId": "uuid-sleep-2",
|
||||
"externalSourceVersion": null,
|
||||
"sleepStage": "DEEP",
|
||||
"rhythmClassification": null,
|
||||
"deviceType": null,
|
||||
"aggregationProvenance": null,
|
||||
"deletedAt": null
|
||||
},
|
||||
{
|
||||
"id": "<id:11>",
|
||||
"type": "ACTIVITY_STEPS",
|
||||
"value": 11200,
|
||||
"valueMin": null,
|
||||
"valueMax": null,
|
||||
"unit": "steps",
|
||||
"source": "APPLE_HEALTH",
|
||||
"measuredAt": "2026-09-01T18:00:00.000Z",
|
||||
"externalId": "stats:HKQuantityTypeIdentifierStepCount:2026-09-01",
|
||||
"externalSourceVersion": null,
|
||||
"sleepStage": null,
|
||||
"rhythmClassification": null,
|
||||
"deviceType": null,
|
||||
"aggregationProvenance": "HEALTHKIT_STATISTICS",
|
||||
"deletedAt": null
|
||||
},
|
||||
{
|
||||
"id": "<id:12>",
|
||||
"type": "ACTIVITY_STEPS",
|
||||
"value": 7250,
|
||||
"valueMin": null,
|
||||
"valueMax": null,
|
||||
"unit": "steps",
|
||||
"source": "APPLE_HEALTH",
|
||||
"measuredAt": "2026-10-12T18:00:00.000Z",
|
||||
"externalId": "stats:HKQuantityTypeIdentifierStepCount:2026-10-12",
|
||||
"externalSourceVersion": null,
|
||||
"sleepStage": null,
|
||||
"rhythmClassification": null,
|
||||
"deviceType": null,
|
||||
"aggregationProvenance": "HEALTHKIT_STATISTICS",
|
||||
"deletedAt": null
|
||||
},
|
||||
{
|
||||
"id": "<id:13>",
|
||||
"type": "ACTIVITY_STEPS",
|
||||
"value": 8400,
|
||||
"valueMin": null,
|
||||
"valueMax": null,
|
||||
"unit": "steps",
|
||||
"source": "APPLE_HEALTH",
|
||||
"measuredAt": "2026-10-13T18:00:00.000Z",
|
||||
"externalId": "stats:HKQuantityTypeIdentifierStepCount:2026-10-13",
|
||||
"externalSourceVersion": null,
|
||||
"sleepStage": null,
|
||||
"rhythmClassification": null,
|
||||
"deviceType": "phone",
|
||||
"aggregationProvenance": "HEALTHKIT_STATISTICS",
|
||||
"deletedAt": null
|
||||
},
|
||||
{
|
||||
"id": "<id:14>",
|
||||
"type": "ACTIVITY_STEPS",
|
||||
"value": 6300,
|
||||
"valueMin": null,
|
||||
"valueMax": null,
|
||||
"unit": "steps",
|
||||
"source": "APPLE_HEALTH",
|
||||
"measuredAt": "2026-10-14T18:00:00.000Z",
|
||||
"externalId": "stats:HKQuantityTypeIdentifierStepCount:2026-10-14",
|
||||
"externalSourceVersion": null,
|
||||
"sleepStage": null,
|
||||
"rhythmClassification": null,
|
||||
"deviceType": null,
|
||||
"aggregationProvenance": "HEALTHKIT_STATISTICS",
|
||||
"deletedAt": null
|
||||
},
|
||||
{
|
||||
"id": "<id:15>",
|
||||
"type": "OXYGEN_SATURATION",
|
||||
"value": 97,
|
||||
"valueMin": null,
|
||||
"valueMax": null,
|
||||
"unit": "%",
|
||||
"source": "APPLE_HEALTH",
|
||||
"measuredAt": "2026-10-14T07:10:00.000Z",
|
||||
"externalId": "uuid-spo2-1",
|
||||
"externalSourceVersion": null,
|
||||
"sleepStage": null,
|
||||
"rhythmClassification": null,
|
||||
"deviceType": null,
|
||||
"aggregationProvenance": null,
|
||||
"deletedAt": null
|
||||
}
|
||||
],
|
||||
"hours": [
|
||||
{
|
||||
"id": "<id:16>",
|
||||
"userId": "<id:17>",
|
||||
"type": "ACTIVITY_STEPS",
|
||||
"dateKey": "2026-10-14",
|
||||
"hourlyCumulative": [],
|
||||
"dayTotal": 0,
|
||||
"sampleCount": 0,
|
||||
"hourlyIncrements": [
|
||||
-1,
|
||||
-1,
|
||||
-1,
|
||||
-1,
|
||||
-1,
|
||||
-1,
|
||||
-1,
|
||||
-1,
|
||||
900,
|
||||
1450,
|
||||
-1,
|
||||
-1,
|
||||
-1,
|
||||
-1,
|
||||
-1,
|
||||
-1,
|
||||
-1,
|
||||
-1,
|
||||
-1,
|
||||
-1,
|
||||
-1,
|
||||
-1,
|
||||
-1,
|
||||
-1
|
||||
],
|
||||
"basis": "PER_SAMPLE",
|
||||
"bucketCount": 2,
|
||||
"timezone": "UTC",
|
||||
"createdAt": "<createdAt>",
|
||||
"updatedAt": "<updatedAt>"
|
||||
}
|
||||
],
|
||||
"user": {
|
||||
"lastSyncedAt": "<now>",
|
||||
"healthKitLastSyncedAt": "<now>",
|
||||
"healthKitLastSyncTrigger": null,
|
||||
"healthKitLastBackgroundSyncAt": "<now>"
|
||||
},
|
||||
"typeSync": [
|
||||
{
|
||||
"userId": "<id:17>",
|
||||
"type": "ACTIVITY_STEPS",
|
||||
"lastReceivedAt": "<now>",
|
||||
"lastTrigger": "background",
|
||||
"lastNewSampleAt": "<now>",
|
||||
"lastBackgroundAt": "<now>",
|
||||
"lastSeenDuplicateAt": null
|
||||
},
|
||||
{
|
||||
"userId": "<id:17>",
|
||||
"type": "OXYGEN_SATURATION",
|
||||
"lastReceivedAt": "<now>",
|
||||
"lastTrigger": "foreground",
|
||||
"lastNewSampleAt": "<now>",
|
||||
"lastBackgroundAt": null,
|
||||
"lastSeenDuplicateAt": "<now>"
|
||||
},
|
||||
{
|
||||
"userId": "<id:17>",
|
||||
"type": "PULSE",
|
||||
"lastReceivedAt": "<now>",
|
||||
"lastTrigger": "foreground",
|
||||
"lastNewSampleAt": "<now>",
|
||||
"lastBackgroundAt": null,
|
||||
"lastSeenDuplicateAt": "<now>"
|
||||
},
|
||||
{
|
||||
"userId": "<id:17>",
|
||||
"type": "SLEEP_DURATION",
|
||||
"lastReceivedAt": "<now>",
|
||||
"lastTrigger": "foreground",
|
||||
"lastNewSampleAt": "<now>",
|
||||
"lastBackgroundAt": null,
|
||||
"lastSeenDuplicateAt": "<now>"
|
||||
},
|
||||
{
|
||||
"userId": "<id:17>",
|
||||
"type": "WEIGHT",
|
||||
"lastReceivedAt": "<now>",
|
||||
"lastTrigger": "foreground",
|
||||
"lastNewSampleAt": "<now>",
|
||||
"lastBackgroundAt": null,
|
||||
"lastSeenDuplicateAt": "<now>"
|
||||
},
|
||||
{
|
||||
"userId": "<id:17>",
|
||||
"type": "backfill:ACTIVITY_STEPS",
|
||||
"lastReceivedAt": "<now>",
|
||||
"lastTrigger": null,
|
||||
"lastNewSampleAt": null,
|
||||
"lastBackgroundAt": null,
|
||||
"lastSeenDuplicateAt": null
|
||||
},
|
||||
{
|
||||
"userId": "<id:17>",
|
||||
"type": "backfill:PULSE",
|
||||
"lastReceivedAt": "<now>",
|
||||
"lastTrigger": null,
|
||||
"lastNewSampleAt": null,
|
||||
"lastBackgroundAt": null,
|
||||
"lastSeenDuplicateAt": null
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
+419
@@ -0,0 +1,419 @@
|
||||
{
|
||||
"status": 422,
|
||||
"body": {
|
||||
"data": null,
|
||||
"error": "Invalid input: expected number, received string",
|
||||
"details": {
|
||||
"issues": [
|
||||
{
|
||||
"path": "entries.0.value",
|
||||
"code": "invalid_type",
|
||||
"message": "Invalid input: expected number, received string"
|
||||
},
|
||||
{
|
||||
"path": "entries.0.startDate",
|
||||
"code": "invalid_type",
|
||||
"message": "Invalid input: expected string, received undefined"
|
||||
},
|
||||
{
|
||||
"path": "entries.0.endDate",
|
||||
"code": "invalid_type",
|
||||
"message": "Invalid input: expected string, received undefined"
|
||||
},
|
||||
{
|
||||
"path": "entries.0.externalId",
|
||||
"code": "invalid_type",
|
||||
"message": "Invalid input: expected string, received undefined"
|
||||
}
|
||||
]
|
||||
},
|
||||
"meta": {
|
||||
"errorCode": "measurement.batch.invalid",
|
||||
"requestId": "<requestId>"
|
||||
}
|
||||
},
|
||||
"events": [
|
||||
{
|
||||
"status": 422,
|
||||
"action": null,
|
||||
"meta": {
|
||||
"write_bucket": "own"
|
||||
},
|
||||
"warnings": null,
|
||||
"error": null
|
||||
}
|
||||
],
|
||||
"effects": [],
|
||||
"stored": {
|
||||
"measurements": [
|
||||
{
|
||||
"id": "<id:1>",
|
||||
"type": "WEIGHT",
|
||||
"value": 80.4,
|
||||
"valueMin": null,
|
||||
"valueMax": null,
|
||||
"unit": "kg",
|
||||
"source": "APPLE_HEALTH",
|
||||
"measuredAt": "2026-10-14T06:30:00.000Z",
|
||||
"externalId": "uuid-mass-1",
|
||||
"externalSourceVersion": null,
|
||||
"sleepStage": null,
|
||||
"rhythmClassification": null,
|
||||
"deviceType": "scale",
|
||||
"aggregationProvenance": null,
|
||||
"deletedAt": null
|
||||
},
|
||||
{
|
||||
"id": "<id:2>",
|
||||
"type": "WEIGHT",
|
||||
"value": 80.1,
|
||||
"valueMin": null,
|
||||
"valueMax": null,
|
||||
"unit": "kg",
|
||||
"source": "MANUAL",
|
||||
"measuredAt": "2026-10-15T06:30:00.000Z",
|
||||
"externalId": "manual-1",
|
||||
"externalSourceVersion": null,
|
||||
"sleepStage": null,
|
||||
"rhythmClassification": null,
|
||||
"deviceType": null,
|
||||
"aggregationProvenance": null,
|
||||
"deletedAt": null
|
||||
},
|
||||
{
|
||||
"id": "<id:3>",
|
||||
"type": "PULSE",
|
||||
"value": 58,
|
||||
"valueMin": null,
|
||||
"valueMax": null,
|
||||
"unit": "bpm",
|
||||
"source": "APPLE_HEALTH",
|
||||
"measuredAt": "2026-09-01T07:00:00.000Z",
|
||||
"externalId": "uuid-hr-old-1",
|
||||
"externalSourceVersion": null,
|
||||
"sleepStage": null,
|
||||
"rhythmClassification": null,
|
||||
"deviceType": null,
|
||||
"aggregationProvenance": null,
|
||||
"deletedAt": null
|
||||
},
|
||||
{
|
||||
"id": "<id:4>",
|
||||
"type": "PULSE",
|
||||
"value": 62,
|
||||
"valueMin": null,
|
||||
"valueMax": null,
|
||||
"unit": "bpm",
|
||||
"source": "APPLE_HEALTH",
|
||||
"measuredAt": "2026-10-14T07:00:00.000Z",
|
||||
"externalId": "uuid-hr-1",
|
||||
"externalSourceVersion": null,
|
||||
"sleepStage": null,
|
||||
"rhythmClassification": null,
|
||||
"deviceType": "watch",
|
||||
"aggregationProvenance": null,
|
||||
"deletedAt": null
|
||||
},
|
||||
{
|
||||
"id": "<id:5>",
|
||||
"type": "PULSE",
|
||||
"value": 64,
|
||||
"valueMin": null,
|
||||
"valueMax": null,
|
||||
"unit": "bpm",
|
||||
"source": "APPLE_HEALTH",
|
||||
"measuredAt": "2026-10-14T07:05:00.000Z",
|
||||
"externalId": "uuid-hr-2",
|
||||
"externalSourceVersion": null,
|
||||
"sleepStage": null,
|
||||
"rhythmClassification": null,
|
||||
"deviceType": null,
|
||||
"aggregationProvenance": null,
|
||||
"deletedAt": null
|
||||
},
|
||||
{
|
||||
"id": "<id:6>",
|
||||
"type": "PULSE",
|
||||
"value": 65,
|
||||
"valueMin": null,
|
||||
"valueMax": null,
|
||||
"unit": "bpm",
|
||||
"source": "APPLE_HEALTH",
|
||||
"measuredAt": "2026-10-14T07:25:00.000Z",
|
||||
"externalId": "uuid-hr-twice",
|
||||
"externalSourceVersion": null,
|
||||
"sleepStage": null,
|
||||
"rhythmClassification": null,
|
||||
"deviceType": null,
|
||||
"aggregationProvenance": null,
|
||||
"deletedAt": null
|
||||
},
|
||||
{
|
||||
"id": "<id:7>",
|
||||
"type": "PULSE",
|
||||
"value": 71,
|
||||
"valueMin": 66,
|
||||
"valueMax": 79,
|
||||
"unit": "bpm",
|
||||
"source": "APPLE_HEALTH",
|
||||
"measuredAt": "2026-10-14T08:10:00.000Z",
|
||||
"externalId": "stats:HKQuantityTypeIdentifierHeartRate:2026-10-14T08:10:00.000Z",
|
||||
"externalSourceVersion": null,
|
||||
"sleepStage": null,
|
||||
"rhythmClassification": null,
|
||||
"deviceType": null,
|
||||
"aggregationProvenance": "HEALTHKIT_STATISTICS",
|
||||
"deletedAt": null
|
||||
},
|
||||
{
|
||||
"id": "<id:8>",
|
||||
"type": "PULSE",
|
||||
"value": 70,
|
||||
"valueMin": null,
|
||||
"valueMax": null,
|
||||
"unit": "bpm",
|
||||
"source": "APPLE_HEALTH",
|
||||
"measuredAt": "2026-10-14T08:20:00.000Z",
|
||||
"externalId": "stats:HKQuantityTypeIdentifierHeartRate:2026-10-14T08:20:00.000Z",
|
||||
"externalSourceVersion": null,
|
||||
"sleepStage": null,
|
||||
"rhythmClassification": null,
|
||||
"deviceType": null,
|
||||
"aggregationProvenance": "HEALTHKIT_STATISTICS",
|
||||
"deletedAt": null
|
||||
},
|
||||
{
|
||||
"id": "<id:9>",
|
||||
"type": "SLEEP_DURATION",
|
||||
"value": 0,
|
||||
"valueMin": null,
|
||||
"valueMax": null,
|
||||
"unit": "minutes",
|
||||
"source": "APPLE_HEALTH",
|
||||
"measuredAt": "2026-10-14T01:00:00.000Z",
|
||||
"externalId": "uuid-sleep-1",
|
||||
"externalSourceVersion": null,
|
||||
"sleepStage": "CORE",
|
||||
"rhythmClassification": null,
|
||||
"deviceType": null,
|
||||
"aggregationProvenance": null,
|
||||
"deletedAt": null
|
||||
},
|
||||
{
|
||||
"id": "<id:10>",
|
||||
"type": "SLEEP_DURATION",
|
||||
"value": 0,
|
||||
"valueMin": null,
|
||||
"valueMax": null,
|
||||
"unit": "minutes",
|
||||
"source": "APPLE_HEALTH",
|
||||
"measuredAt": "2026-10-14T02:30:00.000Z",
|
||||
"externalId": "uuid-sleep-2",
|
||||
"externalSourceVersion": null,
|
||||
"sleepStage": "DEEP",
|
||||
"rhythmClassification": null,
|
||||
"deviceType": null,
|
||||
"aggregationProvenance": null,
|
||||
"deletedAt": null
|
||||
},
|
||||
{
|
||||
"id": "<id:11>",
|
||||
"type": "ACTIVITY_STEPS",
|
||||
"value": 11200,
|
||||
"valueMin": null,
|
||||
"valueMax": null,
|
||||
"unit": "steps",
|
||||
"source": "APPLE_HEALTH",
|
||||
"measuredAt": "2026-09-01T18:00:00.000Z",
|
||||
"externalId": "stats:HKQuantityTypeIdentifierStepCount:2026-09-01",
|
||||
"externalSourceVersion": null,
|
||||
"sleepStage": null,
|
||||
"rhythmClassification": null,
|
||||
"deviceType": null,
|
||||
"aggregationProvenance": "HEALTHKIT_STATISTICS",
|
||||
"deletedAt": null
|
||||
},
|
||||
{
|
||||
"id": "<id:12>",
|
||||
"type": "ACTIVITY_STEPS",
|
||||
"value": 7250,
|
||||
"valueMin": null,
|
||||
"valueMax": null,
|
||||
"unit": "steps",
|
||||
"source": "APPLE_HEALTH",
|
||||
"measuredAt": "2026-10-12T18:00:00.000Z",
|
||||
"externalId": "stats:HKQuantityTypeIdentifierStepCount:2026-10-12",
|
||||
"externalSourceVersion": null,
|
||||
"sleepStage": null,
|
||||
"rhythmClassification": null,
|
||||
"deviceType": null,
|
||||
"aggregationProvenance": "HEALTHKIT_STATISTICS",
|
||||
"deletedAt": null
|
||||
},
|
||||
{
|
||||
"id": "<id:13>",
|
||||
"type": "ACTIVITY_STEPS",
|
||||
"value": 8400,
|
||||
"valueMin": null,
|
||||
"valueMax": null,
|
||||
"unit": "steps",
|
||||
"source": "APPLE_HEALTH",
|
||||
"measuredAt": "2026-10-13T18:00:00.000Z",
|
||||
"externalId": "stats:HKQuantityTypeIdentifierStepCount:2026-10-13",
|
||||
"externalSourceVersion": null,
|
||||
"sleepStage": null,
|
||||
"rhythmClassification": null,
|
||||
"deviceType": "phone",
|
||||
"aggregationProvenance": "HEALTHKIT_STATISTICS",
|
||||
"deletedAt": null
|
||||
},
|
||||
{
|
||||
"id": "<id:14>",
|
||||
"type": "ACTIVITY_STEPS",
|
||||
"value": 6300,
|
||||
"valueMin": null,
|
||||
"valueMax": null,
|
||||
"unit": "steps",
|
||||
"source": "APPLE_HEALTH",
|
||||
"measuredAt": "2026-10-14T18:00:00.000Z",
|
||||
"externalId": "stats:HKQuantityTypeIdentifierStepCount:2026-10-14",
|
||||
"externalSourceVersion": null,
|
||||
"sleepStage": null,
|
||||
"rhythmClassification": null,
|
||||
"deviceType": null,
|
||||
"aggregationProvenance": "HEALTHKIT_STATISTICS",
|
||||
"deletedAt": null
|
||||
},
|
||||
{
|
||||
"id": "<id:15>",
|
||||
"type": "OXYGEN_SATURATION",
|
||||
"value": 97,
|
||||
"valueMin": null,
|
||||
"valueMax": null,
|
||||
"unit": "%",
|
||||
"source": "APPLE_HEALTH",
|
||||
"measuredAt": "2026-10-14T07:10:00.000Z",
|
||||
"externalId": "uuid-spo2-1",
|
||||
"externalSourceVersion": null,
|
||||
"sleepStage": null,
|
||||
"rhythmClassification": null,
|
||||
"deviceType": null,
|
||||
"aggregationProvenance": null,
|
||||
"deletedAt": null
|
||||
}
|
||||
],
|
||||
"hours": [
|
||||
{
|
||||
"id": "<id:16>",
|
||||
"userId": "<id:17>",
|
||||
"type": "ACTIVITY_STEPS",
|
||||
"dateKey": "2026-10-14",
|
||||
"hourlyCumulative": [],
|
||||
"dayTotal": 0,
|
||||
"sampleCount": 0,
|
||||
"hourlyIncrements": [
|
||||
-1,
|
||||
-1,
|
||||
-1,
|
||||
-1,
|
||||
-1,
|
||||
-1,
|
||||
-1,
|
||||
-1,
|
||||
900,
|
||||
1450,
|
||||
-1,
|
||||
-1,
|
||||
-1,
|
||||
-1,
|
||||
-1,
|
||||
-1,
|
||||
-1,
|
||||
-1,
|
||||
-1,
|
||||
-1,
|
||||
-1,
|
||||
-1,
|
||||
-1,
|
||||
-1
|
||||
],
|
||||
"basis": "PER_SAMPLE",
|
||||
"bucketCount": 2,
|
||||
"timezone": "UTC",
|
||||
"createdAt": "<createdAt>",
|
||||
"updatedAt": "<updatedAt>"
|
||||
}
|
||||
],
|
||||
"user": {
|
||||
"lastSyncedAt": "<now>",
|
||||
"healthKitLastSyncedAt": "<now>",
|
||||
"healthKitLastSyncTrigger": null,
|
||||
"healthKitLastBackgroundSyncAt": "<now>"
|
||||
},
|
||||
"typeSync": [
|
||||
{
|
||||
"userId": "<id:17>",
|
||||
"type": "ACTIVITY_STEPS",
|
||||
"lastReceivedAt": "<now>",
|
||||
"lastTrigger": "background",
|
||||
"lastNewSampleAt": "<now>",
|
||||
"lastBackgroundAt": "<now>",
|
||||
"lastSeenDuplicateAt": null
|
||||
},
|
||||
{
|
||||
"userId": "<id:17>",
|
||||
"type": "OXYGEN_SATURATION",
|
||||
"lastReceivedAt": "<now>",
|
||||
"lastTrigger": "foreground",
|
||||
"lastNewSampleAt": "<now>",
|
||||
"lastBackgroundAt": null,
|
||||
"lastSeenDuplicateAt": "<now>"
|
||||
},
|
||||
{
|
||||
"userId": "<id:17>",
|
||||
"type": "PULSE",
|
||||
"lastReceivedAt": "<now>",
|
||||
"lastTrigger": "foreground",
|
||||
"lastNewSampleAt": "<now>",
|
||||
"lastBackgroundAt": null,
|
||||
"lastSeenDuplicateAt": "<now>"
|
||||
},
|
||||
{
|
||||
"userId": "<id:17>",
|
||||
"type": "SLEEP_DURATION",
|
||||
"lastReceivedAt": "<now>",
|
||||
"lastTrigger": "foreground",
|
||||
"lastNewSampleAt": "<now>",
|
||||
"lastBackgroundAt": null,
|
||||
"lastSeenDuplicateAt": "<now>"
|
||||
},
|
||||
{
|
||||
"userId": "<id:17>",
|
||||
"type": "WEIGHT",
|
||||
"lastReceivedAt": "<now>",
|
||||
"lastTrigger": "foreground",
|
||||
"lastNewSampleAt": "<now>",
|
||||
"lastBackgroundAt": null,
|
||||
"lastSeenDuplicateAt": "<now>"
|
||||
},
|
||||
{
|
||||
"userId": "<id:17>",
|
||||
"type": "backfill:ACTIVITY_STEPS",
|
||||
"lastReceivedAt": "<now>",
|
||||
"lastTrigger": null,
|
||||
"lastNewSampleAt": null,
|
||||
"lastBackgroundAt": null,
|
||||
"lastSeenDuplicateAt": null
|
||||
},
|
||||
{
|
||||
"userId": "<id:17>",
|
||||
"type": "backfill:PULSE",
|
||||
"lastReceivedAt": "<now>",
|
||||
"lastTrigger": null,
|
||||
"lastNewSampleAt": null,
|
||||
"lastBackgroundAt": null,
|
||||
"lastSeenDuplicateAt": null
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
+398
@@ -0,0 +1,398 @@
|
||||
{
|
||||
"status": 422,
|
||||
"body": {
|
||||
"data": null,
|
||||
"error": "This credential resolves the source itself; omit the field",
|
||||
"meta": {
|
||||
"errorCode": "measurement.batch.source_not_permitted",
|
||||
"requestId": "<requestId>"
|
||||
}
|
||||
},
|
||||
"events": [
|
||||
{
|
||||
"status": 422,
|
||||
"action": {
|
||||
"name": "measurement.batch.ingest"
|
||||
},
|
||||
"meta": {
|
||||
"write_bucket": "own",
|
||||
"outcome": "source_not_permitted"
|
||||
},
|
||||
"warnings": null,
|
||||
"error": null
|
||||
}
|
||||
],
|
||||
"effects": [],
|
||||
"stored": {
|
||||
"measurements": [
|
||||
{
|
||||
"id": "<id:1>",
|
||||
"type": "WEIGHT",
|
||||
"value": 80.4,
|
||||
"valueMin": null,
|
||||
"valueMax": null,
|
||||
"unit": "kg",
|
||||
"source": "APPLE_HEALTH",
|
||||
"measuredAt": "2026-10-14T06:30:00.000Z",
|
||||
"externalId": "uuid-mass-1",
|
||||
"externalSourceVersion": null,
|
||||
"sleepStage": null,
|
||||
"rhythmClassification": null,
|
||||
"deviceType": "scale",
|
||||
"aggregationProvenance": null,
|
||||
"deletedAt": null
|
||||
},
|
||||
{
|
||||
"id": "<id:2>",
|
||||
"type": "WEIGHT",
|
||||
"value": 80.1,
|
||||
"valueMin": null,
|
||||
"valueMax": null,
|
||||
"unit": "kg",
|
||||
"source": "MANUAL",
|
||||
"measuredAt": "2026-10-15T06:30:00.000Z",
|
||||
"externalId": "manual-1",
|
||||
"externalSourceVersion": null,
|
||||
"sleepStage": null,
|
||||
"rhythmClassification": null,
|
||||
"deviceType": null,
|
||||
"aggregationProvenance": null,
|
||||
"deletedAt": null
|
||||
},
|
||||
{
|
||||
"id": "<id:3>",
|
||||
"type": "PULSE",
|
||||
"value": 58,
|
||||
"valueMin": null,
|
||||
"valueMax": null,
|
||||
"unit": "bpm",
|
||||
"source": "APPLE_HEALTH",
|
||||
"measuredAt": "2026-09-01T07:00:00.000Z",
|
||||
"externalId": "uuid-hr-old-1",
|
||||
"externalSourceVersion": null,
|
||||
"sleepStage": null,
|
||||
"rhythmClassification": null,
|
||||
"deviceType": null,
|
||||
"aggregationProvenance": null,
|
||||
"deletedAt": null
|
||||
},
|
||||
{
|
||||
"id": "<id:4>",
|
||||
"type": "PULSE",
|
||||
"value": 62,
|
||||
"valueMin": null,
|
||||
"valueMax": null,
|
||||
"unit": "bpm",
|
||||
"source": "APPLE_HEALTH",
|
||||
"measuredAt": "2026-10-14T07:00:00.000Z",
|
||||
"externalId": "uuid-hr-1",
|
||||
"externalSourceVersion": null,
|
||||
"sleepStage": null,
|
||||
"rhythmClassification": null,
|
||||
"deviceType": "watch",
|
||||
"aggregationProvenance": null,
|
||||
"deletedAt": null
|
||||
},
|
||||
{
|
||||
"id": "<id:5>",
|
||||
"type": "PULSE",
|
||||
"value": 64,
|
||||
"valueMin": null,
|
||||
"valueMax": null,
|
||||
"unit": "bpm",
|
||||
"source": "APPLE_HEALTH",
|
||||
"measuredAt": "2026-10-14T07:05:00.000Z",
|
||||
"externalId": "uuid-hr-2",
|
||||
"externalSourceVersion": null,
|
||||
"sleepStage": null,
|
||||
"rhythmClassification": null,
|
||||
"deviceType": null,
|
||||
"aggregationProvenance": null,
|
||||
"deletedAt": null
|
||||
},
|
||||
{
|
||||
"id": "<id:6>",
|
||||
"type": "PULSE",
|
||||
"value": 65,
|
||||
"valueMin": null,
|
||||
"valueMax": null,
|
||||
"unit": "bpm",
|
||||
"source": "APPLE_HEALTH",
|
||||
"measuredAt": "2026-10-14T07:25:00.000Z",
|
||||
"externalId": "uuid-hr-twice",
|
||||
"externalSourceVersion": null,
|
||||
"sleepStage": null,
|
||||
"rhythmClassification": null,
|
||||
"deviceType": null,
|
||||
"aggregationProvenance": null,
|
||||
"deletedAt": null
|
||||
},
|
||||
{
|
||||
"id": "<id:7>",
|
||||
"type": "PULSE",
|
||||
"value": 71,
|
||||
"valueMin": 66,
|
||||
"valueMax": 79,
|
||||
"unit": "bpm",
|
||||
"source": "APPLE_HEALTH",
|
||||
"measuredAt": "2026-10-14T08:10:00.000Z",
|
||||
"externalId": "stats:HKQuantityTypeIdentifierHeartRate:2026-10-14T08:10:00.000Z",
|
||||
"externalSourceVersion": null,
|
||||
"sleepStage": null,
|
||||
"rhythmClassification": null,
|
||||
"deviceType": null,
|
||||
"aggregationProvenance": "HEALTHKIT_STATISTICS",
|
||||
"deletedAt": null
|
||||
},
|
||||
{
|
||||
"id": "<id:8>",
|
||||
"type": "PULSE",
|
||||
"value": 70,
|
||||
"valueMin": null,
|
||||
"valueMax": null,
|
||||
"unit": "bpm",
|
||||
"source": "APPLE_HEALTH",
|
||||
"measuredAt": "2026-10-14T08:20:00.000Z",
|
||||
"externalId": "stats:HKQuantityTypeIdentifierHeartRate:2026-10-14T08:20:00.000Z",
|
||||
"externalSourceVersion": null,
|
||||
"sleepStage": null,
|
||||
"rhythmClassification": null,
|
||||
"deviceType": null,
|
||||
"aggregationProvenance": "HEALTHKIT_STATISTICS",
|
||||
"deletedAt": null
|
||||
},
|
||||
{
|
||||
"id": "<id:9>",
|
||||
"type": "SLEEP_DURATION",
|
||||
"value": 0,
|
||||
"valueMin": null,
|
||||
"valueMax": null,
|
||||
"unit": "minutes",
|
||||
"source": "APPLE_HEALTH",
|
||||
"measuredAt": "2026-10-14T01:00:00.000Z",
|
||||
"externalId": "uuid-sleep-1",
|
||||
"externalSourceVersion": null,
|
||||
"sleepStage": "CORE",
|
||||
"rhythmClassification": null,
|
||||
"deviceType": null,
|
||||
"aggregationProvenance": null,
|
||||
"deletedAt": null
|
||||
},
|
||||
{
|
||||
"id": "<id:10>",
|
||||
"type": "SLEEP_DURATION",
|
||||
"value": 0,
|
||||
"valueMin": null,
|
||||
"valueMax": null,
|
||||
"unit": "minutes",
|
||||
"source": "APPLE_HEALTH",
|
||||
"measuredAt": "2026-10-14T02:30:00.000Z",
|
||||
"externalId": "uuid-sleep-2",
|
||||
"externalSourceVersion": null,
|
||||
"sleepStage": "DEEP",
|
||||
"rhythmClassification": null,
|
||||
"deviceType": null,
|
||||
"aggregationProvenance": null,
|
||||
"deletedAt": null
|
||||
},
|
||||
{
|
||||
"id": "<id:11>",
|
||||
"type": "ACTIVITY_STEPS",
|
||||
"value": 11200,
|
||||
"valueMin": null,
|
||||
"valueMax": null,
|
||||
"unit": "steps",
|
||||
"source": "APPLE_HEALTH",
|
||||
"measuredAt": "2026-09-01T18:00:00.000Z",
|
||||
"externalId": "stats:HKQuantityTypeIdentifierStepCount:2026-09-01",
|
||||
"externalSourceVersion": null,
|
||||
"sleepStage": null,
|
||||
"rhythmClassification": null,
|
||||
"deviceType": null,
|
||||
"aggregationProvenance": "HEALTHKIT_STATISTICS",
|
||||
"deletedAt": null
|
||||
},
|
||||
{
|
||||
"id": "<id:12>",
|
||||
"type": "ACTIVITY_STEPS",
|
||||
"value": 7250,
|
||||
"valueMin": null,
|
||||
"valueMax": null,
|
||||
"unit": "steps",
|
||||
"source": "APPLE_HEALTH",
|
||||
"measuredAt": "2026-10-12T18:00:00.000Z",
|
||||
"externalId": "stats:HKQuantityTypeIdentifierStepCount:2026-10-12",
|
||||
"externalSourceVersion": null,
|
||||
"sleepStage": null,
|
||||
"rhythmClassification": null,
|
||||
"deviceType": null,
|
||||
"aggregationProvenance": "HEALTHKIT_STATISTICS",
|
||||
"deletedAt": null
|
||||
},
|
||||
{
|
||||
"id": "<id:13>",
|
||||
"type": "ACTIVITY_STEPS",
|
||||
"value": 8400,
|
||||
"valueMin": null,
|
||||
"valueMax": null,
|
||||
"unit": "steps",
|
||||
"source": "APPLE_HEALTH",
|
||||
"measuredAt": "2026-10-13T18:00:00.000Z",
|
||||
"externalId": "stats:HKQuantityTypeIdentifierStepCount:2026-10-13",
|
||||
"externalSourceVersion": null,
|
||||
"sleepStage": null,
|
||||
"rhythmClassification": null,
|
||||
"deviceType": "phone",
|
||||
"aggregationProvenance": "HEALTHKIT_STATISTICS",
|
||||
"deletedAt": null
|
||||
},
|
||||
{
|
||||
"id": "<id:14>",
|
||||
"type": "ACTIVITY_STEPS",
|
||||
"value": 6300,
|
||||
"valueMin": null,
|
||||
"valueMax": null,
|
||||
"unit": "steps",
|
||||
"source": "APPLE_HEALTH",
|
||||
"measuredAt": "2026-10-14T18:00:00.000Z",
|
||||
"externalId": "stats:HKQuantityTypeIdentifierStepCount:2026-10-14",
|
||||
"externalSourceVersion": null,
|
||||
"sleepStage": null,
|
||||
"rhythmClassification": null,
|
||||
"deviceType": null,
|
||||
"aggregationProvenance": "HEALTHKIT_STATISTICS",
|
||||
"deletedAt": null
|
||||
},
|
||||
{
|
||||
"id": "<id:15>",
|
||||
"type": "OXYGEN_SATURATION",
|
||||
"value": 97,
|
||||
"valueMin": null,
|
||||
"valueMax": null,
|
||||
"unit": "%",
|
||||
"source": "APPLE_HEALTH",
|
||||
"measuredAt": "2026-10-14T07:10:00.000Z",
|
||||
"externalId": "uuid-spo2-1",
|
||||
"externalSourceVersion": null,
|
||||
"sleepStage": null,
|
||||
"rhythmClassification": null,
|
||||
"deviceType": null,
|
||||
"aggregationProvenance": null,
|
||||
"deletedAt": null
|
||||
}
|
||||
],
|
||||
"hours": [
|
||||
{
|
||||
"id": "<id:16>",
|
||||
"userId": "<id:17>",
|
||||
"type": "ACTIVITY_STEPS",
|
||||
"dateKey": "2026-10-14",
|
||||
"hourlyCumulative": [],
|
||||
"dayTotal": 0,
|
||||
"sampleCount": 0,
|
||||
"hourlyIncrements": [
|
||||
-1,
|
||||
-1,
|
||||
-1,
|
||||
-1,
|
||||
-1,
|
||||
-1,
|
||||
-1,
|
||||
-1,
|
||||
900,
|
||||
1450,
|
||||
-1,
|
||||
-1,
|
||||
-1,
|
||||
-1,
|
||||
-1,
|
||||
-1,
|
||||
-1,
|
||||
-1,
|
||||
-1,
|
||||
-1,
|
||||
-1,
|
||||
-1,
|
||||
-1,
|
||||
-1
|
||||
],
|
||||
"basis": "PER_SAMPLE",
|
||||
"bucketCount": 2,
|
||||
"timezone": "UTC",
|
||||
"createdAt": "<createdAt>",
|
||||
"updatedAt": "<updatedAt>"
|
||||
}
|
||||
],
|
||||
"user": {
|
||||
"lastSyncedAt": "<now>",
|
||||
"healthKitLastSyncedAt": "<now>",
|
||||
"healthKitLastSyncTrigger": null,
|
||||
"healthKitLastBackgroundSyncAt": "<now>"
|
||||
},
|
||||
"typeSync": [
|
||||
{
|
||||
"userId": "<id:17>",
|
||||
"type": "ACTIVITY_STEPS",
|
||||
"lastReceivedAt": "<now>",
|
||||
"lastTrigger": "background",
|
||||
"lastNewSampleAt": "<now>",
|
||||
"lastBackgroundAt": "<now>",
|
||||
"lastSeenDuplicateAt": null
|
||||
},
|
||||
{
|
||||
"userId": "<id:17>",
|
||||
"type": "OXYGEN_SATURATION",
|
||||
"lastReceivedAt": "<now>",
|
||||
"lastTrigger": "foreground",
|
||||
"lastNewSampleAt": "<now>",
|
||||
"lastBackgroundAt": null,
|
||||
"lastSeenDuplicateAt": "<now>"
|
||||
},
|
||||
{
|
||||
"userId": "<id:17>",
|
||||
"type": "PULSE",
|
||||
"lastReceivedAt": "<now>",
|
||||
"lastTrigger": "foreground",
|
||||
"lastNewSampleAt": "<now>",
|
||||
"lastBackgroundAt": null,
|
||||
"lastSeenDuplicateAt": "<now>"
|
||||
},
|
||||
{
|
||||
"userId": "<id:17>",
|
||||
"type": "SLEEP_DURATION",
|
||||
"lastReceivedAt": "<now>",
|
||||
"lastTrigger": "foreground",
|
||||
"lastNewSampleAt": "<now>",
|
||||
"lastBackgroundAt": null,
|
||||
"lastSeenDuplicateAt": "<now>"
|
||||
},
|
||||
{
|
||||
"userId": "<id:17>",
|
||||
"type": "WEIGHT",
|
||||
"lastReceivedAt": "<now>",
|
||||
"lastTrigger": "foreground",
|
||||
"lastNewSampleAt": "<now>",
|
||||
"lastBackgroundAt": null,
|
||||
"lastSeenDuplicateAt": "<now>"
|
||||
},
|
||||
{
|
||||
"userId": "<id:17>",
|
||||
"type": "backfill:ACTIVITY_STEPS",
|
||||
"lastReceivedAt": "<now>",
|
||||
"lastTrigger": null,
|
||||
"lastNewSampleAt": null,
|
||||
"lastBackgroundAt": null,
|
||||
"lastSeenDuplicateAt": null
|
||||
},
|
||||
{
|
||||
"userId": "<id:17>",
|
||||
"type": "backfill:PULSE",
|
||||
"lastReceivedAt": "<now>",
|
||||
"lastTrigger": null,
|
||||
"lastNewSampleAt": null,
|
||||
"lastBackgroundAt": null,
|
||||
"lastSeenDuplicateAt": null
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
+483
@@ -0,0 +1,483 @@
|
||||
{
|
||||
"status": 200,
|
||||
"body": {
|
||||
"data": {
|
||||
"processed": 2,
|
||||
"inserted": 1,
|
||||
"updated": 0,
|
||||
"duplicates": 0,
|
||||
"failed": 0,
|
||||
"skipped": [
|
||||
{
|
||||
"index": 1,
|
||||
"reason": "hour_bucket_unsupported_type"
|
||||
}
|
||||
],
|
||||
"entries": [
|
||||
{
|
||||
"index": 0,
|
||||
"status": "inserted"
|
||||
},
|
||||
{
|
||||
"index": 1,
|
||||
"status": "skipped",
|
||||
"reason": "hour_bucket_unsupported_type"
|
||||
}
|
||||
]
|
||||
},
|
||||
"error": null
|
||||
},
|
||||
"events": [
|
||||
{
|
||||
"status": 200,
|
||||
"action": {
|
||||
"name": "measurement.batch.ingest"
|
||||
},
|
||||
"meta": {
|
||||
"write_bucket": "own",
|
||||
"pr_detection_enqueued": true,
|
||||
"pr_detection_silent": false,
|
||||
"processed": 2,
|
||||
"inserted": 1,
|
||||
"updated": 0,
|
||||
"stats_unchanged": 0,
|
||||
"duplicates": 0,
|
||||
"skipped": 1,
|
||||
"skipped_by_reason": {
|
||||
"hour_bucket_unsupported_type": 1
|
||||
},
|
||||
"failed": 0,
|
||||
"syncTrigger": "foreground",
|
||||
"folded_window": 0,
|
||||
"set_inserted": 1
|
||||
},
|
||||
"warnings": null,
|
||||
"error": null
|
||||
}
|
||||
],
|
||||
"effects": [
|
||||
{
|
||||
"effect": "enqueueReminderSatisfy",
|
||||
"args": [
|
||||
"<id:1>"
|
||||
]
|
||||
},
|
||||
{
|
||||
"effect": "enqueuePrDetection",
|
||||
"args": [
|
||||
"<id:1>",
|
||||
{
|
||||
"silent": false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"effect": "maybeEnqueueMorningRefresh",
|
||||
"args": [
|
||||
"<id:1>",
|
||||
[]
|
||||
]
|
||||
},
|
||||
{
|
||||
"effect": "emitDataArrival",
|
||||
"args": [
|
||||
{
|
||||
"userId": "<id:1>",
|
||||
"kind": "weight",
|
||||
"newestSampleAt": "2026-10-15T07:00:00.000Z",
|
||||
"insertedCount": 1,
|
||||
"source": "batch"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"stored": {
|
||||
"measurements": [
|
||||
{
|
||||
"id": "<id:2>",
|
||||
"type": "WEIGHT",
|
||||
"value": 80.4,
|
||||
"valueMin": null,
|
||||
"valueMax": null,
|
||||
"unit": "kg",
|
||||
"source": "APPLE_HEALTH",
|
||||
"measuredAt": "2026-10-14T06:30:00.000Z",
|
||||
"externalId": "uuid-mass-1",
|
||||
"externalSourceVersion": null,
|
||||
"sleepStage": null,
|
||||
"rhythmClassification": null,
|
||||
"deviceType": "scale",
|
||||
"aggregationProvenance": null,
|
||||
"deletedAt": null
|
||||
},
|
||||
{
|
||||
"id": "<id:3>",
|
||||
"type": "WEIGHT",
|
||||
"value": 80.1,
|
||||
"valueMin": null,
|
||||
"valueMax": null,
|
||||
"unit": "kg",
|
||||
"source": "MANUAL",
|
||||
"measuredAt": "2026-10-15T06:30:00.000Z",
|
||||
"externalId": "manual-1",
|
||||
"externalSourceVersion": null,
|
||||
"sleepStage": null,
|
||||
"rhythmClassification": null,
|
||||
"deviceType": null,
|
||||
"aggregationProvenance": null,
|
||||
"deletedAt": null
|
||||
},
|
||||
{
|
||||
"id": "<id:4>",
|
||||
"type": "WEIGHT",
|
||||
"value": 80,
|
||||
"valueMin": null,
|
||||
"valueMax": null,
|
||||
"unit": "kg",
|
||||
"source": "EXTERNAL",
|
||||
"measuredAt": "2026-10-15T07:00:00.000Z",
|
||||
"externalId": "bridge-1",
|
||||
"externalSourceVersion": null,
|
||||
"sleepStage": null,
|
||||
"rhythmClassification": null,
|
||||
"deviceType": null,
|
||||
"aggregationProvenance": null,
|
||||
"deletedAt": null
|
||||
},
|
||||
{
|
||||
"id": "<id:5>",
|
||||
"type": "PULSE",
|
||||
"value": 58,
|
||||
"valueMin": null,
|
||||
"valueMax": null,
|
||||
"unit": "bpm",
|
||||
"source": "APPLE_HEALTH",
|
||||
"measuredAt": "2026-09-01T07:00:00.000Z",
|
||||
"externalId": "uuid-hr-old-1",
|
||||
"externalSourceVersion": null,
|
||||
"sleepStage": null,
|
||||
"rhythmClassification": null,
|
||||
"deviceType": null,
|
||||
"aggregationProvenance": null,
|
||||
"deletedAt": null
|
||||
},
|
||||
{
|
||||
"id": "<id:6>",
|
||||
"type": "PULSE",
|
||||
"value": 62,
|
||||
"valueMin": null,
|
||||
"valueMax": null,
|
||||
"unit": "bpm",
|
||||
"source": "APPLE_HEALTH",
|
||||
"measuredAt": "2026-10-14T07:00:00.000Z",
|
||||
"externalId": "uuid-hr-1",
|
||||
"externalSourceVersion": null,
|
||||
"sleepStage": null,
|
||||
"rhythmClassification": null,
|
||||
"deviceType": "watch",
|
||||
"aggregationProvenance": null,
|
||||
"deletedAt": null
|
||||
},
|
||||
{
|
||||
"id": "<id:7>",
|
||||
"type": "PULSE",
|
||||
"value": 64,
|
||||
"valueMin": null,
|
||||
"valueMax": null,
|
||||
"unit": "bpm",
|
||||
"source": "APPLE_HEALTH",
|
||||
"measuredAt": "2026-10-14T07:05:00.000Z",
|
||||
"externalId": "uuid-hr-2",
|
||||
"externalSourceVersion": null,
|
||||
"sleepStage": null,
|
||||
"rhythmClassification": null,
|
||||
"deviceType": null,
|
||||
"aggregationProvenance": null,
|
||||
"deletedAt": null
|
||||
},
|
||||
{
|
||||
"id": "<id:8>",
|
||||
"type": "PULSE",
|
||||
"value": 65,
|
||||
"valueMin": null,
|
||||
"valueMax": null,
|
||||
"unit": "bpm",
|
||||
"source": "APPLE_HEALTH",
|
||||
"measuredAt": "2026-10-14T07:25:00.000Z",
|
||||
"externalId": "uuid-hr-twice",
|
||||
"externalSourceVersion": null,
|
||||
"sleepStage": null,
|
||||
"rhythmClassification": null,
|
||||
"deviceType": null,
|
||||
"aggregationProvenance": null,
|
||||
"deletedAt": null
|
||||
},
|
||||
{
|
||||
"id": "<id:9>",
|
||||
"type": "PULSE",
|
||||
"value": 71,
|
||||
"valueMin": 66,
|
||||
"valueMax": 79,
|
||||
"unit": "bpm",
|
||||
"source": "APPLE_HEALTH",
|
||||
"measuredAt": "2026-10-14T08:10:00.000Z",
|
||||
"externalId": "stats:HKQuantityTypeIdentifierHeartRate:2026-10-14T08:10:00.000Z",
|
||||
"externalSourceVersion": null,
|
||||
"sleepStage": null,
|
||||
"rhythmClassification": null,
|
||||
"deviceType": null,
|
||||
"aggregationProvenance": "HEALTHKIT_STATISTICS",
|
||||
"deletedAt": null
|
||||
},
|
||||
{
|
||||
"id": "<id:10>",
|
||||
"type": "PULSE",
|
||||
"value": 70,
|
||||
"valueMin": null,
|
||||
"valueMax": null,
|
||||
"unit": "bpm",
|
||||
"source": "APPLE_HEALTH",
|
||||
"measuredAt": "2026-10-14T08:20:00.000Z",
|
||||
"externalId": "stats:HKQuantityTypeIdentifierHeartRate:2026-10-14T08:20:00.000Z",
|
||||
"externalSourceVersion": null,
|
||||
"sleepStage": null,
|
||||
"rhythmClassification": null,
|
||||
"deviceType": null,
|
||||
"aggregationProvenance": "HEALTHKIT_STATISTICS",
|
||||
"deletedAt": null
|
||||
},
|
||||
{
|
||||
"id": "<id:11>",
|
||||
"type": "SLEEP_DURATION",
|
||||
"value": 0,
|
||||
"valueMin": null,
|
||||
"valueMax": null,
|
||||
"unit": "minutes",
|
||||
"source": "APPLE_HEALTH",
|
||||
"measuredAt": "2026-10-14T01:00:00.000Z",
|
||||
"externalId": "uuid-sleep-1",
|
||||
"externalSourceVersion": null,
|
||||
"sleepStage": "CORE",
|
||||
"rhythmClassification": null,
|
||||
"deviceType": null,
|
||||
"aggregationProvenance": null,
|
||||
"deletedAt": null
|
||||
},
|
||||
{
|
||||
"id": "<id:12>",
|
||||
"type": "SLEEP_DURATION",
|
||||
"value": 0,
|
||||
"valueMin": null,
|
||||
"valueMax": null,
|
||||
"unit": "minutes",
|
||||
"source": "APPLE_HEALTH",
|
||||
"measuredAt": "2026-10-14T02:30:00.000Z",
|
||||
"externalId": "uuid-sleep-2",
|
||||
"externalSourceVersion": null,
|
||||
"sleepStage": "DEEP",
|
||||
"rhythmClassification": null,
|
||||
"deviceType": null,
|
||||
"aggregationProvenance": null,
|
||||
"deletedAt": null
|
||||
},
|
||||
{
|
||||
"id": "<id:13>",
|
||||
"type": "ACTIVITY_STEPS",
|
||||
"value": 11200,
|
||||
"valueMin": null,
|
||||
"valueMax": null,
|
||||
"unit": "steps",
|
||||
"source": "APPLE_HEALTH",
|
||||
"measuredAt": "2026-09-01T18:00:00.000Z",
|
||||
"externalId": "stats:HKQuantityTypeIdentifierStepCount:2026-09-01",
|
||||
"externalSourceVersion": null,
|
||||
"sleepStage": null,
|
||||
"rhythmClassification": null,
|
||||
"deviceType": null,
|
||||
"aggregationProvenance": "HEALTHKIT_STATISTICS",
|
||||
"deletedAt": null
|
||||
},
|
||||
{
|
||||
"id": "<id:14>",
|
||||
"type": "ACTIVITY_STEPS",
|
||||
"value": 7250,
|
||||
"valueMin": null,
|
||||
"valueMax": null,
|
||||
"unit": "steps",
|
||||
"source": "APPLE_HEALTH",
|
||||
"measuredAt": "2026-10-12T18:00:00.000Z",
|
||||
"externalId": "stats:HKQuantityTypeIdentifierStepCount:2026-10-12",
|
||||
"externalSourceVersion": null,
|
||||
"sleepStage": null,
|
||||
"rhythmClassification": null,
|
||||
"deviceType": null,
|
||||
"aggregationProvenance": "HEALTHKIT_STATISTICS",
|
||||
"deletedAt": null
|
||||
},
|
||||
{
|
||||
"id": "<id:15>",
|
||||
"type": "ACTIVITY_STEPS",
|
||||
"value": 8400,
|
||||
"valueMin": null,
|
||||
"valueMax": null,
|
||||
"unit": "steps",
|
||||
"source": "APPLE_HEALTH",
|
||||
"measuredAt": "2026-10-13T18:00:00.000Z",
|
||||
"externalId": "stats:HKQuantityTypeIdentifierStepCount:2026-10-13",
|
||||
"externalSourceVersion": null,
|
||||
"sleepStage": null,
|
||||
"rhythmClassification": null,
|
||||
"deviceType": "phone",
|
||||
"aggregationProvenance": "HEALTHKIT_STATISTICS",
|
||||
"deletedAt": null
|
||||
},
|
||||
{
|
||||
"id": "<id:16>",
|
||||
"type": "ACTIVITY_STEPS",
|
||||
"value": 6300,
|
||||
"valueMin": null,
|
||||
"valueMax": null,
|
||||
"unit": "steps",
|
||||
"source": "APPLE_HEALTH",
|
||||
"measuredAt": "2026-10-14T18:00:00.000Z",
|
||||
"externalId": "stats:HKQuantityTypeIdentifierStepCount:2026-10-14",
|
||||
"externalSourceVersion": null,
|
||||
"sleepStage": null,
|
||||
"rhythmClassification": null,
|
||||
"deviceType": null,
|
||||
"aggregationProvenance": "HEALTHKIT_STATISTICS",
|
||||
"deletedAt": null
|
||||
},
|
||||
{
|
||||
"id": "<id:17>",
|
||||
"type": "OXYGEN_SATURATION",
|
||||
"value": 97,
|
||||
"valueMin": null,
|
||||
"valueMax": null,
|
||||
"unit": "%",
|
||||
"source": "APPLE_HEALTH",
|
||||
"measuredAt": "2026-10-14T07:10:00.000Z",
|
||||
"externalId": "uuid-spo2-1",
|
||||
"externalSourceVersion": null,
|
||||
"sleepStage": null,
|
||||
"rhythmClassification": null,
|
||||
"deviceType": null,
|
||||
"aggregationProvenance": null,
|
||||
"deletedAt": null
|
||||
}
|
||||
],
|
||||
"hours": [
|
||||
{
|
||||
"id": "<id:18>",
|
||||
"userId": "<id:1>",
|
||||
"type": "ACTIVITY_STEPS",
|
||||
"dateKey": "2026-10-14",
|
||||
"hourlyCumulative": [],
|
||||
"dayTotal": 0,
|
||||
"sampleCount": 0,
|
||||
"hourlyIncrements": [
|
||||
-1,
|
||||
-1,
|
||||
-1,
|
||||
-1,
|
||||
-1,
|
||||
-1,
|
||||
-1,
|
||||
-1,
|
||||
900,
|
||||
1450,
|
||||
-1,
|
||||
-1,
|
||||
-1,
|
||||
-1,
|
||||
-1,
|
||||
-1,
|
||||
-1,
|
||||
-1,
|
||||
-1,
|
||||
-1,
|
||||
-1,
|
||||
-1,
|
||||
-1,
|
||||
-1
|
||||
],
|
||||
"basis": "PER_SAMPLE",
|
||||
"bucketCount": 2,
|
||||
"timezone": "UTC",
|
||||
"createdAt": "<createdAt>",
|
||||
"updatedAt": "<updatedAt>"
|
||||
}
|
||||
],
|
||||
"user": {
|
||||
"lastSyncedAt": "<now>",
|
||||
"healthKitLastSyncedAt": "<now>",
|
||||
"healthKitLastSyncTrigger": null,
|
||||
"healthKitLastBackgroundSyncAt": "<now>"
|
||||
},
|
||||
"typeSync": [
|
||||
{
|
||||
"userId": "<id:1>",
|
||||
"type": "ACTIVITY_STEPS",
|
||||
"lastReceivedAt": "<now>",
|
||||
"lastTrigger": "background",
|
||||
"lastNewSampleAt": "<now>",
|
||||
"lastBackgroundAt": "<now>",
|
||||
"lastSeenDuplicateAt": null
|
||||
},
|
||||
{
|
||||
"userId": "<id:1>",
|
||||
"type": "OXYGEN_SATURATION",
|
||||
"lastReceivedAt": "<now>",
|
||||
"lastTrigger": "foreground",
|
||||
"lastNewSampleAt": "<now>",
|
||||
"lastBackgroundAt": null,
|
||||
"lastSeenDuplicateAt": "<now>"
|
||||
},
|
||||
{
|
||||
"userId": "<id:1>",
|
||||
"type": "PULSE",
|
||||
"lastReceivedAt": "<now>",
|
||||
"lastTrigger": "foreground",
|
||||
"lastNewSampleAt": "<now>",
|
||||
"lastBackgroundAt": null,
|
||||
"lastSeenDuplicateAt": "<now>"
|
||||
},
|
||||
{
|
||||
"userId": "<id:1>",
|
||||
"type": "SLEEP_DURATION",
|
||||
"lastReceivedAt": "<now>",
|
||||
"lastTrigger": "foreground",
|
||||
"lastNewSampleAt": "<now>",
|
||||
"lastBackgroundAt": null,
|
||||
"lastSeenDuplicateAt": "<now>"
|
||||
},
|
||||
{
|
||||
"userId": "<id:1>",
|
||||
"type": "WEIGHT",
|
||||
"lastReceivedAt": "<now>",
|
||||
"lastTrigger": "foreground",
|
||||
"lastNewSampleAt": "<now>",
|
||||
"lastBackgroundAt": null,
|
||||
"lastSeenDuplicateAt": "<now>"
|
||||
},
|
||||
{
|
||||
"userId": "<id:1>",
|
||||
"type": "backfill:ACTIVITY_STEPS",
|
||||
"lastReceivedAt": "<now>",
|
||||
"lastTrigger": null,
|
||||
"lastNewSampleAt": null,
|
||||
"lastBackgroundAt": null,
|
||||
"lastSeenDuplicateAt": null
|
||||
},
|
||||
{
|
||||
"userId": "<id:1>",
|
||||
"type": "backfill:PULSE",
|
||||
"lastReceivedAt": "<now>",
|
||||
"lastTrigger": null,
|
||||
"lastNewSampleAt": null,
|
||||
"lastBackgroundAt": null,
|
||||
"lastSeenDuplicateAt": null
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,437 @@
|
||||
/**
|
||||
* Parity for `POST /api/measurements/batch` while its ingest moves into
|
||||
* `src/lib/measurements/batch-ingest/`.
|
||||
*
|
||||
* One account walks through the cases the route tells apart, in order, each
|
||||
* request seeing what the earlier ones stored: a first sync of mixed
|
||||
* entries (fresh samples, a day total, a heart-rate bucket with its spread,
|
||||
* sleep stages, hourly sums, and every per-entry refusal), the same sync
|
||||
* again, a re-computed day total from the background, a hand-entered
|
||||
* reading the phone also mirrored, a history catch-up, the two whole-batch
|
||||
* refusals, and a narrow bridge token with and without a `source`. After
|
||||
* each request the snapshot holds the response, the request's wide event,
|
||||
* the stored measurements and hourly profile, and the account's sync stamps.
|
||||
*
|
||||
* The clock is pinned (`Date` only), so the snapshot is the same on every
|
||||
* day it runs.
|
||||
*/
|
||||
import { afterAll, beforeAll, describe, expect, it, vi } from "vitest";
|
||||
|
||||
import { POST } from "@/app/api/measurements/batch/route";
|
||||
import { MEASUREMENTS_WRITE_SCOPE } from "@/lib/measurements/scopes";
|
||||
|
||||
import { callRoute, type RouteAuth } from "../../../kit/call-route";
|
||||
import { makeSession, makeToken, makeUser } from "../../../kit/factories";
|
||||
import {
|
||||
effectRecorder,
|
||||
eventFacts,
|
||||
expectParity,
|
||||
stable,
|
||||
wideEventRecorder,
|
||||
} from "../../../kit/parity";
|
||||
import { getPrismaClient, truncateAllTables } from "../../setup";
|
||||
|
||||
vi.mock("@/lib/logging/transports", async (importOriginal) => {
|
||||
const actual =
|
||||
await importOriginal<typeof import("@/lib/logging/transports")>();
|
||||
const { wideEventRecorder: recorder } = await import("../../../kit/parity");
|
||||
return {
|
||||
...actual,
|
||||
emitIfSampled: (event: (typeof recorder.events)[number]) => {
|
||||
recorder.events.push(event);
|
||||
},
|
||||
};
|
||||
});
|
||||
|
||||
// The queue and arrival tails the route hands work to, recorded instead of
|
||||
// run (see `effectRecorder`).
|
||||
vi.mock("@/lib/arrivals/emit-shared", async (importOriginal) => {
|
||||
const actual =
|
||||
await importOriginal<typeof import("@/lib/arrivals/emit-shared")>();
|
||||
const { effectRecorder } = await import("../../../kit/parity");
|
||||
return {
|
||||
...actual,
|
||||
emitDataArrival: async (...args: unknown[]) => {
|
||||
effectRecorder.record("emitDataArrival", args);
|
||||
},
|
||||
};
|
||||
});
|
||||
vi.mock("@/lib/daily/morning-refresh-trigger", async (importOriginal) => {
|
||||
const actual =
|
||||
await importOriginal<
|
||||
typeof import("@/lib/daily/morning-refresh-trigger")
|
||||
>();
|
||||
const { effectRecorder } = await import("../../../kit/parity");
|
||||
return {
|
||||
...actual,
|
||||
maybeEnqueueMorningRefresh: async (...args: unknown[]) => {
|
||||
effectRecorder.record("maybeEnqueueMorningRefresh", args);
|
||||
},
|
||||
};
|
||||
});
|
||||
vi.mock("@/lib/jobs/reminder-satisfy", async (importOriginal) => {
|
||||
const actual =
|
||||
await importOriginal<typeof import("@/lib/jobs/reminder-satisfy")>();
|
||||
const { effectRecorder } = await import("../../../kit/parity");
|
||||
return {
|
||||
...actual,
|
||||
enqueueReminderSatisfy: async (...args: unknown[]) => {
|
||||
effectRecorder.record("enqueueReminderSatisfy", args);
|
||||
},
|
||||
};
|
||||
});
|
||||
vi.mock("@/lib/jobs/pr-detection", async (importOriginal) => {
|
||||
const actual =
|
||||
await importOriginal<typeof import("@/lib/jobs/pr-detection")>();
|
||||
const { effectRecorder } = await import("../../../kit/parity");
|
||||
return {
|
||||
...actual,
|
||||
enqueuePrDetection: async (...args: unknown[]) => {
|
||||
effectRecorder.record("enqueuePrDetection", args);
|
||||
},
|
||||
};
|
||||
});
|
||||
|
||||
const prisma = getPrismaClient();
|
||||
const NOW = new Date("2026-10-15T12:00:00.000Z");
|
||||
const HR = "HKQuantityTypeIdentifierHeartRate";
|
||||
const STEPS = "HKQuantityTypeIdentifierStepCount";
|
||||
const MASS = "HKQuantityTypeIdentifierBodyMass";
|
||||
const SPO2 = "HKQuantityTypeIdentifierOxygenSaturation";
|
||||
const SLEEP = "HKCategoryTypeIdentifierSleepAnalysis";
|
||||
|
||||
type Entry = Record<string, unknown>;
|
||||
|
||||
function sample(
|
||||
hkIdentifier: string,
|
||||
externalId: string,
|
||||
at: string,
|
||||
value: number,
|
||||
unit: string,
|
||||
extra: Entry = {},
|
||||
): Entry {
|
||||
return {
|
||||
hkIdentifier,
|
||||
value,
|
||||
unit,
|
||||
startDate: at,
|
||||
endDate: at,
|
||||
externalId,
|
||||
...extra,
|
||||
};
|
||||
}
|
||||
|
||||
function dayTotal(day: string, value: number, extra: Entry = {}): Entry {
|
||||
return {
|
||||
hkIdentifier: STEPS,
|
||||
value,
|
||||
unit: "count",
|
||||
startDate: `${day}T00:00:00.000Z`,
|
||||
endDate: `${day}T18:00:00.000Z`,
|
||||
externalId: `stats:${STEPS}:${day}`,
|
||||
...extra,
|
||||
};
|
||||
}
|
||||
|
||||
function hourSum(day: string, hour: number, value: number): Entry {
|
||||
const hh = String(hour).padStart(2, "0");
|
||||
const start = `${day}T${hh}:00:00.000Z`;
|
||||
return {
|
||||
hkIdentifier: STEPS,
|
||||
value,
|
||||
unit: "count",
|
||||
startDate: start,
|
||||
endDate: new Date(Date.parse(start) + 3_600_000).toISOString(),
|
||||
externalId: `stats:${STEPS}:${day}T${hh}`,
|
||||
};
|
||||
}
|
||||
|
||||
function sleep(externalId: string, from: string, to: string, stage: number) {
|
||||
return {
|
||||
hkIdentifier: SLEEP,
|
||||
value: 0,
|
||||
unit: "min",
|
||||
startDate: from,
|
||||
endDate: to,
|
||||
externalId,
|
||||
sleepStage: stage,
|
||||
};
|
||||
}
|
||||
|
||||
const FIRST_SYNC: Entry[] = [
|
||||
sample(MASS, "uuid-mass-1", "2026-10-14T06:30:00.000Z", 80.4, "kg", {
|
||||
deviceType: "scale",
|
||||
}),
|
||||
sample(HR, "uuid-hr-1", "2026-10-14T07:00:00.000Z", 62, "count/min", {
|
||||
deviceType: "watch",
|
||||
}),
|
||||
sample(HR, "uuid-hr-2", "2026-10-14T07:05:00.000Z", 64, "count/min"),
|
||||
sample(SPO2, "uuid-spo2-1", "2026-10-14T07:10:00.000Z", 0.97, "%"),
|
||||
dayTotal("2026-10-13", 8_400, { deviceType: "phone" }),
|
||||
dayTotal("2026-10-14", 5_100),
|
||||
sample(
|
||||
HR,
|
||||
`stats:${HR}:2026-10-14T08:10:00.000Z`,
|
||||
"2026-10-14T08:10:00.000Z",
|
||||
71,
|
||||
"count/min",
|
||||
{ valueMin: 66, valueMax: 79 },
|
||||
),
|
||||
// A spread that does not bracket the mean is dropped, the mean kept.
|
||||
sample(
|
||||
HR,
|
||||
`stats:${HR}:2026-10-14T08:20:00.000Z`,
|
||||
"2026-10-14T08:20:00.000Z",
|
||||
70,
|
||||
"count/min",
|
||||
{ valueMin: 72, valueMax: 75 },
|
||||
),
|
||||
sleep(
|
||||
"uuid-sleep-1",
|
||||
"2026-10-13T22:00:00.000Z",
|
||||
"2026-10-14T01:00:00.000Z",
|
||||
3,
|
||||
),
|
||||
sleep(
|
||||
"uuid-sleep-2",
|
||||
"2026-10-14T01:00:00.000Z",
|
||||
"2026-10-14T02:30:00.000Z",
|
||||
4,
|
||||
),
|
||||
hourSum("2026-10-14", 8, 900),
|
||||
hourSum("2026-10-14", 9, 1_300),
|
||||
// Refused per entry.
|
||||
sample(
|
||||
"HKQuantityTypeIdentifierNotAThing",
|
||||
"uuid-x-1",
|
||||
"2026-10-14T07:00:00.000Z",
|
||||
1,
|
||||
"count",
|
||||
),
|
||||
sample(HR, "uuid-hr-range", "2026-10-14T07:15:00.000Z", 900, "count/min"),
|
||||
sample(HR, "uuid-hr-future", "2027-03-01T07:15:00.000Z", 61, "count/min"),
|
||||
sample(
|
||||
HR,
|
||||
`stats:${HR}:2026-10-14T08:13:00.000Z`,
|
||||
"2026-10-14T08:13:00.000Z",
|
||||
70,
|
||||
"count/min",
|
||||
),
|
||||
sample(
|
||||
HR,
|
||||
"<HKQuantitySample: 0x600003a1c0c0>",
|
||||
"2026-10-14T07:20:00.000Z",
|
||||
63,
|
||||
"count/min",
|
||||
),
|
||||
// The same sample twice in one batch, and a day total sent twice.
|
||||
sample(HR, "uuid-hr-twice", "2026-10-14T07:25:00.000Z", 65, "count/min"),
|
||||
sample(HR, "uuid-hr-twice", "2026-10-14T07:25:00.000Z", 65, "count/min"),
|
||||
dayTotal("2026-10-12", 7_000),
|
||||
dayTotal("2026-10-12", 7_250),
|
||||
];
|
||||
|
||||
const MEASUREMENT_SELECT = {
|
||||
id: true,
|
||||
type: true,
|
||||
value: true,
|
||||
valueMin: true,
|
||||
valueMax: true,
|
||||
unit: true,
|
||||
source: true,
|
||||
measuredAt: true,
|
||||
externalId: true,
|
||||
externalSourceVersion: true,
|
||||
sleepStage: true,
|
||||
rhythmClassification: true,
|
||||
deviceType: true,
|
||||
aggregationProvenance: true,
|
||||
deletedAt: true,
|
||||
} as const;
|
||||
|
||||
let userId: string;
|
||||
let session: RouteAuth;
|
||||
|
||||
async function state() {
|
||||
const [measurements, hours, user, typeSync] = await Promise.all([
|
||||
prisma.measurement.findMany({
|
||||
where: { userId },
|
||||
select: MEASUREMENT_SELECT,
|
||||
orderBy: [
|
||||
{ type: "asc" },
|
||||
{ measuredAt: "asc" },
|
||||
{ source: "asc" },
|
||||
{ externalId: "asc" },
|
||||
],
|
||||
}),
|
||||
prisma.intradayCumulativeProfile.findMany({
|
||||
where: { userId },
|
||||
orderBy: [{ type: "asc" }, { dateKey: "asc" }],
|
||||
}),
|
||||
prisma.user.findUniqueOrThrow({
|
||||
where: { id: userId },
|
||||
select: {
|
||||
lastSyncedAt: true,
|
||||
healthKitLastSyncedAt: true,
|
||||
healthKitLastSyncTrigger: true,
|
||||
healthKitLastBackgroundSyncAt: true,
|
||||
},
|
||||
}),
|
||||
prisma.healthKitTypeSync.findMany({
|
||||
where: { userId },
|
||||
orderBy: { type: "asc" },
|
||||
}),
|
||||
]);
|
||||
return { measurements, hours, user, typeSync };
|
||||
}
|
||||
|
||||
async function step(
|
||||
name: string,
|
||||
body: unknown,
|
||||
auth: RouteAuth = session,
|
||||
): Promise<void> {
|
||||
wideEventRecorder.take();
|
||||
effectRecorder.take();
|
||||
const res = await callRoute(POST, {
|
||||
method: "POST",
|
||||
route: "/api/measurements/batch",
|
||||
body,
|
||||
auth,
|
||||
});
|
||||
const events = wideEventRecorder.take();
|
||||
expect(events.length).toBeGreaterThan(0);
|
||||
await expectParity(
|
||||
`measurements-batch.${name}`,
|
||||
stable(
|
||||
{
|
||||
status: res.status,
|
||||
body: res.body,
|
||||
events: events.map(eventFacts),
|
||||
effects: effectRecorder.take(),
|
||||
stored: await state(),
|
||||
},
|
||||
{ since: NOW },
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
beforeAll(async () => {
|
||||
vi.useFakeTimers({ toFake: ["Date"], now: NOW });
|
||||
await truncateAllTables(prisma);
|
||||
const user = await makeUser({ timezone: "UTC" });
|
||||
userId = user.id;
|
||||
session = await makeSession(user);
|
||||
});
|
||||
|
||||
afterAll(() => {
|
||||
vi.useRealTimers();
|
||||
});
|
||||
|
||||
describe("POST /api/measurements/batch parity", () => {
|
||||
it("01 a first sync of mixed entries", async () => {
|
||||
await step("01-first-sync", {
|
||||
entries: FIRST_SYNC,
|
||||
syncTrigger: "foreground",
|
||||
});
|
||||
});
|
||||
|
||||
it("02 the same sync again", async () => {
|
||||
await step("02-same-sync-again", {
|
||||
entries: FIRST_SYNC,
|
||||
syncTrigger: "foreground",
|
||||
});
|
||||
});
|
||||
|
||||
it("03 a re-computed day total from the background", async () => {
|
||||
await step("03-background-day-total", {
|
||||
entries: [
|
||||
dayTotal("2026-10-14", 6_300),
|
||||
dayTotal("2026-10-13", 8_400, { deviceType: "phone" }),
|
||||
hourSum("2026-10-14", 9, 1_450),
|
||||
],
|
||||
syncTrigger: "background",
|
||||
});
|
||||
});
|
||||
|
||||
it("04 a hand-entered reading the phone also mirrored", async () => {
|
||||
await step("04-cross-source-merge", {
|
||||
entries: [
|
||||
sample(MASS, "manual-1", "2026-10-15T06:30:00.000Z", 80.1, "kg", {
|
||||
source: "MANUAL",
|
||||
}),
|
||||
sample(
|
||||
MASS,
|
||||
"uuid-mass-mirror",
|
||||
"2026-10-15T06:30:01.000Z",
|
||||
80.1,
|
||||
"kg",
|
||||
),
|
||||
],
|
||||
});
|
||||
});
|
||||
|
||||
it("05 a history catch-up", async () => {
|
||||
await step("05-backfill", {
|
||||
entries: [
|
||||
sample(
|
||||
HR,
|
||||
"uuid-hr-old-1",
|
||||
"2026-09-01T07:00:00.000Z",
|
||||
58,
|
||||
"count/min",
|
||||
),
|
||||
dayTotal("2026-09-01", 11_200),
|
||||
],
|
||||
syncTrigger: "backfill",
|
||||
});
|
||||
});
|
||||
|
||||
it("06 a batch over the entry limit", async () => {
|
||||
await step("06-too-large", {
|
||||
entries: Array.from({ length: 501 }, (_, i) =>
|
||||
sample(
|
||||
HR,
|
||||
`uuid-bulk-${i}`,
|
||||
"2026-10-14T10:00:00.000Z",
|
||||
60,
|
||||
"count/min",
|
||||
),
|
||||
),
|
||||
});
|
||||
});
|
||||
|
||||
it("07 a batch the schema refuses", async () => {
|
||||
await step("07-invalid", {
|
||||
entries: [{ hkIdentifier: HR, value: "fast", unit: "count/min" }],
|
||||
});
|
||||
});
|
||||
|
||||
it("08 a bridge token naming a source, and one that does not", async () => {
|
||||
const bridge = await makeToken(
|
||||
{ id: userId },
|
||||
{ permissions: [MEASUREMENTS_WRITE_SCOPE] },
|
||||
);
|
||||
await step(
|
||||
"08a-bridge-with-source",
|
||||
{
|
||||
entries: [
|
||||
sample(MASS, "bridge-1", "2026-10-15T07:00:00.000Z", 80.0, "kg", {
|
||||
source: "APPLE_HEALTH",
|
||||
}),
|
||||
],
|
||||
},
|
||||
bridge,
|
||||
);
|
||||
await step(
|
||||
"08b-bridge",
|
||||
{
|
||||
entries: [
|
||||
sample(MASS, "bridge-1", "2026-10-15T07:00:00.000Z", 80.0, "kg"),
|
||||
hourSum("2026-10-15", 6, 400),
|
||||
],
|
||||
syncTrigger: "foreground",
|
||||
},
|
||||
bridge,
|
||||
);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,160 @@
|
||||
/**
|
||||
* Response parity for a route whose code moves: record what the route
|
||||
* answers, stores and reports before the move, and compare after it.
|
||||
*
|
||||
* A parity test drives a route through `callRoute` across the cases it
|
||||
* distinguishes, and pins three things per case in a committed snapshot
|
||||
* under `tests/integration/routes/parity/__snapshots__/`:
|
||||
*
|
||||
* - the response (status, envelope);
|
||||
* - what the request left in the database, read back by the test;
|
||||
* - the wide event the request emitted: its action and meta, which is what
|
||||
* the operator dashboards read.
|
||||
*
|
||||
* The snapshot is written on the code before the move, committed on its own,
|
||||
* and must come out byte-identical after it. Values that differ between two
|
||||
* runs of the same code (generated ids, server timestamps, request ids,
|
||||
* durations) are replaced by stable placeholders first, so the comparison
|
||||
* sees only what the code decides. Ids are numbered by first appearance,
|
||||
* so two references to the same row still read as the same placeholder.
|
||||
*/
|
||||
import { expect } from "vitest";
|
||||
|
||||
import type { WideEvent } from "@/lib/logging/types";
|
||||
|
||||
/** Generated identifiers: Prisma `cuid()` values and UUIDs. */
|
||||
const GENERATED_ID =
|
||||
/^(c[a-z0-9]{24}|[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})$/;
|
||||
const ISO_INSTANT = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(\.\d{1,6})?Z$/;
|
||||
|
||||
/**
|
||||
* Keys whose values the clock or a random source decides on every run. Their
|
||||
* presence is kept, their value is not.
|
||||
*/
|
||||
const VOLATILE_KEYS = new Set([
|
||||
"requestId",
|
||||
"request_id",
|
||||
"createdAt",
|
||||
"updatedAt",
|
||||
"syncVersion",
|
||||
"duration_ms",
|
||||
"durationMs",
|
||||
"timestamp",
|
||||
"lastUsedAt",
|
||||
]);
|
||||
|
||||
export interface StableOptions {
|
||||
/**
|
||||
* Instants inside `[since, until]` are server clock readings (a row's
|
||||
* `createdAt`, a stamp the route wrote) and read as `<now>`. Instants the
|
||||
* test sent, which lie outside that window, are kept as they are.
|
||||
*/
|
||||
since: Date;
|
||||
until?: Date;
|
||||
/** Further keys to blank, for a route with a volatile field of its own. */
|
||||
volatileKeys?: readonly string[];
|
||||
}
|
||||
|
||||
/** A copy of `value` with the run-dependent parts replaced. */
|
||||
export function stable(value: unknown, options: StableOptions): unknown {
|
||||
const ids = new Map<string, string>();
|
||||
const until = (options.until ?? new Date(Date.now() + 60_000)).getTime();
|
||||
const since = options.since.getTime();
|
||||
const volatile = new Set([...VOLATILE_KEYS, ...(options.volatileKeys ?? [])]);
|
||||
|
||||
const walk = (node: unknown, key: string | null): unknown => {
|
||||
if (
|
||||
key !== null &&
|
||||
volatile.has(key) &&
|
||||
node !== null &&
|
||||
node !== undefined
|
||||
) {
|
||||
return `<${key}>`;
|
||||
}
|
||||
if (node instanceof Date) node = node.toISOString();
|
||||
if (typeof node === "string") {
|
||||
if (GENERATED_ID.test(node)) {
|
||||
let label = ids.get(node);
|
||||
if (!label) {
|
||||
label = `<id:${ids.size + 1}>`;
|
||||
ids.set(node, label);
|
||||
}
|
||||
return label;
|
||||
}
|
||||
if (ISO_INSTANT.test(node)) {
|
||||
const t = Date.parse(node);
|
||||
if (t >= since && t <= until) return "<now>";
|
||||
}
|
||||
return node;
|
||||
}
|
||||
if (typeof node === "bigint") return `${node}n`;
|
||||
if (Array.isArray(node)) return node.map((item) => walk(item, null));
|
||||
if (node && typeof node === "object") {
|
||||
const out: Record<string, unknown> = {};
|
||||
for (const [k, v] of Object.entries(node)) out[k] = walk(v, k);
|
||||
return out;
|
||||
}
|
||||
return node;
|
||||
};
|
||||
return walk(value, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* The wide events requests emitted, collected in order. Install with
|
||||
* `vi.mock("@/lib/logging/transports", wideEventRecorder.mockFactory)` in
|
||||
* the test file, then read `wideEventRecorder.take()` after each call.
|
||||
*/
|
||||
export const wideEventRecorder = {
|
||||
events: [] as WideEvent[],
|
||||
/** The events since the last call, emptied. */
|
||||
take(): WideEvent[] {
|
||||
return this.events.splice(0, this.events.length);
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* Calls the route handed to a queue or another fire-and-forget tail (a job
|
||||
* enqueue, a data-arrival emit), recorded in order with their arguments. A
|
||||
* parity test replaces those collaborators with recorders: the snapshot then
|
||||
* shows what the route asked for, and the request's wide event no longer
|
||||
* depends on whether a tail it did not await happened to finish first.
|
||||
*/
|
||||
export const effectRecorder = {
|
||||
calls: [] as Array<{ effect: string; args: unknown[] }>,
|
||||
record(effect: string, args: unknown[]): void {
|
||||
this.calls.push({ effect, args });
|
||||
},
|
||||
/** The calls since the last take, emptied. */
|
||||
take(): Array<{ effect: string; args: unknown[] }> {
|
||||
return this.calls.splice(0, this.calls.length);
|
||||
},
|
||||
};
|
||||
|
||||
/** What of a wide event a parity snapshot keeps: what the code decided. */
|
||||
export function eventFacts(event: WideEvent): unknown {
|
||||
return {
|
||||
status: event.http?.status ?? null,
|
||||
action: event.action ?? null,
|
||||
meta: event.meta ?? null,
|
||||
warnings: event.warnings ?? null,
|
||||
error: event.error
|
||||
? { type: event.error.type, message: event.error.message }
|
||||
: null,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Compare `value` with the committed snapshot `name`, a file under
|
||||
* `__snapshots__/` beside the calling test (parity tests live in
|
||||
* `tests/integration/routes/parity/`). A missing snapshot is written outside
|
||||
* CI (the recording run); in CI a missing one fails, and a present one must
|
||||
* match everywhere.
|
||||
*/
|
||||
export async function expectParity(
|
||||
name: string,
|
||||
value: unknown,
|
||||
): Promise<void> {
|
||||
await expect(`${JSON.stringify(value, null, 2)}\n`).toMatchFileSnapshot(
|
||||
`./__snapshots__/${name}.json.snap`,
|
||||
);
|
||||
}
|
||||
Reference in new issue
Block a user