test(anamnesis): drive the life circumstances, AUDIT-C and its backup through real Postgres and the manage matrix

This commit is contained in:
Marc-André Bombeck committed 2026-10-16 01:34:17 +02:00
1 parent 88aa5ccacd
commit 4d2c8c2bbb
8 files changed
+718 -16

No files matched your search

+2 -2
View File
@@ -16,7 +16,7 @@ import {
correctLifeFact,
removeHealthProfileFact,
} from "@/lib/profile/health-facts";
import { dayStartUtc } from "@/lib/profile/life-derived";
import { dateOnlyAtNoonUtc } from "@/lib/tz/date-only";
import {
validateCorrectedFactValue,
type HealthProfileFactKind,
@@ -63,7 +63,7 @@ export const PATCH = apiHandler(
// circumstances (v1.43, #614).
const now = new Date();
const validFrom = parsed.data.validFrom
? dayStartUtc(parsed.data.validFrom)
? dateOnlyAtNoonUtc(parsed.data.validFrom)
: undefined;
let corrected: { id: string; kind: string } | null;
if (isLifeFactKind(current.kind)) {
+2 -2
View File
@@ -17,7 +17,7 @@ import {
createLifeFact,
readHealthProfileFacts,
} from "@/lib/profile/health-facts";
import { dayStartUtc } from "@/lib/profile/life-derived";
import { dateOnlyAtNoonUtc } from "@/lib/tz/date-only";
import { factWriteSchema } from "@/lib/validations/life-circumstances";
/**
@@ -51,7 +51,7 @@ async function postFact(request: NextRequest): Promise<Response> {
const now = new Date();
const validFrom = parsed.data.validFrom
? dayStartUtc(parsed.data.validFrom)
? dateOnlyAtNoonUtc(parsed.data.validFrom)
: undefined;
try {
const input = parsed.data;
+7 -3
View File
@@ -27,6 +27,7 @@
* Server-only — reads `@/lib/db`.
*/
import { prisma } from "@/lib/db";
import { userDayKey } from "@/lib/tz/format";
import { getEvent } from "@/lib/logging/context";
import { decryptFromBytes, encryptToBytes } from "@/lib/ai/coach/bytes-codec";
import {
@@ -508,6 +509,8 @@ export interface LifeFactForPrompt {
export interface AuditCForPrompt {
totalScore: number;
takenAt: Date;
/** The zone the entry was taken in, for its calendar day. */
tz: string;
cutoff: number | null;
aboveCutoff: boolean | null;
}
@@ -624,7 +627,7 @@ export function composeLifeCircumstancesText(
lines.push(
`${L.auditC}: ${fill(L.auditCValue, {
score: auditC.totalScore,
date: auditC.takenAt.toISOString().slice(0, 10),
date: userDayKey(auditC.takenAt, auditC.tz),
})}${verdict}`,
);
}
@@ -645,12 +648,12 @@ async function loadAuditCForPrompt(
const audit = await prisma.mentalHealthAssessment.findFirst({
where: { userId, instrument: "AUDIT_C", deletedAt: null },
orderBy: [{ takenAt: "desc" }, { id: "desc" }],
select: { totalScore: true, takenAt: true, locale: true },
select: { totalScore: true, takenAt: true, locale: true, tz: true },
});
if (!audit) return null;
const user = await prisma.user.findUnique({
where: { id: userId },
select: { gender: true, locale: true },
select: { gender: true, locale: true, timezone: true },
});
const cutoff = auditCCutoff(
audit.locale,
@@ -660,6 +663,7 @@ async function loadAuditCForPrompt(
return {
totalScore: audit.totalScore,
takenAt: audit.takenAt,
tz: audit.tz ?? user?.timezone ?? "UTC",
cutoff: cutoff?.value ?? null,
aboveCutoff: cutoff ? audit.totalScore >= cutoff.value : null,
};
-5
View File
@@ -62,11 +62,6 @@ export const LIFE_KIND_AI_SECTION: Readonly<
export const REVIEW_AFTER_DAYS = 365;
const MS_PER_DAY = 86_400_000;
/** UTC midnight of a `YYYY-MM-DD` calendar day. */
export function dayStartUtc(day: string): Date {
return new Date(`${day}T00:00:00.000Z`);
}
/** Whether an instant is at least `REVIEW_AFTER_DAYS` before `now`. */
export function isReviewDue(at: Date | null, now: Date): boolean {
return (
+1 -1
View File
@@ -249,7 +249,7 @@ const validFromDay = z.iso
.date()
.optional()
.describe(
"The calendar day the answer holds from (UTC midnight). Omitted, it holds from now. Never later than today; an earlier day than the end of the previous answer of the same kind starts at that end instead.",
"The calendar day the answer holds from, stored at noon UTC like every date-only value. Omitted, it holds from now. Never later than today; an earlier day than the end of the previous answer of the same kind starts at that end instead.",
);
/**