From a42b29a160a799a08184207c61919eb52e08cc6c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Bombeck?= Date: Sun, 25 Oct 2026 18:54:33 +0100 Subject: [PATCH] perf(ai): read the deletion lock with the usage level, not on its own The capability gate's check for an account pending deletion added a point read of users to every request that resolves AI capabilities, one statement over the budget on /api/auth/me, the dashboard snapshot and the batch ingest. The usage-level read already loads the record's row once per request; it now carries the deletion lock too. --- src/lib/ai/capabilities/load.ts | 13 +++++++------ src/lib/ai/capabilities/usage.ts | 8 +++++++- 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/src/lib/ai/capabilities/load.ts b/src/lib/ai/capabilities/load.ts index d619c1c5a..2b037b45a 100644 --- a/src/lib/ai/capabilities/load.ts +++ b/src/lib/ai/capabilities/load.ts @@ -41,7 +41,11 @@ import { type AiRecordKind, } from "./resolve"; import type { AiCapabilities } from "./types"; -import { loadAiUsageState, loadRecordUsageLevel } from "./usage"; +import { + loadAiUsageState, + loadRecordAiUsage, + loadRecordUsageLevel, +} from "./usage"; /** Whose record, seen by whom, through which grant. */ export interface AiCapabilityScope { @@ -89,11 +93,8 @@ function loadActiveConsents( * (`src/lib/account-deletion/active-account.ts`). */ async function loadRecordDeletionPending(recordId: string): Promise { - const row = await prisma.user.findUnique({ - where: { id: recordId }, - select: { deletionRequestedAt: true }, - }); - return row?.deletionRequestedAt != null; + // The same memoised point read as the usage level. + return (await loadRecordAiUsage(recordId)).deletionPending; } function scopeKey(scope: AiCapabilityScope): string { diff --git a/src/lib/ai/capabilities/usage.ts b/src/lib/ai/capabilities/usage.ts index decf7e4ff..d1eb3e7af 100644 --- a/src/lib/ai/capabilities/usage.ts +++ b/src/lib/ai/capabilities/usage.ts @@ -106,6 +106,11 @@ export function loadAiUsageSettings(): Promise { export interface RecordAiUsage extends AiUsageResolution { preference: AiUsageLevel | null; settings: AiUsageSettings; + /** + * The record is pending deletion. Read in the same point read as the level, + * so the capability gate's deletion check costs no statement of its own. + */ + deletionPending: boolean; } /** @@ -118,11 +123,12 @@ export function loadRecordAiUsage(recordId: string): Promise { loadAiUsageSettings(), prisma.user.findUnique({ where: { id: recordId }, - select: { aiUsageLevel: true }, + select: { aiUsageLevel: true, deletionRequestedAt: true }, }), ]); const preference = usageLevelFromDb(row?.aiUsageLevel); return { + deletionPending: row?.deletionRequestedAt != null, ...resolveAiUsageLevel({ preference, defaultLevel: settings.defaultLevel,