mirror of
https://github.com/MBombeck/HealthLog.git
synced 2026-11-12 06:06:10 +00:00
feat(insights): bucketed measurement payload for raw mode
Replace the per-row rawMeasurements dump with DAY/WEEK/MONTH bucket means read from measurement_rollups. The legacy shape blew past Codex's 10 MB string limit on power-user accounts; the bucketed shape stays O(types × buckets) regardless of row count. Enforce a 5 MB ceiling on the serialised payload; the generate route downgrades to the aggregated shape and annotates when the cap trips so future regressions surface in logs.
This commit is contained in:
1 parent
b4bef03fd7
commit
2e2ca2242f
3 files changed
+346
-15
No files matched your search
@@ -1,7 +1,10 @@
|
||||
import { prisma } from "@/lib/db";
|
||||
import { auditLog } from "@/lib/auth/audit";
|
||||
import { apiSuccess, apiError, getClientIp } from "@/lib/api-response";
|
||||
import { extractFeatures } from "@/lib/insights/features";
|
||||
import {
|
||||
extractFeatures,
|
||||
FeaturesPayloadTooLargeError,
|
||||
} from "@/lib/insights/features";
|
||||
import {
|
||||
detectGlp1Plateau,
|
||||
buildGlp1PlateauPrompt,
|
||||
@@ -266,8 +269,37 @@ export const POST = apiHandler(async (request: NextRequest) => {
|
||||
}
|
||||
|
||||
const includeRaw = dbUser?.insightsPrivacyMode === "raw";
|
||||
const features = await extractFeatures(userId, includeRaw);
|
||||
// v1.4.36 W3 T1 — `extractFeatures` enforces a 5 MB ceiling on the
|
||||
// serialised payload. If the raw (bucketed) shape ever blows past
|
||||
// it (regression watch — the v1.4.35 rawMeasurements shape hit
|
||||
// 25.9 MB on Marc's account), the helper throws
|
||||
// `FeaturesPayloadTooLargeError`. We downgrade to the aggregated
|
||||
// shape rather than 500-ing so the user still gets an insight; the
|
||||
// annotate event surfaces the regression to ops via the Logflare
|
||||
// pipeline.
|
||||
let features: Awaited<ReturnType<typeof extractFeatures>>;
|
||||
let payloadDowngraded = false;
|
||||
let payloadOversizeBytes: number | null = null;
|
||||
try {
|
||||
features = await extractFeatures(userId, includeRaw);
|
||||
} catch (err) {
|
||||
if (err instanceof FeaturesPayloadTooLargeError) {
|
||||
payloadDowngraded = true;
|
||||
payloadOversizeBytes = err.sizeBytes;
|
||||
features = await extractFeatures(userId, false);
|
||||
} else {
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
const featuresJson = JSON.stringify(features, null, 2);
|
||||
if (payloadDowngraded) {
|
||||
annotate({
|
||||
meta: {
|
||||
insights_features_downgraded: true,
|
||||
insights_features_oversize_bytes: payloadOversizeBytes,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
// v1.4.16 phase B8 — pick up the user's persisted comparison toggle
|
||||
// and, when active, build a compact prior-period snapshot from the
|
||||
|
||||
Reference in new issue
Block a user