mirror of
https://github.com/MBombeck/HealthLog.git
synced 2026-11-09 21:10:59 +00:00
feat(api): carry the score's basis on every surface that carries the score
`scoreBasis` rides the composite, the dashboard snapshot's flattened hero block and the daily digest's score. It says how many distinct areas of health the number counted, how many the method recommends, which tier that lands in, and whether any counted pillar was a physiological measurement. Optional everywhere, because two of the three surfaces are served out of a cache and a payload written before this release cannot grow a field. The snapshot and digest blocks have taken six additive fields this way already; this is the seventh. Resolved on the server for the same reason `configured` is. Counting `composition` client-side would get it wrong more often than right — three of the seven pillars share the cardiometabolic area, so a three-pillar score can rest on one. One shared component, `HealthScoreBasis`, declared once in the insights schema module and referenced from the other two registry modules, rather than three inline copies that drift the first time the block gains a field. Declared through the assigning `.meta()` form: a bare `.meta()` statement registers an instance nothing references, and the id then never becomes a component. The composite's `insufficient` reason narrows to the single value `no_usable_data` and says so in the published description. That field is an open string in the document, so the change is additive on the wire even though the value space shrank. The score-config 422 description drops the two retired reasons and states plainly that the empty selection is now the only refusal, so a client does not keep a three-area rule of its own in front of a write that no longer has one.
This commit is contained in:
1 parent
4ad00406d3
commit
aadc3a8e89
8 files changed
+163
-11
No files matched your search
+62
-7
@@ -6454,11 +6454,13 @@ paths:
|
||||
"422":
|
||||
description: "The write was refused and nothing was stored. `meta.errorCode` distinguishes the cases:
|
||||
`health_score_config.too_narrow` — the selection cannot produce a score (`meta.reason` is
|
||||
`measured_physiological_domain_required` or `three_domains_required`, and the `error` string is the sentence
|
||||
to show the person); `health_score_config.invalid` — the body failed validation, with the per-issue list
|
||||
under `details.issues`; `invalid_base_updated_at` — `baseUpdatedAt` was present but unparseable, `null`
|
||||
included, which is rejected rather than falling back to the unconditional write. A body that is not JSON at
|
||||
all returns the bare message `health-score-config.body.invalid_json` with no errorCode."
|
||||
`no_pillars_selected`, and the `error` string is the sentence to show the person). Since v1.38 the empty
|
||||
selection is the ONLY one refused: two areas of health, or one, now save and produce a score that labels its
|
||||
own breadth, so a client must not pre-empt the write with a three-area rule of its own.
|
||||
`health_score_config.invalid` — the body failed validation, with the per-issue list under `details.issues`;
|
||||
`invalid_base_updated_at` — `baseUpdatedAt` was present but unparseable, `null` included, which is rejected
|
||||
rather than falling back to the unconditional write. A body that is not JSON at all returns the bare message
|
||||
`health-score-config.body.invalid_json` with no errorCode."
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
@@ -48915,6 +48917,12 @@ components:
|
||||
configuration itself is never on this wire. Optional so older cached snapshots without the field
|
||||
stay valid."
|
||||
type: boolean
|
||||
scoreBasis:
|
||||
description: What the number rests on. Since v1.38 a score is served from one or two areas of health as well as three,
|
||||
computed identically at each, so this is the only field that tells a narrow score from a broad one —
|
||||
render it beside the number. Optional so older cached snapshots without the field stay valid; the
|
||||
live builder always sets it.
|
||||
$ref: "#/components/schemas/HealthScoreBasis"
|
||||
deltaReason:
|
||||
anyOf:
|
||||
- type: string
|
||||
@@ -49301,6 +49309,43 @@ components:
|
||||
- score
|
||||
- band
|
||||
additionalProperties: false
|
||||
HealthScoreBasis:
|
||||
type: object
|
||||
properties:
|
||||
domains:
|
||||
type: integer
|
||||
minimum: 1
|
||||
maximum: 9007199254740991
|
||||
description: Distinct areas of health counted. NOT the length of `composition` — three of the seven pillars share the
|
||||
cardiometabolic area, so a three-pillar score can rest on one area.
|
||||
recommended:
|
||||
type: integer
|
||||
minimum: -9007199254740991
|
||||
maximum: 9007199254740991
|
||||
description: "How many distinct areas the method recommends. A recommendation, not a floor: a score below it is computed
|
||||
and served, it is just narrower."
|
||||
tier:
|
||||
type: string
|
||||
enum:
|
||||
- full
|
||||
- partial
|
||||
- minimal
|
||||
description: "`full` = at or above the recommended breadth, `partial` = two areas, `minimal` = one. The arithmetic is
|
||||
identical at every tier — the same mean, the same worst-pillar band drag, the same noise floor — so this is
|
||||
the only thing that distinguishes a narrow score from a broad one on the wire. Render it beside the number."
|
||||
physiological:
|
||||
type: boolean
|
||||
description: "Whether any counted pillar rests on a physiological measurement (blood pressure, glucose, sleep, body
|
||||
shape, cholesterol). False means the score is built from activity and/or wellbeing alone. A statement of
|
||||
scope, not a warning: the score still exists and is still honest about what produced it."
|
||||
required:
|
||||
- domains
|
||||
- recommended
|
||||
- tier
|
||||
- physiological
|
||||
additionalProperties: false
|
||||
description: What the Health Score rests on, resolved server-side. Present on every score computed from at least one
|
||||
usable pillar; optional on every shape that carries it, so payloads cached before v1.38 stay valid.
|
||||
InsightsComprehensiveResponseEnvelope:
|
||||
type: object
|
||||
properties:
|
||||
@@ -50152,6 +50197,11 @@ components:
|
||||
type: boolean
|
||||
description: True when the account's own recipe narrows the composition below what its defaults would resolve to today.
|
||||
The configuration itself never rides this wire.
|
||||
scoreBasis:
|
||||
description: What the number rests on. Since v1.38 a score is produced from one or two areas of health as well as three,
|
||||
with identical arithmetic at each, so this block is the only thing on the wire that distinguishes
|
||||
them. Optional so a composite cached before v1.38 stays valid; the live scorer always sets it.
|
||||
$ref: "#/components/schemas/HealthScoreBasis"
|
||||
noiseFloor:
|
||||
type: number
|
||||
scoreVersion:
|
||||
@@ -64143,14 +64193,19 @@ components:
|
||||
type: array
|
||||
items:
|
||||
type: string
|
||||
scoreBasis:
|
||||
description: What the value rests on. Since v1.38 a score is produced from one or two areas of health as well as three,
|
||||
so this is what distinguishes a narrow score from a broad one. Optional so older cached digests
|
||||
without the field stay valid.
|
||||
$ref: "#/components/schemas/HealthScoreBasis"
|
||||
required:
|
||||
- value
|
||||
- band
|
||||
- delta
|
||||
additionalProperties: false
|
||||
- type: "null"
|
||||
description: Health score + band + week-over-week delta, plus whether the account authored the composition; null when
|
||||
none.
|
||||
description: Health score + band + week-over-week delta, plus whether the account authored the composition and how broad
|
||||
the set behind it is; null when none.
|
||||
topSignal:
|
||||
anyOf:
|
||||
- type: object
|
||||
|
||||
Reference in new issue
Block a user