merge(FIX-E): v1.20.2 audit fixes

This commit is contained in:
Marc-André Bombeck committed 2026-06-26 09:28:43 +02:00
commit ca1cf53d2c
19 files changed
+223 -30

No files matched your search

+12
View File
@@ -109,4 +109,16 @@ export const AI_BUDGETS = {
* gates with a tight 6/hour rate bucket + reserveBudget + upload-size cap.
*/
ocrExtract: { temperature: 0, maxTokens: 4000 },
/**
* v1.20.1 — Lab-OCR text-mode structuring. The browser OCR's the image
* (tesseract.js) and POSTs only the extracted TEXT, so the provider does a
* plain text→JSON structuring pass — no expensive vision input tokens. The
* output contract is identical (the same dozen-plus analyte rows), but the
* spend ceiling is far lower than the vision path's 4000, so the day-budget
* reservation should reflect that rather than over-charging a text call at
* the vision rate. 1500 tokens comfortably covers a dense report's JSON
* envelope. Temperature 0 — faithful structuring, not generation.
*/
ocrExtractText: { temperature: 0, maxTokens: 1500 },
} as const satisfies Record<string, AiBudget>;
+4 -2
View File
@@ -20,8 +20,10 @@
* mutation or egress surface.
*
* The builder result is memoised by the 60s snapshot LRU keyed on
* `(userId, window, sources)`, so several tool calls in one turn (and the
* base-context inventory build) share the underlying reads.
* `(userId, window, sources)`. Each tool scopes to a different source set, so
* tool calls for distinct domains do NOT share a cache entry; sharing happens
* only when the SAME scope recurs (a repeated call, or a turn that re-enters
* the same domain) within the 60s window.
*/
import { z } from "zod/v4";
+16 -3
View File
@@ -47,6 +47,14 @@ import {
/** Refresh the access token this many ms before `tokenExpiresAt`. */
const TOKEN_REFRESH_BUFFER_MS = 5 * 60 * 1000;
/**
* Delimiter joining `(type, externalId)` into a single dedup map key. A
* control character keeps it unambiguous against any value a real type or
* externalId could contain, while staying a normal printable-safe constant
* (a literal NUL in the source made text tooling treat the file as binary).
*/
const DEDUP_KEY_DELIM = "\u0000";
/**
* Overlap window for the incremental sync, in ms. Fitbit finalises daily
* summaries after the fact (a daily SpO2 / HRV / RHR can settle hours after the
@@ -396,7 +404,10 @@ export async function upsertFitbitMeasurements(
liveByKey = new Map(
existing
.filter((e) => e.externalId !== null)
.map((e) => [`${e.type}${e.externalId}`, { id: e.id }]),
.map((e) => [
`${e.type}${DEDUP_KEY_DELIM}${e.externalId}`,
{ id: e.id },
]),
);
} catch (err) {
// A probe failure must not strand the whole batch; fall back to treating
@@ -421,7 +432,7 @@ export async function upsertFitbitMeasurements(
const plannedCreateKeys = new Set<string>();
for (const r of readings) {
const type = r.type as MeasurementType;
const key = `${type}${r.externalId}`;
const key = `${type}${DEDUP_KEY_DELIM}${r.externalId}`;
const live = liveByKey.get(key);
if (live) {
toUpdate.push({ id: live.id, r });
@@ -438,7 +449,9 @@ export async function upsertFitbitMeasurements(
} else {
// A duplicate fresh key inside the same batch — overwrite the planned
// create's payload so last-write-wins, matching the prior upsert loop.
const idx = toCreate.findIndex((c) => `${c.type}${c.externalId}` === key);
const idx = toCreate.findIndex(
(c) => `${c.type}${DEDUP_KEY_DELIM}${c.externalId}` === key,
);
if (idx >= 0) {
toCreate[idx] = {
type,
+1 -3
View File
@@ -29,9 +29,7 @@ const capabilityResponse = z
.object({
available: z.boolean(),
mode: z.enum(["vision", "text"]).nullable(),
reason: z
.enum(["no-provider", "text-only-model", "enable-local-ocr"])
.nullable(),
reason: z.enum(["no-provider", "enable-local-ocr"]).nullable(),
pdfSupported: z.boolean(),
})
.meta({
+1 -1
View File
@@ -207,7 +207,7 @@ export interface OcrCapabilityDto {
*/
mode: "vision" | "text" | null;
/** Why scanning is unavailable, when it is. */
reason: "no-provider" | "text-only-model" | "enable-local-ocr" | null;
reason: "no-provider" | "enable-local-ocr" | null;
/** Whether PDF uploads are accepted (Anthropic vision provider only). */
pdfSupported: boolean;
}