mirror of
https://github.com/MBombeck/HealthLog.git
synced 2026-11-12 14:16:12 +00:00
fix(measurements): name the batch validation refusal and the band an entry broke
The validation 422 from `POST /api/measurements/batch` now carries `meta.errorCode: "measurement.batch.invalid"`, beside the existing `too_large` and `source_not_permitted` codes, so a client can file the rows as permanently refused instead of holding its anchor on a guess. A `value_out_of_range` entry now also carries `convertedValue`, the reading after conversion into the stored unit, and `range` (`min`, `max`, `unit`), the band it was checked against. Both appear only on that skip. A fraction sent where a percent was expected is now visible in the response instead of looking like a sensor glitch. Status codes, the envelope and every existing field are unchanged.
This commit is contained in:
1 parent
74dedee645
commit
a7682a9fed
5 files changed
+320
-15
No files matched your search
@@ -198,6 +198,7 @@ export const ERROR_CODE_CATALOGUE: Readonly<Record<string, readonly string[]>> =
|
||||
"managed_profile.not_found",
|
||||
],
|
||||
measurement: [
|
||||
"measurement.batch.invalid",
|
||||
"measurement.batch.source_not_permitted",
|
||||
"measurement.batch.too_large",
|
||||
"measurement.bulk-delete.invalid",
|
||||
|
||||
@@ -147,6 +147,22 @@ const batchEntryResult = z
|
||||
"`inserted`/`duplicate` — the row landed (advance the cursor). `updated` — a `stats:` aggregate overwrote an existing row. `skipped` — validation no-op; see `reason`. `failed` — retryable database failure that must not advance the entry cursor; the response is marked `Cache-Control: no-store`.",
|
||||
),
|
||||
reason: z.string().optional(),
|
||||
convertedValue: z
|
||||
.number()
|
||||
.optional()
|
||||
.describe(
|
||||
"Only on a `value_out_of_range` skip (since v1.39.1): the entry's value after conversion into the stored unit, which is the number the band was checked against. A HealthKit fraction that should have been a percent shows up here a hundred times off.",
|
||||
),
|
||||
range: z
|
||||
.object({
|
||||
min: z.number(),
|
||||
max: z.number(),
|
||||
unit: z.string(),
|
||||
})
|
||||
.optional()
|
||||
.describe(
|
||||
"Only on a `value_out_of_range` skip (since v1.39.1): the plausibility band that refused the entry, in the stored unit. Both edges are inclusive. A skip is permanent for the value as sent; resending it unchanged skips it again.",
|
||||
),
|
||||
})
|
||||
.meta({ id: "AppleHealthBatchEntryResult" });
|
||||
|
||||
@@ -1011,7 +1027,7 @@ export const measurementPaths: NonNullable<ZodOpenApiObject["paths"]> = {
|
||||
...stdResponses,
|
||||
"422": {
|
||||
description:
|
||||
"The batch exceeded the 500-entry limit (`measurement.batch.too_large`), failed validation, or (`measurement.batch.source_not_permitted`) carried an entry naming `APPLE_HEALTH` under a narrow `measurements:write` credential. Nothing was written in any of the three cases.",
|
||||
"The batch exceeded the 500-entry limit (`measurement.batch.too_large`), failed validation (`measurement.batch.invalid`, with every issue under `details.issues`), or (`measurement.batch.source_not_permitted`) carried an entry naming `APPLE_HEALTH` under a narrow `measurements:write` credential. Nothing was written in any of the three cases, and all three are permanent for the batch as sent: resending it unchanged is refused the same way.",
|
||||
content: { "application/json": { schema: errorEnvelope } },
|
||||
},
|
||||
},
|
||||
|
||||
Reference in new issue
Block a user