mirror of
https://github.com/MBombeck/HealthLog.git
synced 2026-11-09 21:10:59 +00:00
feat(apple-health): show when each type last arrived and how
The Apple Health card listed each type's newest sample. A type the phone only hands over on "Sync all" can carry a reading from this morning and never have arrived in the background, so the sample time could not answer whether a type flows on its own. The batch route's per-type ledger now records, in one upsert per batch, when each Apple Health type last arrived, the trigger that carried it (including the new `manual`), and when a batch last brought a new or updated sample of it. Duplicate-only re-sends move the arrival but keep the last new value; scoped credentials and MANUAL rows write nothing, the same rule as the sync checkpoint. A ledger failure leaves a warn line and never fails the ingest. `GET /api/integrations/healthkit` lays `lastReceivedAt`, `lastTrigger` and `lastNewSampleAt` over each `metricFreshness` entry (null for a type no live sync has carried, absent on the workouts entry and when the ledger read failed), and the card shows them as a second line per type. The per-type newest-sample read walks live types through `listLiveMeasurementTypes` and probes each type's newest row instead of grouping every live row of the source.
This commit is contained in:
1 parent
c8470cc1e6
commit
ba99551faa
15 files changed
+976
-114
No files matched your search
+62
-7
@@ -24873,7 +24873,9 @@ components:
|
||||
description: 'Diagnostic-only. Names what triggered this sync (foreground app open, background refresh, a push wake, or
|
||||
a user-initiated `manual` "Sync all" run, since v1.42). Recorded on the ingest wide event and kept on the
|
||||
account as `lastSyncTrigger` — plus `lastBackgroundSyncAt` for a `background` or `push` trigger — both
|
||||
readable from `GET /api/integrations/healthkit`. It does not affect dedup, attribution, or how any sample is
|
||||
readable from `GET /api/integrations/healthkit`. Since v1.42 it is also recorded per measurement type the
|
||||
batch carried (Apple Health rows only), served as `lastReceivedAt` / `lastTrigger` / `lastNewSampleAt` on
|
||||
each `metricFreshness` entry of that read. It does not affect dedup, attribution, or how any sample is
|
||||
stored. Optional and backward-compatible: pre-#66 clients omit it.'
|
||||
type: string
|
||||
enum:
|
||||
@@ -72802,11 +72804,11 @@ components:
|
||||
description: Present on the GET read; omitted from the PATCH echo.
|
||||
$ref: "#/components/schemas/SyncHealth"
|
||||
metricFreshness:
|
||||
description: Per-metric-type freshness for the `APPLE_HEALTH` source. Present on the GET read; omitted from the PATCH
|
||||
echo.
|
||||
description: Per-metric-type freshness for the `APPLE_HEALTH` source, with the per-type arrival facts. Present on the
|
||||
GET read; omitted from the PATCH echo.
|
||||
type: array
|
||||
items:
|
||||
$ref: "#/components/schemas/MetricFreshnessEntry"
|
||||
$ref: "#/components/schemas/AppleHealthMetricFreshnessEntry"
|
||||
syncProgress:
|
||||
description: Backfill/sync progress summary. Present on the GET read (null when the progress read failed); omitted from
|
||||
the PATCH echo.
|
||||
@@ -72874,7 +72876,7 @@ components:
|
||||
additionalProperties: false
|
||||
description: Server-resolved sync-health verdict. The single source of liveness truth — `lastSyncedAt` alone cannot
|
||||
express 'this pipe stopped delivering'.
|
||||
MetricFreshnessEntry:
|
||||
AppleHealthMetricFreshnessEntry:
|
||||
type: object
|
||||
properties:
|
||||
type:
|
||||
@@ -72889,13 +72891,44 @@ components:
|
||||
type: boolean
|
||||
description: This type has gone quiet while the source around it reads healthy — the dead-pipe signature (e.g. a single
|
||||
revoked HealthKit permission). Only ever true when the verdict is `fresh`.
|
||||
lastReceivedAt:
|
||||
description: "When a live sync batch last carried this type (inserted, updated or duplicate entries all count). Null
|
||||
when no live sync has carried it yet: a type that so far came only from the export import, or from before
|
||||
v1.42. `lastSeenAt` is when the newest sample was TAKEN; this is when the server last RECEIVED the type.
|
||||
Omitted on the `WORKOUTS` entry, which the ledger does not cover, and on every entry when the ledger read
|
||||
failed."
|
||||
anyOf:
|
||||
- type: string
|
||||
format: date-time
|
||||
pattern: ^(?:(?:\d\d[2468][048]|\d\d[13579][26]|\d\d0[48]|[02468][048]00|[13579][26]00)-02-29|\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\d|30)|(?:02)-(?:0[1-9]|1\d|2[0-8])))T(?:(?:[01]\d|2[0-3]):[0-5]\d(?::[0-5]\d(?:\.\d+)?)?(?:Z|([+-](?:[01]\d|2[0-3]):[0-5]\d)))$
|
||||
- type: "null"
|
||||
lastTrigger:
|
||||
description: The `syncTrigger` of that batch. Null when the client reported none. A type whose trigger is only ever
|
||||
`manual` reaches the server only through a user-started full sync. Same omission rules as `lastReceivedAt`.
|
||||
anyOf:
|
||||
- type: string
|
||||
enum:
|
||||
- foreground
|
||||
- background
|
||||
- push
|
||||
- manual
|
||||
description: What triggered a HealthKit batch.
|
||||
- type: "null"
|
||||
lastNewSampleAt:
|
||||
description: When a live sync batch last brought a new or updated sample of this type, as opposed to duplicates only.
|
||||
Null when none has. Same omission rules as `lastReceivedAt`.
|
||||
anyOf:
|
||||
- type: string
|
||||
format: date-time
|
||||
pattern: ^(?:(?:\d\d[2468][048]|\d\d[13579][26]|\d\d0[48]|[02468][048]00|[13579][26]00)-02-29|\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\d|30)|(?:02)-(?:0[1-9]|1\d|2[0-8])))T(?:(?:[01]\d|2[0-3]):[0-5]\d(?::[0-5]\d(?:\.\d+)?)?(?:Z|([+-](?:[01]\d|2[0-3]):[0-5]\d)))$
|
||||
- type: "null"
|
||||
required:
|
||||
- type
|
||||
- lastSeenAt
|
||||
- stale
|
||||
additionalProperties: false
|
||||
description: Per-metric-type last-seen timestamp with the server-computed staleness flag. Only types that have actually
|
||||
delivered appear — absence is absence, never an invented row.
|
||||
description: "Per-type Apple Health freshness: the newest sample's timestamp and staleness flag, plus the per-type
|
||||
arrival facts recorded by `POST /api/measurements/batch` (v1.42)."
|
||||
AppleHealthSyncProgress:
|
||||
type: object
|
||||
properties:
|
||||
@@ -74763,6 +74796,28 @@ components:
|
||||
entry carries, plus the extras that provider has. The optional fields are not optional per request — each is
|
||||
present exactly for the providers named in its description and absent for the rest, so branch on `integration`,
|
||||
not on presence."
|
||||
MetricFreshnessEntry:
|
||||
type: object
|
||||
properties:
|
||||
type:
|
||||
type: string
|
||||
description: The measurement type (e.g. `RESPIRATORY_RATE`), or `WORKOUTS` for the workout leg.
|
||||
lastSeenAt:
|
||||
type: string
|
||||
format: date-time
|
||||
pattern: ^(?:(?:\d\d[2468][048]|\d\d[13579][26]|\d\d0[48]|[02468][048]00|[13579][26]00)-02-29|\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\d|30)|(?:02)-(?:0[1-9]|1\d|2[0-8])))T(?:(?:[01]\d|2[0-3]):[0-5]\d(?::[0-5]\d(?:\.\d+)?)?(?:Z|([+-](?:[01]\d|2[0-3]):[0-5]\d)))$
|
||||
description: Newest recorded reading for this type from this source.
|
||||
stale:
|
||||
type: boolean
|
||||
description: This type has gone quiet while the source around it reads healthy — the dead-pipe signature (e.g. a single
|
||||
revoked HealthKit permission). Only ever true when the verdict is `fresh`.
|
||||
required:
|
||||
- type
|
||||
- lastSeenAt
|
||||
- stale
|
||||
additionalProperties: false
|
||||
description: Per-metric-type last-seen timestamp with the server-computed staleness flag. Only types that have actually
|
||||
delivered appear — absence is absence, never an invented row.
|
||||
FitbitResumeEnvelope:
|
||||
type: object
|
||||
properties:
|
||||
|
||||
Reference in new issue
Block a user