Carry the configured flag onto the snapshot and digest wires

The dashboard snapshot copies it off the composite, the daily digest
copies it off the snapshot, and the derived-metric payload already
carries it inside the composite value. Optional on both DTOs like the
score identity fields beside it, so older cached bodies stay valid.

The digest's score object is additionalProperties:false and had never
declared deltaReason, scoreVersion or composition, all of which it has
been sending. A generated strict decoder would have rejected the real
payload, so they are declared here too rather than left standing next
to a field that documents itself correctly.
This commit is contained in:
Marc-André Bombeck committed 2026-07-31 18:03:53 +02:00
1 parent 5d7d00949c
commit c29055be1c
6 files changed
+84 -2

No files matched your search

+29 -1
View File
@@ -28112,6 +28112,13 @@ components:
- WELLBEING
- FITNESS
- LIPIDS
configured:
description: "True when the account's own recipe narrows the score's composition below what its defaults would resolve
to today. Server-resolved, so a client never interprets a configuration blob: an account that kept
every pillar reads false, and so does one whose disabled modules alone narrow the set. The
configuration itself is never on this wire. Optional so older cached snapshots without the field
stay valid."
type: boolean
deltaReason:
anyOf:
- type: string
@@ -35262,13 +35269,34 @@ components:
anyOf:
- type: number
- type: "null"
configured:
description: True when the account's own recipe narrows the score's composition below what its defaults would resolve to
today. Resolved on the server and carried straight from the dashboard snapshot; the configuration
itself never rides this wire. Optional so older cached digests without the field stay valid.
type: boolean
deltaReason:
description: Why a delta was suppressed; null when it was not.
anyOf:
- type: string
- type: "null"
scoreVersion:
description: Algorithm version that produced the value.
type: integer
exclusiveMinimum: 0
maximum: 9007199254740991
composition:
description: Registry-ordered pillar ids the value was composed of.
type: array
items:
type: string
required:
- value
- band
- delta
additionalProperties: false
- type: "null"
description: Health score + band + week-over-week delta; null when none.
description: Health score + band + week-over-week delta, plus whether the account authored the composition; null when
none.
topSignal:
anyOf:
- type: object
+6
View File
@@ -105,6 +105,12 @@ export interface DailyDigestScore {
deltaReason?: ScoreDeltaReason | null;
scoreVersion?: number;
composition?: ScorePillarId[];
/**
* v1.35.0 — the resolved "this score is configured" flag, carried
* straight from the snapshot's health-score block. Omitted by older
* cached digests, like its siblings above.
*/
configured?: boolean;
}
/** A broken integration, deterministically derived from `IntegrationStatus`. */
+1
View File
@@ -431,6 +431,7 @@ export async function loadDailyDigest(
deltaReason: snapshot.healthScore.deltaReason,
scoreVersion: snapshot.healthScore.scoreVersion,
composition: snapshot.healthScore.composition,
configured: snapshot.healthScore.configured,
}
: null;
+12
View File
@@ -329,6 +329,17 @@ export interface DashboardSnapshotHealthScore {
delta: number | null;
confidence?: DerivedConfidence;
composition?: ScorePillarId[];
/**
* v1.35.0 — the resolved "this score is configured" flag: true when the
* person's own recipe narrows the composition below what the account's
* defaults would resolve to today. Server-resolved so the hero, the
* widget and the complication acknowledge an authored recipe without
* interpreting a config blob; the blob itself never rides this wire,
* and neither does any per-pillar config detail. Optional on the type
* (additive contract) so older cached snapshots stay valid; the live
* builder always sets it.
*/
configured?: boolean;
deltaReason?: ScoreDeltaReason | null;
scoreVersion?: number;
bandSetter?: ScorePillarId | null;
@@ -792,6 +803,7 @@ async function buildExtras(
delta: scoreResult.delta,
confidence: scoreResult.composite.confidence,
composition: scoreResult.composite.value.composition,
configured: scoreResult.composite.value.configured,
deltaReason: scoreResult.deltaReason,
scoreVersion: scoreResult.scoreVersion,
bandSetter: scoreResult.composite.value.bandSetter,
+30 -1
View File
@@ -69,9 +69,38 @@ const dailyDigestResponse = z
value: z.number(),
band: z.string(),
delta: z.number().nullable(),
configured: z
.boolean()
.optional()
.describe(
"True when the account's own recipe narrows the score's composition below what its defaults would resolve to today. Resolved on the server and carried straight from the dashboard snapshot; the configuration itself never rides this wire. Optional so older cached digests without the field stay valid.",
),
// The score's identity fields have ridden this wire since the
// digest first carried a score, but the object is
// `additionalProperties: false` and never declared them — a
// generated strict decoder would have rejected the real payload.
// Declared here rather than left standing beside a new field
// that documents itself correctly.
deltaReason: z
.string()
.nullable()
.optional()
.describe("Why a delta was suppressed; null when it was not."),
scoreVersion: z
.number()
.int()
.positive()
.optional()
.describe("Algorithm version that produced the value."),
composition: z
.array(z.string())
.optional()
.describe("Registry-ordered pillar ids the value was composed of."),
})
.nullable()
.describe("Health score + band + week-over-week delta; null when none."),
.describe(
"Health score + band + week-over-week delta, plus whether the account authored the composition; null when none.",
),
topSignal: z
.object({
sourceMetric: z.string(),
@@ -1109,6 +1109,12 @@ export const dashboardSnapshotResponse = z
]),
)
.optional(),
configured: z
.boolean()
.optional()
.describe(
"True when the account's own recipe narrows the score's composition below what its defaults would resolve to today. Server-resolved, so a client never interprets a configuration blob: an account that kept every pillar reads false, and so does one whose disabled modules alone narrow the set. The configuration itself is never on this wire. Optional so older cached snapshots without the field stay valid.",
),
deltaReason: z
.enum([
"algorithm_changed",