fix(personal-records): exclude soft-deleted measurements from PR detection

pr-detection-worker.ts ran its warm-up count and best-measurement scan
across every Measurement row including soft-deleted ones. A user who
deleted a row that happened to be their PR would not get the next-best
row promoted on the next detection pass. Add `deletedAt: null` to both
where clauses to align with the v1.4.40 soft-delete completeness sweep.

Also document the offhost-backup DR-intent at the matching findMany —
that path deliberately includes soft-deleted rows because the offhost
upload is a disaster-recovery snapshot, not a user-facing export.
This commit is contained in:
Marc-André Bombeck committed 2026-05-21 18:55:14 +02:00
1 parent 6af9e1afff
commit 702afe5d49
2 files changed
+5 -2

No files matched your search

+3
View File
@@ -216,6 +216,9 @@ export async function runOffhostBackup(
try {
const [measurements, medications, intakeEvents, moodEntries] =
await Promise.all([
// includes soft-deleted rows because this is the DR snapshot,
// not a user-facing export — see
// `/api/export/full-backup/route.ts` for the symmetric exclusion.
prisma.measurement.findMany({ where: { userId: user.id } }),
prisma.medication.findMany({
where: { userId: user.id },
@@ -217,7 +217,7 @@ export async function detectPersonalRecordsForUser(
// Warm-up gate. Cheap count first so we don't pull a 30k-row
// scan on a brand-new account.
const sampleCount = await prisma.measurement.count({
where: { userId, type: metricType },
where: { userId, type: metricType, deletedAt: null },
});
if (sampleCount < PR_DETECTION_WARMUP_THRESHOLD) continue;
@@ -400,7 +400,7 @@ async function findBestMeasurement(
direction: PersonalRecordDirection,
): Promise<MeasurementCandidate | null> {
const row = await prisma.measurement.findFirst({
where: { userId, type },
where: { userId, type, deletedAt: null },
orderBy:
direction === PersonalRecordDirection.MAX
? { value: "desc" }