diff --git a/.env.example b/.env.example index c0efd6658..61a0289df 100644 --- a/.env.example +++ b/.env.example @@ -38,6 +38,12 @@ # echo "POSTGRES_PASSWORD=$(openssl rand -hex 32)" >> .env # Left commented here so that append does not create a duplicate key. Uncomment # and set it directly instead if you prefer to edit the file by hand. + +# The container runs the app as `healthlog_app`, a database role it creates on +# every start that reads and writes rows but cannot change the schema. The +# migrations keep the DATABASE_URL user. "off" keeps the app on that user, if +# you manage database roles yourself (docs/self-hosting/database-role.md). +# DB_APP_ROLE="off" # POSTGRES_PASSWORD="generate-with-openssl-rand-hex-32" diff --git a/.env.production.example b/.env.production.example index b82aae357..9c6ad5dbe 100644 --- a/.env.production.example +++ b/.env.production.example @@ -526,6 +526,14 @@ API_TOKEN_HMAC_KEY="" # Behind such a pooler, set this to 1, true or yes to send no session # settings at all; the pooler's or the database's own defaults then apply. # DATABASE_SESSION_OPTIONS_DISABLED="1" +# +# The app runs as `healthlog_app`, a database role the container creates on +# every start: it reads and writes rows but cannot alter or drop tables or +# create roles. Migrations and restores still use the user in DATABASE_URL. +# Where that user may not create roles (a managed database), the start log +# says so and the app uses DATABASE_URL as given. Set "off" if you manage +# the database roles yourself. See docs/self-hosting/database-role.md. +# DB_APP_ROLE="off" # ----------------------------------------------------------------------------- diff --git a/Dockerfile b/Dockerfile index 37143e516..7c03b74e2 100644 --- a/Dockerfile +++ b/Dockerfile @@ -257,6 +257,8 @@ COPY --from=builder /app/scripts/pending-migrations.mjs ./scripts/pending-migrat COPY --from=builder /app/scripts/migrate-deploy.mjs ./scripts/migrate-deploy.mjs COPY --from=builder /app/scripts/db-dump.mjs ./scripts/db-dump.mjs COPY --from=builder /app/scripts/db-restore.mjs ./scripts/db-restore.mjs +COPY --from=builder /app/scripts/db-app-role.mjs ./scripts/db-app-role.mjs +COPY --from=builder /app/src/lib/jobs/retired-measurement-indexes.mjs ./src/lib/jobs/retired-measurement-indexes.mjs COPY --from=builder /app/src/lib/database-backup/dump-core.mjs ./src/lib/database-backup/dump-core.mjs COPY --from=builder /app/src/lib/auth/argon2-params.mjs ./src/lib/auth/argon2-params.mjs COPY --from=builder /app/scripts/repair-intake-anomalies.ts ./scripts/repair-intake-anomalies.ts diff --git a/docker-compose.yml b/docker-compose.yml index b7e7faef3..f10142dc2 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -81,6 +81,11 @@ x-healthlog-env: &healthlog_env # 1 sends neither of the two settings above (they ride the libpq `options` # startup parameter, which PgBouncer refuses by default). DATABASE_SESSION_OPTIONS_DISABLED: "${DATABASE_SESSION_OPTIONS_DISABLED:-}" + # The app connects as `healthlog_app`, a role the entrypoint creates that + # reads and writes rows but cannot change the schema; the migrations keep + # the owner above. off keeps the app on the owner (for an operator who + # manages database roles). See docs/self-hosting/database-role.md. + DB_APP_ROLE: "${DB_APP_ROLE:-}" WITHINGS_WEBHOOK_SECRET: "${WITHINGS_WEBHOOK_SECRET:-}" # Overrides the derived `${NEXT_PUBLIC_APP_URL}/api/withings/callback`; # set it when the URL registered with Withings differs from the app's own diff --git a/docker-entrypoint.sh b/docker-entrypoint.sh index b31e9871e..e74be1f56 100644 --- a/docker-entrypoint.sh +++ b/docker-entrypoint.sh @@ -107,6 +107,22 @@ NODE_PATH=/opt/prisma-cli/node_modules \ node scripts/migrate-deploy.mjs echo "HealthLog: Migrations complete." +# ── The app's database role ────────────────────────────────── +# Everything above ran as the owner DATABASE_URL names. The app itself +# connects as `healthlog_app`, which reads and writes rows and runs the queue +# but cannot change the schema (scripts/db-app-role.mjs says what it may and +# may not do, and docs/self-hosting/database-role.md how to opt out). The +# script hands the role's URL over on descriptor 3 only, never on stdout or +# stderr; nothing handed over means it said why and the app stays on the +# owner, as before. The owner's URL is replaced, not kept beside it, so it +# does not reach the app's environment. +app_database_url="$(node scripts/db-app-role.mjs 3>&1 1>&2)" || app_database_url="" +if [ -n "$app_database_url" ]; then + DATABASE_URL="$app_database_url" + export DATABASE_URL +fi +unset app_database_url + # ── Start application ──────────────────────────────────────── echo "HealthLog: Starting application..." exec "$@" diff --git a/docs/ops/deploy.md b/docs/ops/deploy.md index 5a12edd69..15ce03a1d 100644 --- a/docs/ops/deploy.md +++ b/docs/ops/deploy.md @@ -140,6 +140,22 @@ An INVALID index whose migration is already recorded applied is not touched at boot. The boot names it on stderr with `WARNING — index … is INVALID`; rebuild it with `REINDEX INDEX CONCURRENTLY "";` when the database is quiet. +### The app's database role + +The steps above run as the owner `DATABASE_URL` names: the dump, the +migrations and, after them, the setup of `healthlog_app`, the role the app +then connects as ([database-role.md](../self-hosting/database-role.md)). The +app never runs a migration. A migration that creates a table needs nothing +more: the setup grants the role every table it lacks before the app starts. + +On the first start of the release that brings the role, the setup hands the +existing `pgboss` tables to it, which takes each table's lock for a moment. +Stop the old container (and a separate worker) before the new one starts, as +for any update with migrations; a lock that does not come within 15 seconds +leaves that start on the owner with a notice, and the next start tries again. +A web container and a worker container that start together wait for each +other on an advisory lock and derive the same password. + ### v1.46.0 notes - **Postgres 18.** The compose file moves the bundled database from diff --git a/docs/ops/disaster-recovery.md b/docs/ops/disaster-recovery.md index 0e9bb9364..a6c40c94c 100644 --- a/docs/ops/disaster-recovery.md +++ b/docs/ops/disaster-recovery.md @@ -147,6 +147,14 @@ different. Sign in. The app's own key check runs at start and refuses to serve on a key that does not open the data. +The restore runs as the owner `DATABASE_URL` names, and the restored tables +belong to it. The app connects as `healthlog_app` +([database-role.md](../self-hosting/database-role.md)): the start in step 5 +grants that role the restored tables and hands it the queue schema before the +app runs. A dump carries grants to `healthlog_app`; `db-restore` leaves them +out (`--no-owner --no-privileges`). Restoring with `pg_restore` by hand, pass +the same two flags, or it fails on a database without the role. + When the dumps are still in the server's `backups` volume (the database volume was lost, the backups volume was not), step 4 is `docker compose run --rm db-restore latest`. diff --git a/docs/ops/measurement-maintenance.md b/docs/ops/measurement-maintenance.md index e0bce3094..53e827ddb 100644 --- a/docs/ops/measurement-maintenance.md +++ b/docs/ops/measurement-maintenance.md @@ -214,7 +214,7 @@ So an index is retired in two halves (v1.43.8, migration 0416, for exactly as the schema does, and `prisma migrate dev` / `migrate diff` see no drift and generate nothing. 2. The index name goes into `RETIRED_MEASUREMENT_INDEXES` in - `src/lib/jobs/measurement-maintenance.ts`. Every run of this job, the + `src/lib/jobs/retired-measurement-indexes.mjs`. Every run of this job, the nightly 03:40 check included, drops each name still present with `DROP INDEX CONCURRENTLY IF EXISTS`, waiting at most 60 seconds for its locks. A run that runs out of time leaves the index (possibly marked @@ -242,6 +242,16 @@ SET lock_timeout = '60s'; DROP INDEX CONCURRENTLY IF EXISTS "measurements_user_id_type_measured_at_idx"; ``` +When the app connects as its restricted role +([database-role.md](../self-hosting/database-role.md)), the job may vacuum and +rebuild (`MAINTAIN`) but not drop: `DROP INDEX` belongs to the table's owner. +A run then skips the drops, of retired indexes and of the invalid copy a +failed rebuild leaves, names what it found under +`maintenance_drops_left_for_boot` with a warning, and the next start drops +each as the owner with `DROP INDEX CONCURRENTLY`, waiting at most five +seconds. Until then a failed rebuild's copy holds its disk; restart the +container, or drop it by hand as the owner with the statement above. + For the next large index, follow the same two halves. `src/__tests__/migration-lock-timeout-guard.test.ts` refuses a `DROP INDEX CONCURRENTLY` in any migration and requires every retired name to diff --git a/docs/self-hosting/database-role.md b/docs/self-hosting/database-role.md new file mode 100644 index 000000000..4b8ea1403 --- /dev/null +++ b/docs/self-hosting/database-role.md @@ -0,0 +1,112 @@ +# The app's database role + +The container connects to Postgres under two names. The user in +`DATABASE_URL` (on the bundled compose file, `healthlog`, which the official +Postgres image makes a superuser) owns the schema: the entrypoint uses it for +the dump before an update, the migrations and the restore. The app itself, +web and worker, connects as `healthlog_app`, a role the entrypoint sets up +after the migrations on every start. Nothing to configure: the first start of +a release with this change creates it. + +The point is the blast radius of a bug. If a dependency of the app were ever +made to run code inside the container, the database connection it found would +be one that can read and write rows, not one that can drop tables, rewrite the +schema or reach the server's files. + +## What the role may and may not do + +| May | May not | +| ------------------------------------------------------------------------- | --------------------------------------------------------------- | +| read, insert, update and delete rows in every table of the app's schema | create, alter or drop tables, indexes, types or functions there | +| use and advance its sequences | write `_prisma_migrations` (it may read it) | +| `VACUUM`, `ANALYZE` and `REINDEX` the `measurements` table (`MAINTAIN`) | create roles, schemas or databases | +| own the `pgboss` schema, where the job queue keeps and changes its tables | act as a superuser: no `COPY … PROGRAM`, no `pg_read_file` | +| create temporary tables | become the owner (`SET ROLE`) | + +The queue schema is the role's because pg-boss creates and migrates its own +tables, functions and per-queue partitions while the app runs. Nothing of the +app's data lives there. The start also takes `CREATE` on the app's schema +away from `PUBLIC`, which Postgres 15 and newer already do for a new database +but a database first created on an older major still allows. + +Its password is derived from `API_TOKEN_HMAC_KEY`, so a separate worker +container ([scaling.md](scaling.md)) arrives at the same one without a new +variable, and it is stored as a SCRAM hash. The owner's URL is replaced, not +kept beside the role's, so it is not in the app's environment. +`docker compose exec app …` still starts with the container's configured +environment, so the operator scripts (`reset-password.mjs` and the others) +run as the owner as before. + +Each start re-applies the grants, so a table the new migrations created is +covered before the app starts, and a restored database is put right on the +start after the restore. + +## What the start log says + +When it is in place: + +```text +HealthLog: the app connects as healthlog_app: rows and the queue, no schema changes (DB_APP_ROLE=off turns this off) +``` + +When it is not, one notice names the reason, and the app runs as the +`DATABASE_URL` user, exactly as every earlier release did: + +```text +HealthLog: notice: the app connects as healthlog, the user DATABASE_URL names, not as the restricted role healthlog_app: . … +``` + +The reasons: + +- **The user may not create roles.** A managed database (RDS, Cloud SQL, + Supabase and the like) or a database server where you gave HealthLog an + account without `CREATEROLE`. Either leave it, or create the split yourself + (below) and set `DB_APP_ROLE=off`. +- **Postgres older than 17.** The maintenance job's `VACUUM` and index rebuild + need the `MAINTAIN` privilege, which Postgres 17 introduced; before it only + the table's owner may run them. The bundled database is Postgres 18; see + [postgres-major-upgrade.md](../ops/postgres-major-upgrade.md) for one you + run yourself. +- **The role cannot log in.** A `pg_hba.conf` that lists users by name needs a + line for `healthlog_app` beside the one for the owner. +- **A role named `healthlog_app` exists that HealthLog did not create.** The + start leaves a role it does not recognise alone. +- **Setting it up failed**, most often a lock it waited 15 seconds for: the + first start hands the existing queue tables to the role, and another + container still using them holds it up. The next start tries again. + +None of these stops the start. + +## Turning it off + +Set `DB_APP_ROLE=off` in `.env` and recreate the container. The app then +connects as the `DATABASE_URL` user. Use it when you manage database roles +yourself, including when `DATABASE_URL` already names a restricted role of +your own; then that role needs what the table above lists, and the +migrations need a user that owns the schema. + +The role stays in the database when you turn it off and does no harm. To +remove it, as the owner: + +```sql +REASSIGN OWNED BY healthlog_app TO healthlog; +DROP OWNED BY healthlog_app; +DROP ROLE healthlog_app; +``` + +## Index drops at start + +`DROP INDEX` belongs to a table's owner; `MAINTAIN` does not include it. The +measurement maintenance therefore no longer drops a retired index or the +invalid copy a failed rebuild leaves; it names them on its run and the next +start drops them as the owner, waiting at most five seconds for each +([measurement-maintenance.md](../ops/measurement-maintenance.md)). + +## Dumps and restores + +The nightly dump runs as the role and reads everything: the app's schema +through its grants, the queue schema as its owner. A dump carries the grants +to `healthlog_app`; `db-restore` leaves them and the ownership out +(`--no-owner --no-privileges`), restores as the owner, and the next start +grants again. A restore of your own with `pg_restore` should do the same, or +it fails on a database without the role. diff --git a/docs/self-hosting/scaling.md b/docs/self-hosting/scaling.md index 6ecac0731..3bc36d23b 100644 --- a/docs/self-hosting/scaling.md +++ b/docs/self-hosting/scaling.md @@ -129,6 +129,15 @@ looks healthy. Deploy both from the same image tag (`HEALTHLOG_IMAGE_REF` is shared by `app` and the `app-worker` block) and restart the worker together with the web containers. +## Database role + +Both containers run the entrypoint, and both set up `healthlog_app`, the +database role the app connects as +([database-role.md](database-role.md)). They take turns on an advisory lock +and derive the same password from `API_TOKEN_HMAC_KEY`, which the shared +environment block gives both, so a worker that starts after the web container +changes nothing the web container relies on. + ## Healthchecks - `app` (web) healthcheck: `wget /api/health` every 30s. diff --git a/scripts/db-app-role.mjs b/scripts/db-app-role.mjs new file mode 100644 index 000000000..73b9ca2f5 --- /dev/null +++ b/scripts/db-app-role.mjs @@ -0,0 +1,648 @@ +#!/usr/bin/env node +/** + * The database role the running app connects as. + * + * The migrations, the dump before them and the restore connect as the owner + * `DATABASE_URL` names. The long-running web and worker processes do not need + * the owner: they read and write rows, run the queue, and maintain one table. + * After the migrations, `docker-entrypoint.sh` runs this script as the owner. + * It ensures a login role, `healthlog_app`, that can do exactly that, and + * hands the entrypoint a `DATABASE_URL` for it; the entrypoint then starts the + * app with that URL in place of the owner's, so the owner's credentials never + * reach the app's environment. + * + * What the role can do: + * - SELECT, INSERT, UPDATE, DELETE on every table of the app's schema, and + * USAGE, SELECT, UPDATE on its sequences. `_prisma_migrations` is SELECT + * only: the app reads the migration history, it never writes it. + * - MAINTAIN on `measurements` (Postgres 17+): the maintenance job's + * `VACUUM (ANALYZE)` and `REINDEX INDEX CONCURRENTLY`. + * - Own the `pgboss` schema and everything in it. pg-boss creates and + * migrates its own tables, functions and per-queue partitions at runtime, + * so it needs DDL there; it is the queue's private schema and nothing of + * the app's data lives in it. + * + * What it cannot do: create, alter or drop anything in the app's schema; + * create schemas, databases or roles; act as a superuser, so no + * `COPY ... FROM PROGRAM`, no `pg_read_file`, no untrusted languages; write + * the migration history. `CREATE` on the app's schema is revoked from PUBLIC + * as well (the default since Postgres 15; a database first created on an + * older major still grants it), where the owner may do so. + * + * Every boot re-applies it, inside one transaction under an advisory lock, so + * a table a new migration created is covered before the app starts, a web and + * a worker container booting together do not race, and a restored database + * (whose objects `pg_restore --no-owner` hands to the owner) is put right. + * Grants only touch what lacks them, so a boot after the first writes + * almost nothing to the catalog. + * + * The password is derived, not stored: HMAC-SHA256 of a fixed label under + * API_TOKEN_HMAC_KEY. Every container of one instance carries that key, so a + * separate worker container derives the same password without a new + * variable. It is set as a SCRAM verifier computed here, so the plaintext + * never travels to the server, where a statement log could keep it. The role + * is marked with a comment; a role of the same name without the mark is not + * HealthLog's, and is left alone. + * + * Fail open, loudly. When the owner cannot do this (a managed or external + * database whose user may not create roles, Postgres before 17, a pg_hba.conf + * that does not let the new role in, a lock that did not come in time), the + * script says why in one notice and the app runs as the owner, as it did + * before. `DB_APP_ROLE=off` skips it for an operator who manages roles + * themselves, including one whose `DATABASE_URL` already names a restricted role. + * + * Why Postgres 17: the maintenance job vacuums and rebuilds the indexes of + * `measurements`, and before the MAINTAIN privilege only the table's owner + * could. Rather than leave that job broken on 16, an older server keeps + * today's behaviour. + * + * Index drops stay with the owner: `DROP INDEX` belongs to the table's owner + * and MAINTAIN does not include it. When the role is in place this script + * also drops, as the owner, the indexes the maintenance job used to drop + * (retired indexes, and the invalid copies an interrupted concurrent rebuild + * leaves), each under a short lock wait, so a held lock delays the boot by + * seconds and the drop waits for the next boot. + * + * Interface: the URL for the role goes to file descriptor 3 and nowhere else; + * every message goes to stderr, and no message carries a password or a URL. + * The entrypoint reads it with `url="$(node scripts/db-app-role.mjs 3>&1 1>&2)"`. + * Without descriptor 3 (a manual run) the role is still ensured and the URL is + * not printed. Exit 0 in every case the app should start; nothing written to + * descriptor 3 means: stay on the owner. + * + * Plain ESM with no imports beyond Node, `pg` and the shared dump module, so + * it runs from the runtime image like the other entrypoint scripts. + */ +import { createHash, createHmac, pbkdf2Sync, randomBytes } from "node:crypto"; +import { writeSync } from "node:fs"; +import { pathToFileURL } from "node:url"; + +import { connect } from "../src/lib/database-backup/dump-core.mjs"; +import { + CONCURRENT_COPY, + RETIRED_MEASUREMENT_INDEXES, +} from "../src/lib/jobs/retired-measurement-indexes.mjs"; + +/** The role's name. Cluster-wide, like every Postgres role. */ +export const APP_ROLE = "healthlog_app"; + +/** The mark on a role this script created. */ +export const ROLE_COMMENT = + "Managed by HealthLog: the app's least-privilege login (scripts/db-app-role.mjs). Recreated and re-granted on every start."; + +/** The schema pg-boss keeps its queue in (its default; HealthLog sets none). */ +export const QUEUE_SCHEMA = "pgboss"; + +/** Tables the role may maintain (VACUUM, ANALYZE, REINDEX). */ +export const MAINTAINED_TABLES = Object.freeze(["measurements"]); + +/** Tables the role may only read. */ +export const READ_ONLY_TABLES = Object.freeze(["_prisma_migrations"]); + +/** The label the password is derived under. A new label is a new password. */ +const PASSWORD_LABEL = "healthlog database app role v1"; + +/** The first major with the MAINTAIN privilege. */ +export const MIN_SERVER_VERSION_NUM = 170000; + +/** How long the setup waits for a lock before staying on the owner. */ +const SETUP_LOCK_TIMEOUT = "15s"; + +/** How long a boot-time index drop waits for its lock. */ +export const BOOT_DROP_LOCK_TIMEOUT = "5s"; + +/** An identifier this script splices into SQL: lower-case catalog names only. */ +const IDENTIFIER = /^[a-z_][a-z0-9_]{0,62}$/; + +function say(message) { + process.stderr.write(`HealthLog: ${message}\n`); +} + +/** Double-quote an identifier after checking its shape. */ +function ident(name) { + if (!IDENTIFIER.test(name)) { + throw new Error("refusing to splice an identifier of unexpected shape"); + } + return `"${name}"`; +} + +/** The role's password: 64 hex characters, the same in every container. */ +export function appRolePassword(hmacKey) { + if (!hmacKey) throw new Error("API_TOKEN_HMAC_KEY is not set"); + return createHmac("sha256", hmacKey).update(PASSWORD_LABEL).digest("hex"); +} + +/** + * A SCRAM-SHA-256 verifier in the form `pg_authid.rolpassword` stores + * (RFC 5802/7677; the password is ASCII hex, so SASLprep leaves it as is). + * Postgres takes a string of this shape as already hashed. + */ +export function scramVerifier( + password, + salt = randomBytes(16), + iterations = 4096, +) { + const salted = pbkdf2Sync(password, salt, iterations, 32, "sha256"); + const clientKey = createHmac("sha256", salted).update("Client Key").digest(); + const storedKey = createHash("sha256").update(clientKey).digest(); + const serverKey = createHmac("sha256", salted).update("Server Key").digest(); + return `SCRAM-SHA-256$${iterations}:${salt.toString("base64")}$${storedKey.toString("base64")}:${serverKey.toString("base64")}`; +} + +/** The owner's URL with the role's name and password: same host, database and parameters. */ +export function appRoleUrl(ownerUrl, password) { + const url = new URL(ownerUrl); + url.username = APP_ROLE; + url.password = password; + return url.toString(); +} + +/** The user a URL names, for the notices. Never the password. */ +function userOf(databaseUrl) { + try { + return decodeURIComponent(new URL(databaseUrl).username) || "(default)"; + } catch { + return "(unparsable)"; + } +} + +function errorText(err) { + const code = err?.code; + const message = err instanceof Error ? err.message : String(err); + return typeof code === "string" ? `${code} ${message}` : message; +} + +/** + * Whether the connected user can set the role up, and why not when it + * cannot. Read-only. + * + * @param {{ query: Function }} client + * @returns {Promise<{ ok: true, superuser: boolean } | { ok: false, reason: string, detail: string }>} + */ +export async function checkPreconditions(client) { + const { rows } = await client.query( + `SELECT current_setting('server_version_num')::int AS version, + r.rolsuper AS superuser, + r.rolcreaterole AS createrole, + current_user AS me + FROM pg_roles r WHERE r.rolname = current_user`, + ); + const me = rows[0]; + if (me.me === APP_ROLE) { + return { + ok: false, + reason: "already_app_role", + detail: `DATABASE_URL already names ${APP_ROLE}`, + }; + } + if (me.version < MIN_SERVER_VERSION_NUM) { + return { + ok: false, + reason: "server_too_old", + detail: `Postgres ${Math.floor(me.version / 10000)} has no MAINTAIN privilege (17 or newer does)`, + }; + } + if (!me.superuser && !me.createrole) { + return { + ok: false, + reason: "cannot_create_roles", + detail: `the database user ${me.me} may not create roles (a managed or external database, or a user without CREATEROLE)`, + }; + } + const existing = await client.query( + `SELECT shobj_description(r.oid, 'pg_authid') AS comment, + pg_has_role(r.oid, current_user, 'MEMBER') AS member_of_owner, + r.rolsuper OR r.rolreplication OR r.rolbypassrls AS elevated + FROM pg_roles r WHERE r.rolname = $1`, + [APP_ROLE], + ); + const role = existing.rows[0]; + if (role && role.comment !== ROLE_COMMENT) { + return { + ok: false, + reason: "foreign_role", + detail: `a role named ${APP_ROLE} exists that HealthLog did not create`, + }; + } + if (role?.member_of_owner) { + return { + ok: false, + reason: "role_inherits_owner", + detail: `${APP_ROLE} is a member of ${me.me}, so it would hold the owner's rights`, + }; + } + if (role?.elevated && !me.superuser) { + return { + ok: false, + reason: "role_elevated", + detail: `${APP_ROLE} has SUPERUSER, REPLICATION or BYPASSRLS, and only a superuser can take it away`, + }; + } + return { ok: true, superuser: me.superuser }; +} + +/** + * Create or update the role and apply every grant, in one transaction. + * Call it on a client connected as the owner, after the migrations. + * + * @param {{ query: Function }} client + * @param {{ password: string, schema?: string, superuser: boolean }} options + */ +export async function applyAppRole(client, options) { + const schema = options.schema ?? "public"; + const role = ident(APP_ROLE); + const app = ident(schema); + const queue = ident(QUEUE_SCHEMA); + // The verifier is a base64/`$`/`:` string; it never contains a quote. + const verifier = scramVerifier(options.password); + if (verifier.includes("'")) throw new Error("unexpected verifier shape"); + + await client.query("BEGIN"); + try { + await client.query(`SET LOCAL lock_timeout = '${SETUP_LOCK_TIMEOUT}'`); + await client.query( + `SELECT pg_advisory_xact_lock(hashtext('healthlog.db-app-role'))`, + ); + + const { rows: present } = await client.query( + `SELECT 1 FROM pg_roles WHERE rolname = $1`, + [APP_ROLE], + ); + // The attributes a superuser alone may set are named only by one; a + // role a CREATEROLE user creates never has them (checked beforehand). + const elevatedOff = options.superuser + ? " NOSUPERUSER NOREPLICATION NOBYPASSRLS" + : ""; + const attributes = `LOGIN NOCREATEDB NOCREATEROLE NOINHERIT${elevatedOff}`; + if (present.length === 0) { + await client.query( + `CREATE ROLE ${role} ${attributes} PASSWORD '${verifier}'`, + ); + } else { + await client.query( + `ALTER ROLE ${role} ${attributes} PASSWORD '${verifier}'`, + ); + } + await client.query( + `COMMENT ON ROLE ${role} IS '${ROLE_COMMENT.replace(/'/g, "''")}'`, + ); + + // A non-superuser owner hands objects to the role only when it may act + // as it (Postgres 16+), and must keep reading what the role owns: the + // dump before a migration reads the queue schema too. The membership + // runs owner -> role, never the other way. + if (!options.superuser) { + await client.query( + `GRANT ${role} TO CURRENT_USER WITH INHERIT TRUE, SET TRUE`, + ); + } + + const { rows: db } = await client.query( + `SELECT current_database() AS name`, + ); + await client.query( + `GRANT CONNECT, TEMPORARY ON DATABASE "${String(db[0].name).replace(/"/g, '""')}" TO ${role}`, + ); + + // The app's schema: rows, never structure. + await client.query(`GRANT USAGE ON SCHEMA ${app} TO ${role}`); + await client.query(`REVOKE CREATE ON SCHEMA ${app} FROM ${role}`); + const { rows: schemaOwner } = await client.query( + `SELECT pg_has_role(current_user, nspowner, 'USAGE') AS owns + FROM pg_namespace WHERE nspname = $1`, + [schema], + ); + if (options.superuser || schemaOwner[0]?.owns) { + await client.query(`REVOKE CREATE ON SCHEMA ${app} FROM PUBLIC`); + } else { + say( + `notice: the schema ${schema} is not the database user's to change; PUBLIC may still create objects in it`, + ); + } + + const { rows: tables } = await client.query( + `SELECT c.relname AS name + FROM pg_class c + JOIN pg_namespace n ON n.oid = c.relnamespace + WHERE n.nspname = $1 AND c.relkind IN ('r', 'p', 'v', 'm', 'f') + AND c.relname <> ALL($3::text[]) + AND NOT (has_table_privilege($2, c.oid, 'SELECT') + AND has_table_privilege($2, c.oid, 'INSERT') + AND has_table_privilege($2, c.oid, 'UPDATE') + AND has_table_privilege($2, c.oid, 'DELETE'))`, + [schema, APP_ROLE, READ_ONLY_TABLES], + ); + for (const { name } of tables) { + await client.query( + `GRANT SELECT, INSERT, UPDATE, DELETE ON ${app}.${ident(name)} TO ${role}`, + ); + } + for (const name of READ_ONLY_TABLES) { + const { rows } = await client.query( + `SELECT to_regclass($1) IS NOT NULL AS present`, + [`${app}.${ident(name)}`], + ); + if (!rows[0].present) continue; + await client.query( + `REVOKE INSERT, UPDATE, DELETE, TRUNCATE ON ${app}.${ident(name)} FROM ${role}`, + ); + await client.query(`GRANT SELECT ON ${app}.${ident(name)} TO ${role}`); + } + + const { rows: sequences } = await client.query( + `SELECT c.relname AS name + FROM pg_class c + JOIN pg_namespace n ON n.oid = c.relnamespace + WHERE n.nspname = $1 AND c.relkind = 'S' + AND NOT (has_sequence_privilege($2, c.oid, 'USAGE') + AND has_sequence_privilege($2, c.oid, 'SELECT') + AND has_sequence_privilege($2, c.oid, 'UPDATE'))`, + [schema, APP_ROLE], + ); + for (const { name } of sequences) { + await client.query( + `GRANT USAGE, SELECT, UPDATE ON SEQUENCE ${app}.${ident(name)} TO ${role}`, + ); + } + + // Objects the owner creates later in this schema (the migrations of the + // next update) are granted at creation as well. The per-boot pass above + // is what the app relies on; this covers the time between the two. + await client.query( + `ALTER DEFAULT PRIVILEGES IN SCHEMA ${app} GRANT SELECT, INSERT, UPDATE, DELETE ON TABLES TO ${role}`, + ); + await client.query( + `ALTER DEFAULT PRIVILEGES IN SCHEMA ${app} GRANT USAGE, SELECT, UPDATE ON SEQUENCES TO ${role}`, + ); + + for (const name of MAINTAINED_TABLES) { + const { rows } = await client.query( + `SELECT to_regclass($1) IS NOT NULL AS present`, + [`${app}.${ident(name)}`], + ); + if (rows[0].present) { + await client.query( + `GRANT MAINTAIN ON ${app}.${ident(name)} TO ${role}`, + ); + } + } + + // The queue's schema belongs to the role: pg-boss creates its tables, + // functions and partitions there at runtime. On the first boot after an + // update, and after a restore, everything in it still belongs to the + // owner and is handed over once. + await client.query( + `CREATE SCHEMA IF NOT EXISTS ${queue} AUTHORIZATION ${role}`, + ); + await client.query(`ALTER SCHEMA ${queue} OWNER TO ${role}`); + await transferQueueObjects(client, role); + + await client.query("COMMIT"); + } catch (err) { + await client.query("ROLLBACK").catch(() => {}); + throw err; + } +} + +/** Hand every object in the queue schema the role does not own to it. */ +async function transferQueueObjects(client, role) { + const { rows: relations } = await client.query( + `SELECT c.oid::regclass::text AS name, c.relkind AS kind + FROM pg_class c + JOIN pg_namespace n ON n.oid = c.relnamespace + WHERE n.nspname = $1 + AND c.relowner <> (SELECT oid FROM pg_roles WHERE rolname = $2) + AND c.relkind IN ('r', 'p', 'v', 'm', 'f', 'S') + -- A sequence a column owns follows its table. + AND NOT (c.relkind = 'S' AND EXISTS ( + SELECT 1 FROM pg_depend d + WHERE d.classid = 'pg_class'::regclass AND d.objid = c.oid + AND d.deptype IN ('a', 'i'))) + ORDER BY c.relkind = 'r' DESC, c.oid`, + [QUEUE_SCHEMA, APP_ROLE], + ); + for (const { name, kind } of relations) { + const what = + kind === "S" + ? "SEQUENCE" + : kind === "v" + ? "VIEW" + : kind === "m" + ? "MATERIALIZED VIEW" + : kind === "f" + ? "FOREIGN TABLE" + : "TABLE"; + // `regclass::text` is the catalog's own quoting of the name. + await client.query(`ALTER ${what} ${name} OWNER TO ${role}`); + } + + const { rows: routines } = await client.query( + `SELECT p.oid::regprocedure::text AS signature + FROM pg_proc p + JOIN pg_namespace n ON n.oid = p.pronamespace + WHERE n.nspname = $1 + AND p.proowner <> (SELECT oid FROM pg_roles WHERE rolname = $2)`, + [QUEUE_SCHEMA, APP_ROLE], + ); + for (const { signature } of routines) { + await client.query(`ALTER ROUTINE ${signature} OWNER TO ${role}`); + } + + // Enums, domains and free-standing composite types; a table's row type + // and an array type follow their owner object. + const { rows: types } = await client.query( + `SELECT t.oid::regtype::text AS name, t.typtype AS kind + FROM pg_type t + JOIN pg_namespace n ON n.oid = t.typnamespace + LEFT JOIN pg_class c ON c.oid = t.typrelid + WHERE n.nspname = $1 + AND t.typowner <> (SELECT oid FROM pg_roles WHERE rolname = $2) + AND t.typelem = 0 + AND (t.typtype IN ('e', 'd', 'r') OR (t.typtype = 'c' AND c.relkind = 'c'))`, + [QUEUE_SCHEMA, APP_ROLE], + ); + for (const { name, kind } of types) { + await client.query( + `ALTER ${kind === "d" ? "DOMAIN" : "TYPE"} ${name} OWNER TO ${role}`, + ); + } +} + +/** + * Drop, as the owner, the indexes on `measurements` the maintenance job can + * no longer drop as the role: the retired ones and the invalid copies of a + * concurrent rebuild. Each waits at most {@link BOOT_DROP_LOCK_TIMEOUT}; one + * that does not get its lock is left for the next boot. + * + * @param {{ query: Function }} client a connection outside any transaction + * @returns {Promise<{ dropped: string[], left: string[] }>} + */ +export async function dropOwnerOnlyIndexes(client) { + const dropped = []; + const left = []; + const { rows: table } = await client.query( + `SELECT to_regclass('measurements') IS NOT NULL AS present`, + ); + if (!table[0].present) return { dropped, left }; + const { rows } = await client.query( + `SELECT c.relname AS name, i.indisvalid AS valid + FROM pg_index i + JOIN pg_class c ON c.oid = i.indexrelid + WHERE i.indrelid = 'measurements'::regclass`, + ); + const targets = rows + .filter( + (r) => + RETIRED_MEASUREMENT_INDEXES.includes(r.name) || + (!r.valid && CONCURRENT_COPY.test(r.name)), + ) + .map((r) => r.name); + if (targets.length === 0) return { dropped, left }; + const { rows: setting } = await client.query( + `SELECT current_setting('lock_timeout') AS value`, + ); + try { + await client.query(`SET lock_timeout = '${BOOT_DROP_LOCK_TIMEOUT}'`); + for (const name of targets) { + try { + await client.query(`DROP INDEX CONCURRENTLY IF EXISTS ${ident(name)}`); + dropped.push(name); + } catch (err) { + left.push(name); + say( + `notice: index ${name} on measurements was not dropped (${errorText(err)}); the next start tries again`, + ); + } + } + } finally { + await client.query(`SELECT set_config('lock_timeout', $1, false)`, [ + setting[0]?.value ?? "0", + ]); + } + return { dropped, left }; +} + +/** Log in as the role once, so a pg_hba.conf that refuses it shows here. */ +async function proveLogin(url) { + const client = await connect(url); + try { + const { rows } = await client.query(`SELECT current_user AS me`); + if (rows[0].me !== APP_ROLE) { + throw new Error(`logged in as ${rows[0].me}, not ${APP_ROLE}`); + } + } finally { + await client.end().catch(() => {}); + } +} + +/** Write the URL to descriptor 3 when the caller opened it. */ +function handOver(url) { + try { + writeSync(3, url); + return true; + } catch { + return false; + } +} + +/** + * The boot step. Returns the role's URL when the app should use it, or null + * to stay on the owner. + * + * @param {NodeJS.ProcessEnv} env + * @returns {Promise} + */ +export async function ensureAppRole(env = process.env) { + const ownerUrl = env.DATABASE_URL; + const mode = (env.DB_APP_ROLE ?? "").trim().toLowerCase(); + if (mode === "off" || mode === "false") { + say( + `DB_APP_ROLE=off: the app connects as ${userOf(ownerUrl)}, the user DATABASE_URL names`, + ); + return null; + } + if (mode && mode !== "auto" && mode !== "on") { + say( + `notice: DB_APP_ROLE="${mode}" is not auto or off; treating it as auto`, + ); + } + if (!ownerUrl) return null; + + const user = userOf(ownerUrl); + const fallBack = (detail) => { + say( + `notice: the app connects as ${user}, the user DATABASE_URL names, not as the restricted role ${APP_ROLE}: ${detail}. ` + + "This is how every earlier release ran. " + + `If ${user} is a restricted role you manage yourself, DB_APP_ROLE=off silences this; otherwise see docs/self-hosting/database-role.md.`, + ); + return null; + }; + + let client; + try { + client = await connect(ownerUrl); + } catch (err) { + return fallBack(`could not connect to set it up (${errorText(err)})`); + } + try { + const pre = await checkPreconditions(client); + if (!pre.ok) { + if (pre.reason === "already_app_role") { + say(`DATABASE_URL already names ${APP_ROLE}; nothing to set up`); + return null; + } + return fallBack(pre.detail); + } + const password = appRolePassword(env.API_TOKEN_HMAC_KEY); + const schema = new URL(ownerUrl).searchParams.get("schema") || "public"; + try { + await applyAppRole(client, { + password, + schema, + superuser: pre.superuser, + }); + } catch (err) { + return fallBack(`setting it up failed (${errorText(err)})`); + } + const url = appRoleUrl(ownerUrl, password); + try { + await proveLogin(url); + } catch (err) { + return fallBack( + `${APP_ROLE} cannot log in (${errorText(err)}); a pg_hba.conf that lists users by name needs a line for it`, + ); + } + const { dropped } = await dropOwnerOnlyIndexes(client); + if (dropped.length > 0) { + say(`dropped index ${dropped.join(", ")} on measurements`); + } + say( + `the app connects as ${APP_ROLE}: rows and the queue, no schema changes (DB_APP_ROLE=off turns this off)`, + ); + return url; + } catch (err) { + return fallBack(`the check failed (${errorText(err)})`); + } finally { + await client.end().catch(() => {}); + } +} + +export async function main(env = process.env) { + const url = await ensureAppRole(env); + if (url && !handOver(url)) { + say( + "the role is ready; the URL goes to file descriptor 3, which this run did not open", + ); + } + return 0; +} + +if (import.meta.url === pathToFileURL(process.argv[1] ?? "").href) { + main().then( + (code) => process.exit(code), + (err) => { + say(`notice: the database role step failed (${errorText(err)})`); + process.exit(0); + }, + ); +} diff --git a/scripts/env-manifest.json b/scripts/env-manifest.json index 70546fd43..977a50755 100644 --- a/scripts/env-manifest.json +++ b/scripts/env-manifest.json @@ -225,6 +225,11 @@ { "name": "DATABASE_SESSION_OPTIONS_DISABLED", "purpose": "Set to 1, true or yes to send no session settings (statement timeout, work_mem) as the libpq options startup parameter. Needed behind PgBouncer, which refuses that parameter unless it is in ignore_startup_parameters." + }, + { + "name": "DB_APP_ROLE", + "purpose": "auto (default) or off. Auto: after the migrations the entrypoint creates the role healthlog_app, which may read and write rows and run the queue but not change the schema, and starts the app with it in place of the DATABASE_URL user. Off keeps the app on the DATABASE_URL user, for an operator who manages database roles.", + "example": "off" } ] }, diff --git a/src/__tests__/api/analytics/since-cap.test.ts b/src/__tests__/api/analytics/since-cap.test.ts index 1c9c0f996..0bfd4adb1 100644 --- a/src/__tests__/api/analytics/since-cap.test.ts +++ b/src/__tests__/api/analytics/since-cap.test.ts @@ -46,10 +46,6 @@ vi.mock("@/lib/auth/audit", () => ({ auditLog: vi.fn().mockResolvedValue(undefined), })); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - vi.mock("@/lib/logging/transports", () => ({ emitIfSampled: vi.fn() })); // The slim slice now strips disabled-module types before answering, from diff --git a/src/__tests__/api/auth/login/mfa-branch.test.ts b/src/__tests__/api/auth/login/mfa-branch.test.ts index 1b9a644e1..3fdb91dd0 100644 --- a/src/__tests__/api/auth/login/mfa-branch.test.ts +++ b/src/__tests__/api/auth/login/mfa-branch.test.ts @@ -23,9 +23,6 @@ vi.mock("@/lib/auth/audit", () => ({ auditLog: vi.fn().mockResolvedValue(undefined), })); vi.mock("@/lib/auth/hmac", () => ({ hashToken: vi.fn(() => "h") })); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); vi.mock("@/lib/logging/transports", () => ({ emitIfSampled: vi.fn() })); vi.mock("@/lib/rate-limit", () => ({ checkAuthSurfaceRateLimit: vi.fn().mockResolvedValue({ diff --git a/src/__tests__/api/auth/mfa/verify.test.ts b/src/__tests__/api/auth/mfa/verify.test.ts index 094614336..d23956b80 100644 --- a/src/__tests__/api/auth/mfa/verify.test.ts +++ b/src/__tests__/api/auth/mfa/verify.test.ts @@ -3,9 +3,6 @@ import { describe, it, expect, vi, beforeEach } from "vitest"; vi.mock("@/lib/db", () => ({ prisma: { user: { findUnique: vi.fn() } }, })); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); vi.mock("@/lib/logging/transports", () => ({ emitIfSampled: vi.fn() })); vi.mock("@/lib/auth/audit", () => ({ auditLog: vi.fn().mockResolvedValue(undefined), diff --git a/src/__tests__/api/auth/registration-status/route.test.ts b/src/__tests__/api/auth/registration-status/route.test.ts index 38f04e448..4eac4cf0c 100644 --- a/src/__tests__/api/auth/registration-status/route.test.ts +++ b/src/__tests__/api/auth/registration-status/route.test.ts @@ -37,10 +37,6 @@ vi.mock("@/lib/auth/audit", () => ({ auditLog: vi.fn().mockResolvedValue(undefined), })); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - vi.mock("@/lib/logging/transports", () => ({ emitIfSampled: vi.fn() })); vi.mock("next/headers", () => ({ diff --git a/src/__tests__/baselines/version-stamp-comments.json b/src/__tests__/baselines/version-stamp-comments.json index 69c0ee030..b95f224f2 100644 --- a/src/__tests__/baselines/version-stamp-comments.json +++ b/src/__tests__/baselines/version-stamp-comments.json @@ -1959,7 +1959,6 @@ "lib/day/values.ts": 1, "lib/day/visit-preparation.ts": 1, "lib/day/wire-schemas.ts": 1, - "lib/db-compat.ts": 1, "lib/devices/__tests__/revoke.test.ts": 1, "lib/devices/revoke.ts": 1, "lib/doctor-report-helpers.ts": 1, diff --git a/src/__tests__/container-scripts-ship-guard.test.ts b/src/__tests__/container-scripts-ship-guard.test.ts index 629a62f48..a7db951d9 100644 --- a/src/__tests__/container-scripts-ship-guard.test.ts +++ b/src/__tests__/container-scripts-ship-guard.test.ts @@ -74,9 +74,11 @@ function entrypointScripts(): string[] { const entrypoint = readFileSync(join(ROOT, "docker-entrypoint.sh"), "utf8"); return [ ...new Set( - [...entrypoint.matchAll(/^\s*node\s+(scripts\/[\w.-]+)/gm)].map( - (m) => m[1], - ), + // A line that starts with the call, or a command substitution that + // makes it (`url="$(node scripts/db-app-role.mjs …)"`). + [ + ...entrypoint.matchAll(/(?:^\s*|\$\(\s*)node\s+(scripts\/[\w.-]+)/gm), + ].map((m) => m[1]), ), ].sort(); } @@ -126,6 +128,7 @@ describe("scripts the entrypoint runs ship in the image", () => { it("finds the boot scripts it is meant to check", () => { // An empty match would agree with any Dockerfile. expect(entrypointScripts()).toContain("scripts/pending-migrations.mjs"); + expect(entrypointScripts()).toContain("scripts/db-app-role.mjs"); }); it("copies every boot script and its local imports into the runner stage", () => { diff --git a/src/__tests__/sql-now-utc-guard.test.ts b/src/__tests__/sql-now-utc-guard.test.ts index 4dca58fec..8875c0007 100644 --- a/src/__tests__/sql-now-utc-guard.test.ts +++ b/src/__tests__/sql-now-utc-guard.test.ts @@ -47,10 +47,6 @@ const ALLOWED: Record = { hits: 1, why: "pg-boss tables are timestamptz", }, - "src/lib/db-compat.ts": { - hits: 1, - why: "DDL default on a timestamptz column", - }, }; const SQL_CLOCK = diff --git a/src/__tests__/tz-day-paths-harness.test.ts b/src/__tests__/tz-day-paths-harness.test.ts index edd870974..6be62ece6 100644 --- a/src/__tests__/tz-day-paths-harness.test.ts +++ b/src/__tests__/tz-day-paths-harness.test.ts @@ -65,9 +65,6 @@ vi.mock("@/lib/rollups/measurement-read", () => ({ vi.mock("@/lib/analytics/mood-series", () => ({ buildMoodDailySeries: vi.fn(), })); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); vi.mock("next/headers", () => ({ headers: vi.fn(async () => ({ get: () => null })), cookies: vi.fn(async () => ({ diff --git a/src/app/api/admin/import-apple-health-export/__tests__/route.test.ts b/src/app/api/admin/import-apple-health-export/__tests__/route.test.ts index fcb453ed6..dcbada60d 100644 --- a/src/app/api/admin/import-apple-health-export/__tests__/route.test.ts +++ b/src/app/api/admin/import-apple-health-export/__tests__/route.test.ts @@ -12,9 +12,6 @@ vi.mock("@/lib/auth/audit", () => ({ auditLog: vi.fn().mockResolvedValue(undefined), })); vi.mock("@/lib/logging/transports", () => ({ emitIfSampled: vi.fn() })); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); vi.mock("next/headers", () => ({ headers: vi.fn(async () => ({ get: () => null })), cookies: vi.fn(async () => ({ diff --git a/src/app/api/admin/maintenance/measurements/__tests__/status.test.ts b/src/app/api/admin/maintenance/measurements/__tests__/status.test.ts index b4cb3012e..26de3e9e7 100644 --- a/src/app/api/admin/maintenance/measurements/__tests__/status.test.ts +++ b/src/app/api/admin/maintenance/measurements/__tests__/status.test.ts @@ -12,9 +12,6 @@ vi.mock("@/lib/auth/audit", () => ({ auditLog: vi.fn().mockResolvedValue(undefined), })); vi.mock("@/lib/logging/transports", () => ({ emitIfSampled: vi.fn() })); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); vi.mock("next/headers", () => ({ headers: vi.fn(async () => ({ get: () => null })), cookies: vi.fn(async () => ({ diff --git a/src/app/api/admin/maintenance/pulse-day-mean/__tests__/route.test.ts b/src/app/api/admin/maintenance/pulse-day-mean/__tests__/route.test.ts index 26c89266e..e3c764f42 100644 --- a/src/app/api/admin/maintenance/pulse-day-mean/__tests__/route.test.ts +++ b/src/app/api/admin/maintenance/pulse-day-mean/__tests__/route.test.ts @@ -18,9 +18,6 @@ vi.mock("@/lib/auth/audit", () => ({ })); vi.mock("@/lib/jobs/boss-instance", () => ({ getGlobalBoss: vi.fn() })); vi.mock("@/lib/logging/transports", () => ({ emitIfSampled: vi.fn() })); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); vi.mock("next/headers", () => ({ headers: vi.fn(async () => ({ get: () => null })), cookies: vi.fn(async () => ({ diff --git a/src/app/api/admin/settings/assistant-flags/__tests__/route.test.ts b/src/app/api/admin/settings/assistant-flags/__tests__/route.test.ts index 350c54de8..c23eb48c5 100644 --- a/src/app/api/admin/settings/assistant-flags/__tests__/route.test.ts +++ b/src/app/api/admin/settings/assistant-flags/__tests__/route.test.ts @@ -15,9 +15,6 @@ vi.mock("@/lib/auth/audit", () => ({ auditLog: vi.fn().mockResolvedValue(undefined), })); vi.mock("@/lib/logging/transports", () => ({ emitIfSampled: vi.fn() })); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); vi.mock("next/headers", () => ({ headers: vi.fn(async () => ({ get: () => null })), cookies: vi.fn(async () => ({ diff --git a/src/app/api/admin/settings/module-availability/__tests__/route.test.ts b/src/app/api/admin/settings/module-availability/__tests__/route.test.ts index 846061632..fa2f7278e 100644 --- a/src/app/api/admin/settings/module-availability/__tests__/route.test.ts +++ b/src/app/api/admin/settings/module-availability/__tests__/route.test.ts @@ -15,9 +15,6 @@ vi.mock("@/lib/auth/audit", () => ({ auditLog: vi.fn().mockResolvedValue(undefined), })); vi.mock("@/lib/logging/transports", () => ({ emitIfSampled: vi.fn() })); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); vi.mock("next/headers", () => ({ headers: vi.fn(async () => ({ get: () => null })), cookies: vi.fn(async () => ({ diff --git a/src/app/api/analytics/__tests__/route.test.ts b/src/app/api/analytics/__tests__/route.test.ts index 068af6252..c04a111c9 100644 --- a/src/app/api/analytics/__tests__/route.test.ts +++ b/src/app/api/analytics/__tests__/route.test.ts @@ -75,10 +75,6 @@ vi.mock("@/lib/auth/audit", () => ({ vi.mock("@/lib/logging/transports", () => ({ emitIfSampled: vi.fn() })); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - vi.mock("@/lib/insights/correlation-patterns", () => ({ PATTERN_FAMILIES: { fixed: "FIXED" }, syncAcceptedPatterns: vi.fn().mockResolvedValue(new Map()), diff --git a/src/app/api/auth/login/__tests__/constant-work.test.ts b/src/app/api/auth/login/__tests__/constant-work.test.ts index a41edac7b..39446e467 100644 --- a/src/app/api/auth/login/__tests__/constant-work.test.ts +++ b/src/app/api/auth/login/__tests__/constant-work.test.ts @@ -58,10 +58,6 @@ vi.mock("@/lib/rate-limit", () => ({ refundRateLimit: vi.fn(async () => undefined), })); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - vi.mock("@/lib/auth/hmac", () => ({ hashToken: vi.fn(() => "aa".repeat(32)), })); diff --git a/src/app/api/auth/login/__tests__/native-token.test.ts b/src/app/api/auth/login/__tests__/native-token.test.ts index 4478b89eb..c0ca5e861 100644 --- a/src/app/api/auth/login/__tests__/native-token.test.ts +++ b/src/app/api/auth/login/__tests__/native-token.test.ts @@ -61,10 +61,6 @@ vi.mock("@/lib/rate-limit", () => ({ refundRateLimit: vi.fn(async () => undefined), })); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - vi.mock("@/lib/auth/hmac", () => ({ hashToken: vi.fn((raw: string) => `hashed:${raw}`), })); @@ -90,7 +86,6 @@ import { checkAuthSurfaceRateLimit, rateLimitHeaders, } from "@/lib/rate-limit"; -import { ensureDbCompatibility } from "@/lib/db-compat"; import { auditLog } from "@/lib/auth/audit"; import { createSession } from "@/lib/auth/session"; @@ -136,7 +131,6 @@ beforeEach(() => { ip: "203.0.113.1", } as never); vi.mocked(rateLimitHeaders).mockReturnValue({} as never); - vi.mocked(ensureDbCompatibility).mockResolvedValue(undefined); vi.mocked(auditLog).mockResolvedValue(undefined as never); vi.mocked(createSession).mockResolvedValue("session-id"); }); diff --git a/src/app/api/auth/login/__tests__/route.test.ts b/src/app/api/auth/login/__tests__/route.test.ts index e9c8e3298..5de021855 100644 --- a/src/app/api/auth/login/__tests__/route.test.ts +++ b/src/app/api/auth/login/__tests__/route.test.ts @@ -52,10 +52,6 @@ vi.mock("@/lib/rate-limit", () => ({ rateLimitHeaders: vi.fn(() => ({})), })); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - vi.mock("@/lib/auth/hmac", () => ({ // Return a deterministic hex string that does NOT echo the raw // value — mirrors the real HMAC-SHA256 shape. The audit row's @@ -88,7 +84,6 @@ import { checkAuthSurfaceRateLimit, rateLimitHeaders, } from "@/lib/rate-limit"; -import { ensureDbCompatibility } from "@/lib/db-compat"; const TYPED_EMAIL = "leaked-identifier@example.com"; @@ -117,7 +112,6 @@ beforeEach(() => { ip: "1.2.3.4", } as never); vi.mocked(rateLimitHeaders).mockReturnValue({} as never); - vi.mocked(ensureDbCompatibility).mockResolvedValue(undefined); }); describe("POST /api/auth/login — auth.login.failed audit row (H-1)", () => { diff --git a/src/app/api/auth/login/__tests__/trusted-device.test.ts b/src/app/api/auth/login/__tests__/trusted-device.test.ts index 95b7a3492..49d89ff87 100644 --- a/src/app/api/auth/login/__tests__/trusted-device.test.ts +++ b/src/app/api/auth/login/__tests__/trusted-device.test.ts @@ -52,10 +52,6 @@ vi.mock("@/lib/rate-limit", () => ({ refundRateLimit: vi.fn(async () => undefined), })); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - vi.mock("@/lib/auth/hmac", () => ({ hashToken: vi.fn(() => "h") })); vi.mock("@/lib/logging/transports", () => ({ emitIfSampled: vi.fn() })); vi.mock("next/headers", () => ({ diff --git a/src/app/api/auth/login/route.ts b/src/app/api/auth/login/route.ts index 4c8927f91..0f11f9daf 100644 --- a/src/app/api/auth/login/route.ts +++ b/src/app/api/auth/login/route.ts @@ -11,7 +11,6 @@ import { } from "@/lib/api-response"; import { checkAuthSurfaceRateLimit, rateLimitHeaders } from "@/lib/rate-limit"; import { beginAccountLoginAttempt } from "@/lib/auth/login-throttle"; -import { ensureDbCompatibility } from "@/lib/db-compat"; import { NextRequest, NextResponse } from "next/server"; import { apiHandler } from "@/lib/api-handler"; import { annotate } from "@/lib/logging/context"; @@ -59,8 +58,6 @@ export const POST = apiHandler(async (request: NextRequest) => { ); } - await ensureDbCompatibility(); - const { data: body, error: jsonError } = await safeJson(request, { maxBytes: 64 * 1024, }); diff --git a/src/app/api/auth/mfa/verify/route.ts b/src/app/api/auth/mfa/verify/route.ts index 9ee262970..25cb920de 100644 --- a/src/app/api/auth/mfa/verify/route.ts +++ b/src/app/api/auth/mfa/verify/route.ts @@ -27,7 +27,6 @@ import { apiHandler } from "@/lib/api-handler"; import { annotate } from "@/lib/logging/context"; import { auditLog } from "@/lib/auth/audit"; import { prisma } from "@/lib/db"; -import { ensureDbCompatibility } from "@/lib/db-compat"; import { checkAuthSurfaceRateLimit, rateLimitHeaders } from "@/lib/rate-limit"; import { finishLogin } from "@/lib/auth/login-response"; import { @@ -59,8 +58,6 @@ export const POST = apiHandler(async (request: NextRequest) => { }); } - await ensureDbCompatibility(); - const { data: body, error: jsonError } = await safeJson(request, { maxBytes: 16 * 1024, }); diff --git a/src/app/api/auth/mfa/webauthn/verify/__tests__/route.test.ts b/src/app/api/auth/mfa/webauthn/verify/__tests__/route.test.ts index fa86f7987..cf7f1ddf8 100644 --- a/src/app/api/auth/mfa/webauthn/verify/__tests__/route.test.ts +++ b/src/app/api/auth/mfa/webauthn/verify/__tests__/route.test.ts @@ -14,10 +14,6 @@ vi.mock("@/lib/db", () => ({ prisma: { user: { findUnique: vi.fn() } }, })); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - vi.mock("@/lib/rate-limit", () => ({ checkAuthSurfaceRateLimit: vi.fn(), rateLimitHeaders: vi.fn(() => ({})), diff --git a/src/app/api/auth/mfa/webauthn/verify/options/route.ts b/src/app/api/auth/mfa/webauthn/verify/options/route.ts index 2cd02aa6d..c6c8edd76 100644 --- a/src/app/api/auth/mfa/webauthn/verify/options/route.ts +++ b/src/app/api/auth/mfa/webauthn/verify/options/route.ts @@ -16,7 +16,6 @@ import { apiHandler } from "@/lib/api-handler"; import { apiError, apiSuccess } from "@/lib/api-response"; import { parseJsonBody } from "@/lib/api/body"; import { annotate } from "@/lib/logging/context"; -import { ensureDbCompatibility } from "@/lib/db-compat"; import { checkAuthSurfaceRateLimit, rateLimitHeaders } from "@/lib/rate-limit"; import { loadActiveChallenge } from "@/lib/auth/mfa/challenge"; import { createMfaAuthenticationOptions } from "@/lib/auth/mfa/webauthn"; @@ -37,8 +36,6 @@ export const POST = apiHandler(async (request: NextRequest) => { }); } - await ensureDbCompatibility(); - const parsed = await parseJsonBody(request, mfaWebauthnLoginOptionsSchema, { maxBytes: 16 * 1024, message: "Invalid request", diff --git a/src/app/api/auth/mfa/webauthn/verify/route.ts b/src/app/api/auth/mfa/webauthn/verify/route.ts index d548c9c08..a19585bfe 100644 --- a/src/app/api/auth/mfa/webauthn/verify/route.ts +++ b/src/app/api/auth/mfa/webauthn/verify/route.ts @@ -25,7 +25,6 @@ import { import { annotate } from "@/lib/logging/context"; import { auditLog } from "@/lib/auth/audit"; import { prisma } from "@/lib/db"; -import { ensureDbCompatibility } from "@/lib/db-compat"; import { checkAuthSurfaceRateLimit, rateLimitHeaders } from "@/lib/rate-limit"; import { finishLogin } from "@/lib/auth/login-response"; import { @@ -57,8 +56,6 @@ export const POST = apiHandler(async (request: NextRequest) => { }); } - await ensureDbCompatibility(); - const { data: body, error: jsonError } = await safeJson(request, { maxBytes: 64 * 1024, }); diff --git a/src/app/api/auth/native/token/__tests__/route.test.ts b/src/app/api/auth/native/token/__tests__/route.test.ts index ea0f1361f..b1f733168 100644 --- a/src/app/api/auth/native/token/__tests__/route.test.ts +++ b/src/app/api/auth/native/token/__tests__/route.test.ts @@ -12,10 +12,6 @@ vi.mock("@/lib/db", () => ({ prisma: { user: { findUnique: vi.fn() } }, })); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - vi.mock("@/lib/rate-limit", () => ({ checkAuthSurfaceRateLimit: vi.fn(), rateLimitHeaders: vi.fn(() => ({})), diff --git a/src/app/api/auth/native/token/route.ts b/src/app/api/auth/native/token/route.ts index 606cfba38..f0199e82a 100644 --- a/src/app/api/auth/native/token/route.ts +++ b/src/app/api/auth/native/token/route.ts @@ -26,7 +26,6 @@ import { apiHandler } from "@/lib/api-handler"; import { annotate } from "@/lib/logging/context"; import { auditLog } from "@/lib/auth/audit"; import { prisma } from "@/lib/db"; -import { ensureDbCompatibility } from "@/lib/db-compat"; import { checkAuthSurfaceRateLimit, rateLimitHeaders } from "@/lib/rate-limit"; import { isCookielessNativeCaller } from "@/lib/auth/native-client"; import { isNativeClientRequest } from "@/lib/auth/issue-token"; @@ -74,8 +73,6 @@ export const POST = apiHandler(async (request: NextRequest) => { return invalidCode(); } - await ensureDbCompatibility(); - // (3) Body — bounded, then the exact wire contract. const parsed = await parseJsonBody(request, nativeHandoffTokenSchema, { maxBytes: 16 * 1024, diff --git a/src/app/api/auth/oidc/native/token/__tests__/route.test.ts b/src/app/api/auth/oidc/native/token/__tests__/route.test.ts index 6fc48da0a..7b5daa67a 100644 --- a/src/app/api/auth/oidc/native/token/__tests__/route.test.ts +++ b/src/app/api/auth/oidc/native/token/__tests__/route.test.ts @@ -9,10 +9,6 @@ vi.mock("@/lib/db", () => ({ prisma: { user: { findUnique: vi.fn() } }, })); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - vi.mock("@/lib/rate-limit", () => ({ checkAuthSurfaceRateLimit: vi.fn(), rateLimitHeaders: vi.fn(() => ({})), diff --git a/src/app/api/auth/oidc/native/token/route.ts b/src/app/api/auth/oidc/native/token/route.ts index b3d480082..63b8ef1e9 100644 --- a/src/app/api/auth/oidc/native/token/route.ts +++ b/src/app/api/auth/oidc/native/token/route.ts @@ -29,7 +29,6 @@ import { apiHandler } from "@/lib/api-handler"; import { annotate } from "@/lib/logging/context"; import { auditLog } from "@/lib/auth/audit"; import { prisma } from "@/lib/db"; -import { ensureDbCompatibility } from "@/lib/db-compat"; import { checkAuthSurfaceRateLimit, rateLimitHeaders } from "@/lib/rate-limit"; import { isCookielessNativeCaller } from "@/lib/auth/native-client"; import { isNativeClientRequest } from "@/lib/auth/issue-token"; @@ -80,8 +79,6 @@ export const POST = apiHandler(async (request: NextRequest) => { return invalidCode(); } - await ensureDbCompatibility(); - // (3) Body — bounded, then the exact wire contract. const parsed = await parseJsonBody(request, oidcNativeTokenSchema, { maxBytes: 16 * 1024, diff --git a/src/app/api/auth/passkey/login-verify/__tests__/native-token.test.ts b/src/app/api/auth/passkey/login-verify/__tests__/native-token.test.ts index 8256d35f2..b4216edfe 100644 --- a/src/app/api/auth/passkey/login-verify/__tests__/native-token.test.ts +++ b/src/app/api/auth/passkey/login-verify/__tests__/native-token.test.ts @@ -37,10 +37,6 @@ vi.mock("@/lib/rate-limit", () => ({ checkAuthSurfaceRateLimit: vi.fn(), })); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - vi.mock("@/lib/auth/hmac", () => ({ hashToken: vi.fn((raw: string) => `hashed:${raw}`), })); diff --git a/src/app/api/auth/passkey/login-verify/__tests__/oidc-only.test.ts b/src/app/api/auth/passkey/login-verify/__tests__/oidc-only.test.ts index 5d451530f..72263e6ba 100644 --- a/src/app/api/auth/passkey/login-verify/__tests__/oidc-only.test.ts +++ b/src/app/api/auth/passkey/login-verify/__tests__/oidc-only.test.ts @@ -35,10 +35,6 @@ vi.mock("@/lib/rate-limit", () => ({ checkAuthSurfaceRateLimit: vi.fn(), })); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - vi.mock("@/lib/auth/hmac", () => ({ hashToken: vi.fn((raw: string) => `hashed:${raw}`), })); diff --git a/src/app/api/auth/passkey/login-verify/__tests__/refusals.test.ts b/src/app/api/auth/passkey/login-verify/__tests__/refusals.test.ts index a41950f37..b7ff7fee6 100644 --- a/src/app/api/auth/passkey/login-verify/__tests__/refusals.test.ts +++ b/src/app/api/auth/passkey/login-verify/__tests__/refusals.test.ts @@ -31,10 +31,6 @@ vi.mock("@/lib/rate-limit", () => ({ checkAuthSurfaceRateLimit: vi.fn(), })); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - vi.mock("@/lib/logging/transports", () => ({ emitIfSampled: vi.fn() })); vi.mock("next/headers", () => ({ diff --git a/src/app/api/auth/passkey/login-verify/route.ts b/src/app/api/auth/passkey/login-verify/route.ts index 76c6487c4..b65593baf 100644 --- a/src/app/api/auth/passkey/login-verify/route.ts +++ b/src/app/api/auth/passkey/login-verify/route.ts @@ -9,7 +9,6 @@ import { recordSignInDevice } from "@/lib/auth/login-alert"; import { auditLog } from "@/lib/auth/audit"; import { apiSuccess, apiError, safeJson } from "@/lib/api-response"; import { prisma } from "@/lib/db"; -import { ensureDbCompatibility } from "@/lib/db-compat"; import { checkAuthSurfaceRateLimit } from "@/lib/rate-limit"; import { NextRequest } from "next/server"; import { apiHandler } from "@/lib/api-handler"; @@ -71,8 +70,6 @@ export const POST = apiHandler(async (request: NextRequest) => { }); } - await ensureDbCompatibility(); - // v1.4.43 — tighter shared bucket on trust-chain misconfig. const rl = await checkAuthSurfaceRateLimit( request, diff --git a/src/app/api/auth/password/__tests__/route.test.ts b/src/app/api/auth/password/__tests__/route.test.ts index 5cee4d7cd..ab15ac964 100644 --- a/src/app/api/auth/password/__tests__/route.test.ts +++ b/src/app/api/auth/password/__tests__/route.test.ts @@ -63,9 +63,6 @@ vi.mock("@/lib/auth/hibp", () => ({ })); vi.mock("@/lib/logging/transports", () => ({ emitIfSampled: vi.fn() })); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); vi.mock("next/headers", () => ({ headers: vi.fn(async () => ({ get: () => null })), cookies: vi.fn(async () => ({ diff --git a/src/app/api/auth/register/__tests__/route.test.ts b/src/app/api/auth/register/__tests__/route.test.ts index 00611fffc..3b435bf4b 100644 --- a/src/app/api/auth/register/__tests__/route.test.ts +++ b/src/app/api/auth/register/__tests__/route.test.ts @@ -72,9 +72,6 @@ vi.mock("@/lib/tz/resolver", () => ({ resolveServerDefaultTimezone: vi.fn().mockResolvedValue("Europe/Berlin"), })); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); vi.mock("@/lib/logging/transports", () => ({ emitIfSampled: vi.fn() })); vi.mock("next/headers", () => ({ headers: vi.fn(async () => ({ get: () => null })), diff --git a/src/app/api/auth/register/route.ts b/src/app/api/auth/register/route.ts index 6e374033b..a50be77c2 100644 --- a/src/app/api/auth/register/route.ts +++ b/src/app/api/auth/register/route.ts @@ -12,7 +12,6 @@ import { auditLog } from "@/lib/auth/audit"; import { apiSuccess, apiError } from "@/lib/api-response"; import { parseJsonBody } from "@/lib/api/body"; import { checkAuthSurfaceRateLimit, rateLimitHeaders } from "@/lib/rate-limit"; -import { ensureDbCompatibility } from "@/lib/db-compat"; import { NextRequest, NextResponse } from "next/server"; import { apiHandler } from "@/lib/api-handler"; import { annotate } from "@/lib/logging/context"; @@ -79,8 +78,6 @@ export const POST = apiHandler(async (request: NextRequest) => { ); } - await ensureDbCompatibility(); - const userCount = await prisma.user.count(); // Check if registration is enabled. diff --git a/src/app/api/biomarkers/[id]/__tests__/delete-record-auth.test.ts b/src/app/api/biomarkers/[id]/__tests__/delete-record-auth.test.ts index 3b9cb8f7a..468bb14ea 100644 --- a/src/app/api/biomarkers/[id]/__tests__/delete-record-auth.test.ts +++ b/src/app/api/biomarkers/[id]/__tests__/delete-record-auth.test.ts @@ -33,9 +33,6 @@ vi.mock("@/lib/auth/audit", () => ({ auditLog: vi.fn().mockResolvedValue(undefined), })); vi.mock("@/lib/logging/transports", () => ({ emitIfSampled: vi.fn() })); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); vi.mock("@/lib/cache/invalidate", () => ({ invalidateUserHealthScore: vi.fn(), })); diff --git a/src/app/api/biomarkers/[id]/__tests__/route.test.ts b/src/app/api/biomarkers/[id]/__tests__/route.test.ts index 46a840f1f..bf781ebbc 100644 --- a/src/app/api/biomarkers/[id]/__tests__/route.test.ts +++ b/src/app/api/biomarkers/[id]/__tests__/route.test.ts @@ -32,10 +32,6 @@ vi.mock("@/lib/auth/audit", () => ({ vi.mock("@/lib/logging/transports", () => ({ emitIfSampled: vi.fn() })); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - vi.mock("@/lib/labs/biomarker-store", () => ({ encryptContextToBytes: vi.fn(() => new Uint8Array([1])), decryptContextFromBytes: vi.fn(() => "ctx"), diff --git a/src/app/api/biomarkers/__tests__/error-contract.test.ts b/src/app/api/biomarkers/__tests__/error-contract.test.ts index dcbfe3362..4f4e1506b 100644 --- a/src/app/api/biomarkers/__tests__/error-contract.test.ts +++ b/src/app/api/biomarkers/__tests__/error-contract.test.ts @@ -31,9 +31,6 @@ vi.mock("@/lib/labs/biomarker-store", () => ({ encryptContextToBytes: vi.fn(), })); vi.mock("@/lib/logging/transports", () => ({ emitIfSampled: vi.fn() })); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); vi.mock("next/headers", () => ({ headers: vi.fn(async () => ({ get: () => null })), cookies: vi.fn(async () => ({ diff --git a/src/app/api/c/[token]/unlock/__tests__/route.test.ts b/src/app/api/c/[token]/unlock/__tests__/route.test.ts index e7cf2ef56..317199c29 100644 --- a/src/app/api/c/[token]/unlock/__tests__/route.test.ts +++ b/src/app/api/c/[token]/unlock/__tests__/route.test.ts @@ -37,10 +37,6 @@ vi.mock("@/lib/rate-limit", () => ({ checkAuthSurfaceRateLimit: vi.fn(), })); vi.mock("@/lib/logging/transports", () => ({ emitIfSampled: vi.fn() })); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - import { POST } from "../route"; import { resolveShareGateState } from "@/lib/clinician-share/resolve-share-token"; import { verifyPassphrase } from "@/lib/clinician-share/passphrase"; diff --git a/src/app/api/coach/plans/__tests__/route.test.ts b/src/app/api/coach/plans/__tests__/route.test.ts index 6738a2a44..6d3885d21 100644 --- a/src/app/api/coach/plans/__tests__/route.test.ts +++ b/src/app/api/coach/plans/__tests__/route.test.ts @@ -54,10 +54,6 @@ vi.mock("@/lib/logging/transports", () => ({ emitIfSampled: vi.fn(), })); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - vi.mock("@/lib/logging/context", async (importOriginal) => { const actual = await importOriginal(); return { ...actual, annotate: vi.fn() }; diff --git a/src/app/api/coach/reminders/__tests__/route.test.ts b/src/app/api/coach/reminders/__tests__/route.test.ts index 2bdea457f..9e3391106 100644 --- a/src/app/api/coach/reminders/__tests__/route.test.ts +++ b/src/app/api/coach/reminders/__tests__/route.test.ts @@ -48,9 +48,6 @@ vi.mock("@/lib/ai/coach/bytes-codec", () => ({ encryptToBytes: vi.fn((s: string) => new Uint8Array(Buffer.from(`enc:${s}`))), })); vi.mock("@/lib/logging/transports", () => ({ emitIfSampled: vi.fn() })); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); vi.mock("@/lib/logging/context", async (importOriginal) => { const actual = await importOriginal(); return { ...actual, annotate: vi.fn() }; diff --git a/src/app/api/coach/suggested-actions/__tests__/route.test.ts b/src/app/api/coach/suggested-actions/__tests__/route.test.ts index d1f49c9a0..e629d2c44 100644 --- a/src/app/api/coach/suggested-actions/__tests__/route.test.ts +++ b/src/app/api/coach/suggested-actions/__tests__/route.test.ts @@ -48,9 +48,6 @@ vi.mock("@/lib/measurement-reminders/dto", () => ({ toMeasurementReminderDto: vi.fn((r: { id: string }) => ({ id: r.id })), })); vi.mock("@/lib/logging/transports", () => ({ emitIfSampled: vi.fn() })); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); vi.mock("@/lib/logging/context", async (importOriginal) => { const actual = await importOriginal(); return { ...actual, annotate: vi.fn() }; diff --git a/src/app/api/consent/ai/__tests__/route.test.ts b/src/app/api/consent/ai/__tests__/route.test.ts index c3b9b9ba1..bcfb7341f 100644 --- a/src/app/api/consent/ai/__tests__/route.test.ts +++ b/src/app/api/consent/ai/__tests__/route.test.ts @@ -36,10 +36,6 @@ vi.mock("@/lib/auth/audit", () => ({ vi.mock("@/lib/logging/transports", () => ({ emitIfSampled: vi.fn() })); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - vi.mock("next/headers", () => ({ headers: vi.fn(async () => ({ get: () => null })), cookies: vi.fn(async () => ({ diff --git a/src/app/api/consent/ai/latest/__tests__/route.test.ts b/src/app/api/consent/ai/latest/__tests__/route.test.ts index fcbf29309..c34d9cc2c 100644 --- a/src/app/api/consent/ai/latest/__tests__/route.test.ts +++ b/src/app/api/consent/ai/latest/__tests__/route.test.ts @@ -40,10 +40,6 @@ vi.mock("@/lib/auth/audit", () => ({ vi.mock("@/lib/logging/transports", () => ({ emitIfSampled: vi.fn() })); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - vi.mock("next/headers", () => ({ headers: vi.fn(async () => ({ get: () => null })), cookies: vi.fn(async () => ({ diff --git a/src/app/api/consent/ai/web/__tests__/route.test.ts b/src/app/api/consent/ai/web/__tests__/route.test.ts index 4b101efd5..d6ab7b671 100644 --- a/src/app/api/consent/ai/web/__tests__/route.test.ts +++ b/src/app/api/consent/ai/web/__tests__/route.test.ts @@ -8,10 +8,6 @@ vi.mock("@/lib/auth/audit", () => ({ vi.mock("@/lib/logging/transports", () => ({ emitIfSampled: vi.fn() })); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - vi.mock("next/headers", () => ({ headers: vi.fn(async () => ({ get: () => null })), cookies: vi.fn(async () => ({ diff --git a/src/app/api/custom-metrics/[id]/__tests__/route.test.ts b/src/app/api/custom-metrics/[id]/__tests__/route.test.ts index bc70c9d62..76d08eb28 100644 --- a/src/app/api/custom-metrics/[id]/__tests__/route.test.ts +++ b/src/app/api/custom-metrics/[id]/__tests__/route.test.ts @@ -16,10 +16,6 @@ vi.mock("@/lib/auth/audit", () => ({ vi.mock("@/lib/logging/transports", () => ({ emitIfSampled: vi.fn() })); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - vi.mock("next/headers", () => ({ headers: vi.fn(async () => ({ get: () => null })), cookies: vi.fn(async () => ({ diff --git a/src/app/api/custom-metrics/[id]/entries/__tests__/note-encryption.test.ts b/src/app/api/custom-metrics/[id]/entries/__tests__/note-encryption.test.ts index 89609be1b..ec03e0a59 100644 --- a/src/app/api/custom-metrics/[id]/entries/__tests__/note-encryption.test.ts +++ b/src/app/api/custom-metrics/[id]/entries/__tests__/note-encryption.test.ts @@ -37,10 +37,6 @@ vi.mock("@/lib/auth/audit", () => ({ vi.mock("@/lib/logging/transports", () => ({ emitIfSampled: vi.fn() })); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - vi.mock("@/lib/idempotency", () => ({ withIdempotency: (fn: unknown) => fn, })); diff --git a/src/app/api/custom-metrics/[id]/entries/__tests__/route.test.ts b/src/app/api/custom-metrics/[id]/entries/__tests__/route.test.ts index 2f02eb2b3..a416eb63e 100644 --- a/src/app/api/custom-metrics/[id]/entries/__tests__/route.test.ts +++ b/src/app/api/custom-metrics/[id]/entries/__tests__/route.test.ts @@ -32,10 +32,6 @@ vi.mock("@/lib/auth/audit", () => ({ vi.mock("@/lib/logging/transports", () => ({ emitIfSampled: vi.fn() })); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - vi.mock("@/lib/idempotency", () => ({ withIdempotency: (fn: unknown) => fn, })); diff --git a/src/app/api/custom-metrics/[id]/entries/__tests__/soft-delete-restore.test.ts b/src/app/api/custom-metrics/[id]/entries/__tests__/soft-delete-restore.test.ts index 9794e159b..1cb0edf37 100644 --- a/src/app/api/custom-metrics/[id]/entries/__tests__/soft-delete-restore.test.ts +++ b/src/app/api/custom-metrics/[id]/entries/__tests__/soft-delete-restore.test.ts @@ -30,10 +30,6 @@ vi.mock("@/lib/auth/audit", () => ({ vi.mock("@/lib/logging/transports", () => ({ emitIfSampled: vi.fn() })); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - vi.mock("@/lib/cache/invalidate", () => ({ invalidateUserCorrelationPatterns: vi.fn(), })); diff --git a/src/app/api/custom-metrics/__tests__/route.test.ts b/src/app/api/custom-metrics/__tests__/route.test.ts index 50ee33ccf..1a9a0492c 100644 --- a/src/app/api/custom-metrics/__tests__/route.test.ts +++ b/src/app/api/custom-metrics/__tests__/route.test.ts @@ -22,10 +22,6 @@ vi.mock("@/lib/auth/audit", () => ({ vi.mock("@/lib/logging/transports", () => ({ emitIfSampled: vi.fn() })); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - vi.mock("@/lib/idempotency", () => ({ withIdempotency: (fn: unknown) => fn, })); diff --git a/src/app/api/cycle/__tests__/external-id-floor.test.ts b/src/app/api/cycle/__tests__/external-id-floor.test.ts index 5e1428830..9fe3b848c 100644 --- a/src/app/api/cycle/__tests__/external-id-floor.test.ts +++ b/src/app/api/cycle/__tests__/external-id-floor.test.ts @@ -64,9 +64,6 @@ vi.mock("@/lib/cycle/dto", async (importOriginal) => ({ toMenstrualCycleDTO: vi.fn(() => ({ id: "cycle-1" })), })); vi.mock("@/lib/logging/transports", () => ({ emitIfSampled: vi.fn() })); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); vi.mock("next/headers", () => ({ headers: vi.fn(async () => ({ get: () => null })), cookies: vi.fn(async () => ({ diff --git a/src/app/api/cycle/calendar/__tests__/day-entries.test.ts b/src/app/api/cycle/calendar/__tests__/day-entries.test.ts index 48e25b400..bd64f018a 100644 --- a/src/app/api/cycle/calendar/__tests__/day-entries.test.ts +++ b/src/app/api/cycle/calendar/__tests__/day-entries.test.ts @@ -41,9 +41,6 @@ vi.mock("@/lib/rate-limit", () => ({ })); vi.mock("@/lib/cycle/gate", () => ({ requireCycleEnabled: vi.fn() })); vi.mock("@/lib/logging/transports", () => ({ emitIfSampled: vi.fn() })); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); vi.mock("next/headers", () => ({ headers: vi.fn(async () => ({ get: () => null })), cookies: vi.fn(async () => ({ diff --git a/src/app/api/cycle/calendar/__tests__/verdict-round-trip.test.ts b/src/app/api/cycle/calendar/__tests__/verdict-round-trip.test.ts index 08f125662..ed1dced44 100644 --- a/src/app/api/cycle/calendar/__tests__/verdict-round-trip.test.ts +++ b/src/app/api/cycle/calendar/__tests__/verdict-round-trip.test.ts @@ -41,9 +41,6 @@ vi.mock("@/lib/rate-limit", () => ({ })); vi.mock("@/lib/cycle/gate", () => ({ requireCycleEnabled: vi.fn() })); vi.mock("@/lib/logging/transports", () => ({ emitIfSampled: vi.fn() })); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); vi.mock("next/headers", () => ({ headers: vi.fn(async () => ({ get: () => null })), cookies: vi.fn(async () => ({ diff --git a/src/app/api/cycle/day-logs/bulk/__tests__/route.test.ts b/src/app/api/cycle/day-logs/bulk/__tests__/route.test.ts index 8b59f8fec..aaada8c8c 100644 --- a/src/app/api/cycle/day-logs/bulk/__tests__/route.test.ts +++ b/src/app/api/cycle/day-logs/bulk/__tests__/route.test.ts @@ -36,9 +36,6 @@ vi.mock("@/lib/cycle/day-log-write", () => ({ upsertCycleDayLog: vi.fn(), })); vi.mock("@/lib/logging/transports", () => ({ emitIfSampled: vi.fn() })); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); vi.mock("next/headers", () => ({ headers: vi.fn(async () => ({ get: () => null })), cookies: vi.fn(async () => ({ diff --git a/src/app/api/cycle/insights/__tests__/route-locale.test.ts b/src/app/api/cycle/insights/__tests__/route-locale.test.ts index 0a516735c..4c44ed11e 100644 --- a/src/app/api/cycle/insights/__tests__/route-locale.test.ts +++ b/src/app/api/cycle/insights/__tests__/route-locale.test.ts @@ -67,10 +67,6 @@ vi.mock("@/lib/rate-limit", () => ({ checkRateLimit: vi.fn(async () => ({ allowed: true })), })); vi.mock("@/lib/logging/transports", () => ({ emitIfSampled: vi.fn() })); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - const localeCookie = vi.fn<() => string | undefined>(() => undefined); vi.mock("next/headers", () => ({ headers: vi.fn(async () => ({ get: () => null })), diff --git a/src/app/api/cycle/symptoms/custom/__tests__/custom-crud.test.ts b/src/app/api/cycle/symptoms/custom/__tests__/custom-crud.test.ts index eec847a26..cf0c9bfc7 100644 --- a/src/app/api/cycle/symptoms/custom/__tests__/custom-crud.test.ts +++ b/src/app/api/cycle/symptoms/custom/__tests__/custom-crud.test.ts @@ -27,9 +27,6 @@ vi.mock("@/lib/auth/audit", () => ({ auditLog: vi.fn().mockResolvedValue(undefined), })); vi.mock("@/lib/logging/transports", () => ({ emitIfSampled: vi.fn() })); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); vi.mock("@/lib/cycle/gate", () => ({ requireCycleEnabled: vi.fn(), })); diff --git a/src/app/api/daily/digest/__tests__/route.test.ts b/src/app/api/daily/digest/__tests__/route.test.ts index 10af3f903..1362d9554 100644 --- a/src/app/api/daily/digest/__tests__/route.test.ts +++ b/src/app/api/daily/digest/__tests__/route.test.ts @@ -28,9 +28,6 @@ vi.mock("@/lib/auth/audit", () => ({ auditLog: vi.fn().mockResolvedValue(undefined), })); vi.mock("@/lib/logging/transports", () => ({ emitIfSampled: vi.fn() })); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); vi.mock("next/headers", () => ({ headers: vi.fn(async () => ({ get: () => null })), cookies: vi.fn(async () => ({ diff --git a/src/app/api/daily/digest/dismiss/__tests__/route.test.ts b/src/app/api/daily/digest/dismiss/__tests__/route.test.ts index 71b989788..6797ca8ac 100644 --- a/src/app/api/daily/digest/dismiss/__tests__/route.test.ts +++ b/src/app/api/daily/digest/dismiss/__tests__/route.test.ts @@ -40,9 +40,6 @@ vi.mock("@/lib/auth/audit", () => ({ auditLog: vi.fn().mockResolvedValue(undefined), })); vi.mock("@/lib/logging/transports", () => ({ emitIfSampled: vi.fn() })); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); vi.mock("@/lib/logging/context", async (importOriginal) => { const actual = await importOriginal(); return { ...actual, annotate: vi.fn() }; diff --git a/src/app/api/dashboard/chart-overlay-prefs/__tests__/route.test.ts b/src/app/api/dashboard/chart-overlay-prefs/__tests__/route.test.ts index 29b6c0ccf..7d77f2585 100644 --- a/src/app/api/dashboard/chart-overlay-prefs/__tests__/route.test.ts +++ b/src/app/api/dashboard/chart-overlay-prefs/__tests__/route.test.ts @@ -22,9 +22,6 @@ vi.mock("@/lib/cache/invalidate", () => ({ invalidateUserDashboardWidgets: vi.fn(), })); vi.mock("@/lib/logging/transports", () => ({ emitIfSampled: vi.fn() })); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); vi.mock("next/headers", () => ({ headers: vi.fn(async () => ({ get: () => null })), cookies: vi.fn(async () => ({ diff --git a/src/app/api/dashboard/snapshot/__tests__/route.test.ts b/src/app/api/dashboard/snapshot/__tests__/route.test.ts index e161146af..db2349498 100644 --- a/src/app/api/dashboard/snapshot/__tests__/route.test.ts +++ b/src/app/api/dashboard/snapshot/__tests__/route.test.ts @@ -26,9 +26,6 @@ vi.mock("@/lib/auth/session", () => ({ vi.mock("@/lib/logging/transports", () => ({ emitIfSampled: vi.fn(), })); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); vi.mock("next/headers", () => ({ headers: vi.fn(async () => ({ get: () => null })), cookies: vi.fn(async () => ({ diff --git a/src/app/api/dashboard/summary/__tests__/module-gate.test.ts b/src/app/api/dashboard/summary/__tests__/module-gate.test.ts index 90bbfee18..ba4647551 100644 --- a/src/app/api/dashboard/summary/__tests__/module-gate.test.ts +++ b/src/app/api/dashboard/summary/__tests__/module-gate.test.ts @@ -18,9 +18,6 @@ import { describe, it, expect, vi, beforeEach } from "vitest"; vi.mock("@/lib/auth/session", () => ({ getSession: vi.fn() })); vi.mock("@/lib/logging/transports", () => ({ emitIfSampled: vi.fn() })); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); // The gate resolver runs for real; only its data sources are stubbed, so the // module state is driven the way production drives it. vi.mock("@/lib/db", () => ({ diff --git a/src/app/api/dashboard/summary/__tests__/route.test.ts b/src/app/api/dashboard/summary/__tests__/route.test.ts index c6fd2ca31..df9e71ef4 100644 --- a/src/app/api/dashboard/summary/__tests__/route.test.ts +++ b/src/app/api/dashboard/summary/__tests__/route.test.ts @@ -92,10 +92,6 @@ vi.mock("@/lib/analytics/mood-series", () => ({ })), })); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - vi.mock("next/headers", () => ({ headers: vi.fn(async () => ({ get: () => null })), cookies: vi.fn(async () => ({ diff --git a/src/app/api/dashboard/widgets/__tests__/route.test.ts b/src/app/api/dashboard/widgets/__tests__/route.test.ts index 45777dd56..29ad25c97 100644 --- a/src/app/api/dashboard/widgets/__tests__/route.test.ts +++ b/src/app/api/dashboard/widgets/__tests__/route.test.ts @@ -58,10 +58,6 @@ vi.mock("@/lib/logging/transports", () => ({ emitIfSampled: vi.fn(), })); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - vi.mock("@/lib/logging/context", async (importOriginal) => { const actual = await importOriginal(); return { diff --git a/src/app/api/devices/[id]/__tests__/route.test.ts b/src/app/api/devices/[id]/__tests__/route.test.ts index 6f274a931..b6df569cb 100644 --- a/src/app/api/devices/[id]/__tests__/route.test.ts +++ b/src/app/api/devices/[id]/__tests__/route.test.ts @@ -29,10 +29,6 @@ vi.mock("@/lib/auth/audit", () => ({ vi.mock("@/lib/logging/transports", () => ({ emitIfSampled: vi.fn() })); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - vi.mock("next/headers", () => ({ headers: vi.fn(async () => ({ get: () => null })), cookies: vi.fn(async () => ({ diff --git a/src/app/api/devices/__tests__/route.test.ts b/src/app/api/devices/__tests__/route.test.ts index ef65576c7..a06d413e0 100644 --- a/src/app/api/devices/__tests__/route.test.ts +++ b/src/app/api/devices/__tests__/route.test.ts @@ -37,10 +37,6 @@ vi.mock("@/lib/auth/audit", () => ({ vi.mock("@/lib/logging/transports", () => ({ emitIfSampled: vi.fn() })); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - vi.mock("@/lib/rate-limit", () => ({ checkRateLimit: vi.fn().mockResolvedValue({ allowed: true, diff --git a/src/app/api/documents/inbound/[id]/__tests__/route.test.ts b/src/app/api/documents/inbound/[id]/__tests__/route.test.ts index e9a75d030..1ccc9afd0 100644 --- a/src/app/api/documents/inbound/[id]/__tests__/route.test.ts +++ b/src/app/api/documents/inbound/[id]/__tests__/route.test.ts @@ -98,9 +98,6 @@ vi.mock("@/lib/auth/audit", () => ({ auditLog: vi.fn().mockResolvedValue(undefined), })); vi.mock("@/lib/logging/transports", () => ({ emitIfSampled: vi.fn() })); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); vi.mock("next/headers", () => ({ headers: vi.fn(async () => ({ get: () => null })), cookies: vi.fn(async () => ({ diff --git a/src/app/api/documents/inbound/[id]/chat/__tests__/route.test.ts b/src/app/api/documents/inbound/[id]/chat/__tests__/route.test.ts index 823dd0fd6..c8f303f28 100644 --- a/src/app/api/documents/inbound/[id]/chat/__tests__/route.test.ts +++ b/src/app/api/documents/inbound/[id]/chat/__tests__/route.test.ts @@ -72,9 +72,6 @@ vi.mock("@/lib/auth/audit", () => ({ })); vi.mock("@/lib/auth/session", () => ({ getSession: vi.fn() })); vi.mock("@/lib/logging/transports", () => ({ emitIfSampled: vi.fn() })); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); vi.mock("next/headers", () => ({ headers: vi.fn(async () => ({ get: () => null })), cookies: vi.fn(async () => ({ diff --git a/src/app/api/documents/inbound/[id]/extract/__tests__/route.test.ts b/src/app/api/documents/inbound/[id]/extract/__tests__/route.test.ts index 0506f136d..6789ff28f 100644 --- a/src/app/api/documents/inbound/[id]/extract/__tests__/route.test.ts +++ b/src/app/api/documents/inbound/[id]/extract/__tests__/route.test.ts @@ -96,9 +96,6 @@ vi.mock("@/lib/auth/audit", () => ({ auditLog: vi.fn().mockResolvedValue(undefined), })); vi.mock("@/lib/logging/transports", () => ({ emitIfSampled: vi.fn() })); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); vi.mock("next/headers", () => ({ headers: vi.fn(async () => ({ get: () => null })), cookies: vi.fn(async () => ({ diff --git a/src/app/api/documents/inbound/[id]/index/__tests__/route.test.ts b/src/app/api/documents/inbound/[id]/index/__tests__/route.test.ts index 8307653b2..bbd04cc0c 100644 --- a/src/app/api/documents/inbound/[id]/index/__tests__/route.test.ts +++ b/src/app/api/documents/inbound/[id]/index/__tests__/route.test.ts @@ -76,9 +76,6 @@ vi.mock("@/lib/auth/audit", () => ({ auditLog: vi.fn().mockResolvedValue(undefined), })); vi.mock("@/lib/logging/transports", () => ({ emitIfSampled: vi.fn() })); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); vi.mock("next/headers", () => ({ headers: vi.fn(async () => ({ get: () => null })), cookies: vi.fn(async () => ({ diff --git a/src/app/api/documents/inbound/[id]/original/__tests__/route.test.ts b/src/app/api/documents/inbound/[id]/original/__tests__/route.test.ts index fffc37bcc..617ad602c 100644 --- a/src/app/api/documents/inbound/[id]/original/__tests__/route.test.ts +++ b/src/app/api/documents/inbound/[id]/original/__tests__/route.test.ts @@ -46,9 +46,6 @@ vi.mock("@/lib/auth/audit", () => ({ auditLog: vi.fn().mockResolvedValue(undefined), })); vi.mock("@/lib/logging/transports", () => ({ emitIfSampled: vi.fn() })); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); vi.mock("next/headers", () => ({ headers: vi.fn(async () => ({ get: () => null })), cookies: vi.fn(async () => ({ diff --git a/src/app/api/documents/inbound/[id]/suggest/__tests__/route.test.ts b/src/app/api/documents/inbound/[id]/suggest/__tests__/route.test.ts index bde68062a..7dbed6993 100644 --- a/src/app/api/documents/inbound/[id]/suggest/__tests__/route.test.ts +++ b/src/app/api/documents/inbound/[id]/suggest/__tests__/route.test.ts @@ -55,9 +55,6 @@ vi.mock("@/lib/auth/audit", () => ({ auditLog: vi.fn().mockResolvedValue(undefined), })); vi.mock("@/lib/logging/transports", () => ({ emitIfSampled: vi.fn() })); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); vi.mock("next/headers", () => ({ headers: vi.fn(async () => ({ get: () => null })), cookies: vi.fn(async () => ({ diff --git a/src/app/api/documents/inbound/[id]/summary/__tests__/route.test.ts b/src/app/api/documents/inbound/[id]/summary/__tests__/route.test.ts index 9a0c0b309..62c7de63b 100644 --- a/src/app/api/documents/inbound/[id]/summary/__tests__/route.test.ts +++ b/src/app/api/documents/inbound/[id]/summary/__tests__/route.test.ts @@ -68,9 +68,6 @@ vi.mock("@/lib/auth/audit", () => ({ auditLog: vi.fn().mockResolvedValue(undefined), })); vi.mock("@/lib/logging/transports", () => ({ emitIfSampled: vi.fn() })); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); vi.mock("next/headers", () => ({ headers: vi.fn(async () => ({ get: () => null })), cookies: vi.fn(async () => ({ diff --git a/src/app/api/documents/inbound/[id]/thumbnail/__tests__/route.test.ts b/src/app/api/documents/inbound/[id]/thumbnail/__tests__/route.test.ts index 5d31b1102..08f499b4b 100644 --- a/src/app/api/documents/inbound/[id]/thumbnail/__tests__/route.test.ts +++ b/src/app/api/documents/inbound/[id]/thumbnail/__tests__/route.test.ts @@ -48,9 +48,6 @@ vi.mock("@/lib/auth/audit", () => ({ auditLog: vi.fn().mockResolvedValue(undefined), })); vi.mock("@/lib/logging/transports", () => ({ emitIfSampled: vi.fn() })); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); vi.mock("next/headers", () => ({ headers: vi.fn(async () => ({ get: () => null })), cookies: vi.fn(async () => ({ diff --git a/src/app/api/documents/inbound/__tests__/route.test.ts b/src/app/api/documents/inbound/__tests__/route.test.ts index 81319039f..a68945788 100644 --- a/src/app/api/documents/inbound/__tests__/route.test.ts +++ b/src/app/api/documents/inbound/__tests__/route.test.ts @@ -133,9 +133,6 @@ vi.mock("@/lib/auth/audit", () => ({ auditLog: vi.fn().mockResolvedValue(undefined), })); vi.mock("@/lib/logging/transports", () => ({ emitIfSampled: vi.fn() })); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); vi.mock("next/headers", () => ({ headers: vi.fn(async () => ({ get: () => null })), cookies: vi.fn(async () => ({ diff --git a/src/app/api/documents/inbound/layout/__tests__/route.test.ts b/src/app/api/documents/inbound/layout/__tests__/route.test.ts index 41ca79b2b..1926696d4 100644 --- a/src/app/api/documents/inbound/layout/__tests__/route.test.ts +++ b/src/app/api/documents/inbound/layout/__tests__/route.test.ts @@ -27,10 +27,6 @@ vi.mock("@/lib/logging/transports", () => ({ emitIfSampled: vi.fn(), })); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - vi.mock("@/lib/modules/gate", () => ({ requireModuleEnabled: vi.fn(), })); diff --git a/src/app/api/documents/inbound/reindex/__tests__/route.test.ts b/src/app/api/documents/inbound/reindex/__tests__/route.test.ts index dcdaad6ec..e908f1d1b 100644 --- a/src/app/api/documents/inbound/reindex/__tests__/route.test.ts +++ b/src/app/api/documents/inbound/reindex/__tests__/route.test.ts @@ -37,9 +37,6 @@ vi.mock("@/lib/auth/audit", () => ({ auditLog: vi.fn().mockResolvedValue(undefined), })); vi.mock("@/lib/logging/transports", () => ({ emitIfSampled: vi.fn() })); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); vi.mock("next/headers", () => ({ headers: vi.fn(async () => ({ get: () => null })), cookies: vi.fn(async () => ({ diff --git a/src/app/api/feature-flags/__tests__/route.test.ts b/src/app/api/feature-flags/__tests__/route.test.ts index cec44a7be..8445347ba 100644 --- a/src/app/api/feature-flags/__tests__/route.test.ts +++ b/src/app/api/feature-flags/__tests__/route.test.ts @@ -9,10 +9,6 @@ vi.mock("@/lib/auth/audit", () => ({ vi.mock("@/lib/logging/transports", () => ({ emitIfSampled: vi.fn() })); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - vi.mock("next/headers", () => ({ headers: vi.fn(async () => ({ get: () => null })), cookies: vi.fn(async () => ({ diff --git a/src/app/api/fhir/__tests__/observation-series.test.ts b/src/app/api/fhir/__tests__/observation-series.test.ts index 25fb76e6f..790ea1409 100644 --- a/src/app/api/fhir/__tests__/observation-series.test.ts +++ b/src/app/api/fhir/__tests__/observation-series.test.ts @@ -11,9 +11,6 @@ import { NextRequest } from "next/server"; vi.mock("@/lib/auth/session", () => ({ getSession: vi.fn() })); vi.mock("@/lib/rate-limit", () => ({ checkRateLimit: vi.fn() })); vi.mock("@/lib/logging/transports", () => ({ emitIfSampled: vi.fn() })); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); vi.mock("@/lib/modules/gate", () => ({ requireModuleEnabled: vi.fn(), isModuleEnabled: vi.fn(), diff --git a/src/app/api/fhir/__tests__/route.test.ts b/src/app/api/fhir/__tests__/route.test.ts index 5d2fd4499..6279318b1 100644 --- a/src/app/api/fhir/__tests__/route.test.ts +++ b/src/app/api/fhir/__tests__/route.test.ts @@ -13,9 +13,6 @@ import { NextRequest } from "next/server"; vi.mock("@/lib/auth/session", () => ({ getSession: vi.fn() })); vi.mock("@/lib/rate-limit", () => ({ checkRateLimit: vi.fn() })); vi.mock("@/lib/logging/transports", () => ({ emitIfSampled: vi.fn() })); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); vi.mock("@/lib/modules/gate", () => ({ requireModuleEnabled: vi.fn(), isModuleEnabled: vi.fn(), diff --git a/src/app/api/gamification/achievements/__tests__/hidden-redaction.test.ts b/src/app/api/gamification/achievements/__tests__/hidden-redaction.test.ts index 0b3a403a6..1ff461b37 100644 --- a/src/app/api/gamification/achievements/__tests__/hidden-redaction.test.ts +++ b/src/app/api/gamification/achievements/__tests__/hidden-redaction.test.ts @@ -38,10 +38,6 @@ vi.mock("@/lib/modules/gate", () => ({ vi.mock("@/lib/logging/transports", () => ({ emitIfSampled: vi.fn() })); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - vi.mock("next/headers", () => ({ headers: vi.fn(async () => ({ get: () => null })), cookies: vi.fn(async () => ({ diff --git a/src/app/api/gamification/achievements/__tests__/ios-format.test.ts b/src/app/api/gamification/achievements/__tests__/ios-format.test.ts index 6ed08a845..c3d338474 100644 --- a/src/app/api/gamification/achievements/__tests__/ios-format.test.ts +++ b/src/app/api/gamification/achievements/__tests__/ios-format.test.ts @@ -38,10 +38,6 @@ vi.mock("@/lib/modules/gate", () => ({ vi.mock("@/lib/logging/transports", () => ({ emitIfSampled: vi.fn() })); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - vi.mock("next/headers", () => ({ headers: vi.fn(async () => ({ get: () => null })), cookies: vi.fn(async () => ({ diff --git a/src/app/api/gamification/achievements/__tests__/module-gate.test.ts b/src/app/api/gamification/achievements/__tests__/module-gate.test.ts index 57575b470..ad48c68f6 100644 --- a/src/app/api/gamification/achievements/__tests__/module-gate.test.ts +++ b/src/app/api/gamification/achievements/__tests__/module-gate.test.ts @@ -36,9 +36,6 @@ vi.mock("@/lib/db", () => ({ vi.mock("@/lib/auth/session", () => ({ getSession: vi.fn() })); vi.mock("@/lib/logging/transports", () => ({ emitIfSampled: vi.fn() })); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); vi.mock("next/headers", () => ({ headers: vi.fn(async () => ({ get: () => null })), cookies: vi.fn(async () => ({ diff --git a/src/app/api/gamification/achievements/__tests__/writes-nothing.test.ts b/src/app/api/gamification/achievements/__tests__/writes-nothing.test.ts index fc04778b3..4775ccf13 100644 --- a/src/app/api/gamification/achievements/__tests__/writes-nothing.test.ts +++ b/src/app/api/gamification/achievements/__tests__/writes-nothing.test.ts @@ -20,9 +20,6 @@ vi.mock("@/lib/db", () => ({ vi.mock("@/lib/auth/session", () => ({ getSession: vi.fn() })); vi.mock("@/lib/logging/transports", () => ({ emitIfSampled: vi.fn() })); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); vi.mock("next/headers", () => ({ headers: vi.fn(async () => ({ get: () => null })), cookies: vi.fn(async () => ({ diff --git a/src/app/api/illness/episodes/[id]/__tests__/body-site.test.ts b/src/app/api/illness/episodes/[id]/__tests__/body-site.test.ts index 10698f21c..e61916a04 100644 --- a/src/app/api/illness/episodes/[id]/__tests__/body-site.test.ts +++ b/src/app/api/illness/episodes/[id]/__tests__/body-site.test.ts @@ -47,9 +47,6 @@ vi.mock("@/lib/idempotency", () => ({ fn(...args), })); vi.mock("@/lib/logging/transports", () => ({ emitIfSampled: vi.fn() })); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); vi.mock("next/headers", () => ({ headers: vi.fn(async () => ({ get: () => null })), cookies: vi.fn(async () => ({ diff --git a/src/app/api/illness/episodes/[id]/day-logs/__tests__/route.test.ts b/src/app/api/illness/episodes/[id]/day-logs/__tests__/route.test.ts index 6c2ae4d52..017352d2b 100644 --- a/src/app/api/illness/episodes/[id]/day-logs/__tests__/route.test.ts +++ b/src/app/api/illness/episodes/[id]/day-logs/__tests__/route.test.ts @@ -25,9 +25,6 @@ vi.mock("@/lib/illness/gate", () => ({ requireIllnessEnabled: vi.fn(), })); vi.mock("@/lib/logging/transports", () => ({ emitIfSampled: vi.fn() })); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); vi.mock("next/headers", () => ({ headers: vi.fn(async () => ({ get: () => null })), cookies: vi.fn(async () => ({ diff --git a/src/app/api/illness/episodes/[id]/restore/__tests__/route.test.ts b/src/app/api/illness/episodes/[id]/restore/__tests__/route.test.ts index b7ad8a4e7..dc180da9a 100644 --- a/src/app/api/illness/episodes/[id]/restore/__tests__/route.test.ts +++ b/src/app/api/illness/episodes/[id]/restore/__tests__/route.test.ts @@ -31,9 +31,6 @@ vi.mock("@/lib/idempotency", () => ({ fn(...args), })); vi.mock("@/lib/logging/transports", () => ({ emitIfSampled: vi.fn() })); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); vi.mock("next/headers", () => ({ headers: vi.fn(async () => ({ get: () => null })), cookies: vi.fn(async () => ({ diff --git a/src/app/api/import/apple-health-export/[jobId]/status/__tests__/route.test.ts b/src/app/api/import/apple-health-export/[jobId]/status/__tests__/route.test.ts index b0435ae42..68b53197d 100644 --- a/src/app/api/import/apple-health-export/[jobId]/status/__tests__/route.test.ts +++ b/src/app/api/import/apple-health-export/[jobId]/status/__tests__/route.test.ts @@ -10,9 +10,6 @@ vi.mock("@/lib/auth/audit", () => ({ auditLog: vi.fn().mockResolvedValue(undefined), })); vi.mock("@/lib/logging/transports", () => ({ emitIfSampled: vi.fn() })); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); vi.mock("next/headers", () => ({ headers: vi.fn(async () => ({ get: () => null })), cookies: vi.fn(async () => ({ diff --git a/src/app/api/import/apple-health-export/__tests__/route.test.ts b/src/app/api/import/apple-health-export/__tests__/route.test.ts index fb762f7fa..cc26e6570 100644 --- a/src/app/api/import/apple-health-export/__tests__/route.test.ts +++ b/src/app/api/import/apple-health-export/__tests__/route.test.ts @@ -18,9 +18,6 @@ vi.mock("@/lib/logging/signal", async (importOriginal) => ({ ...(await importOriginal()), emitSignal: vi.fn(), })); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); vi.mock("next/headers", () => ({ headers: vi.fn(async () => ({ get: () => null })), cookies: vi.fn(async () => ({ diff --git a/src/app/api/import/health-connect-export/__tests__/route.test.ts b/src/app/api/import/health-connect-export/__tests__/route.test.ts index bba3c79b6..c55a0ba0a 100644 --- a/src/app/api/import/health-connect-export/__tests__/route.test.ts +++ b/src/app/api/import/health-connect-export/__tests__/route.test.ts @@ -11,9 +11,6 @@ vi.mock("@/lib/auth/audit", () => ({ auditLog: vi.fn().mockResolvedValue(undefined), })); vi.mock("@/lib/logging/transports", () => ({ emitIfSampled: vi.fn() })); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); vi.mock("next/headers", () => ({ headers: vi.fn(async () => ({ get: () => null })), cookies: vi.fn(async () => ({ diff --git a/src/app/api/ingest/medication/__tests__/route.test.ts b/src/app/api/ingest/medication/__tests__/route.test.ts index 4f1f66c5b..254d84f47 100644 --- a/src/app/api/ingest/medication/__tests__/route.test.ts +++ b/src/app/api/ingest/medication/__tests__/route.test.ts @@ -52,9 +52,6 @@ vi.mock("@/lib/cache/invalidate", () => ({ invalidateUserMedications: vi.fn(), })); vi.mock("@/lib/logging/transports", () => ({ emitIfSampled: vi.fn() })); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); vi.mock("next/headers", () => ({ headers: vi.fn(async () => ({ get: () => null })), cookies: vi.fn(async () => ({ diff --git a/src/app/api/insights/biomarker-assessment/__tests__/route.test.ts b/src/app/api/insights/biomarker-assessment/__tests__/route.test.ts index d46454899..a50e0b238 100644 --- a/src/app/api/insights/biomarker-assessment/__tests__/route.test.ts +++ b/src/app/api/insights/biomarker-assessment/__tests__/route.test.ts @@ -30,10 +30,6 @@ vi.mock("@/lib/auth/audit", () => ({ vi.mock("@/lib/logging/transports", () => ({ emitIfSampled: vi.fn() })); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - vi.mock("next/headers", () => ({ headers: vi.fn(async () => ({ get: () => null })), cookies: vi.fn(async () => ({ diff --git a/src/app/api/insights/blood-pressure-status/__tests__/route.test.ts b/src/app/api/insights/blood-pressure-status/__tests__/route.test.ts index 6bec84c6f..d8fe900da 100644 --- a/src/app/api/insights/blood-pressure-status/__tests__/route.test.ts +++ b/src/app/api/insights/blood-pressure-status/__tests__/route.test.ts @@ -26,10 +26,6 @@ vi.mock("@/lib/auth/audit", () => ({ vi.mock("@/lib/logging/transports", () => ({ emitIfSampled: vi.fn() })); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - vi.mock("next/headers", () => ({ headers: vi.fn(async () => ({ get: () => null })), cookies: vi.fn(async () => ({ diff --git a/src/app/api/insights/cards/__tests__/route.test.ts b/src/app/api/insights/cards/__tests__/route.test.ts index e54879a31..ad4c51001 100644 --- a/src/app/api/insights/cards/__tests__/route.test.ts +++ b/src/app/api/insights/cards/__tests__/route.test.ts @@ -43,10 +43,6 @@ vi.mock("@/lib/auth/audit", () => ({ vi.mock("@/lib/logging/transports", () => ({ emitIfSampled: vi.fn() })); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - vi.mock("next/headers", () => ({ headers: vi.fn(async () => ({ get: () => null })), cookies: vi.fn(async () => ({ diff --git a/src/app/api/insights/chat/[id]/attachments/__tests__/route.test.ts b/src/app/api/insights/chat/[id]/attachments/__tests__/route.test.ts index a715ba6c3..00c7e8c2d 100644 --- a/src/app/api/insights/chat/[id]/attachments/__tests__/route.test.ts +++ b/src/app/api/insights/chat/[id]/attachments/__tests__/route.test.ts @@ -34,9 +34,6 @@ vi.mock("@/lib/ai/capabilities/gate", async () => await import("@/__tests__/helpers/provider-order-mock") ).openCapabilityGateMock(), ); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); vi.mock("next/headers", () => ({ headers: vi.fn(async () => ({ get: () => null })), cookies: vi.fn(async () => ({ diff --git a/src/app/api/insights/chat/fenced/__tests__/route.test.ts b/src/app/api/insights/chat/fenced/__tests__/route.test.ts index 52b4a1720..1e7656a50 100644 --- a/src/app/api/insights/chat/fenced/__tests__/route.test.ts +++ b/src/app/api/insights/chat/fenced/__tests__/route.test.ts @@ -45,9 +45,6 @@ vi.mock("@/lib/auth/audit", () => ({ })); vi.mock("@/lib/auth/session", () => ({ getSession: vi.fn() })); vi.mock("@/lib/logging/transports", () => ({ emitIfSampled: vi.fn() })); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); vi.mock("next/headers", () => ({ headers: vi.fn(async () => ({ get: () => null })), cookies: vi.fn(async () => ({ diff --git a/src/app/api/insights/coach-read/__tests__/route.test.ts b/src/app/api/insights/coach-read/__tests__/route.test.ts index 4425cd2eb..8d20f555f 100644 --- a/src/app/api/insights/coach-read/__tests__/route.test.ts +++ b/src/app/api/insights/coach-read/__tests__/route.test.ts @@ -45,10 +45,6 @@ vi.mock("@/lib/rate-limit", () => ({ checkAnalyticsReadRateLimit: vi.fn(), })); vi.mock("@/lib/logging/transports", () => ({ emitIfSampled: vi.fn() })); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - const localeCookie = vi.fn<() => string | undefined>(() => undefined); vi.mock("next/headers", () => ({ headers: vi.fn(async () => ({ get: () => null })), diff --git a/src/app/api/insights/coach/facts/__tests__/route-memory.test.ts b/src/app/api/insights/coach/facts/__tests__/route-memory.test.ts index 314c23803..9fb3ffac3 100644 --- a/src/app/api/insights/coach/facts/__tests__/route-memory.test.ts +++ b/src/app/api/insights/coach/facts/__tests__/route-memory.test.ts @@ -63,10 +63,6 @@ vi.mock("@/lib/logging/transports", () => ({ emitIfSampled: vi.fn(), })); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - vi.mock("@/lib/logging/context", async (importOriginal) => { const actual = await importOriginal(); return { diff --git a/src/app/api/insights/coach/facts/__tests__/route.test.ts b/src/app/api/insights/coach/facts/__tests__/route.test.ts index 4ce52362c..97591c5c0 100644 --- a/src/app/api/insights/coach/facts/__tests__/route.test.ts +++ b/src/app/api/insights/coach/facts/__tests__/route.test.ts @@ -59,10 +59,6 @@ vi.mock("@/lib/logging/transports", () => ({ emitIfSampled: vi.fn(), })); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - vi.mock("@/lib/logging/context", async (importOriginal) => { const actual = await importOriginal(); return { diff --git a/src/app/api/insights/comprehensive/__tests__/route.test.ts b/src/app/api/insights/comprehensive/__tests__/route.test.ts index 3454f7fc2..723cc103a 100644 --- a/src/app/api/insights/comprehensive/__tests__/route.test.ts +++ b/src/app/api/insights/comprehensive/__tests__/route.test.ts @@ -66,10 +66,6 @@ vi.mock("@/lib/rate-limit", () => ({ vi.mock("@/lib/logging/transports", () => ({ emitIfSampled: vi.fn() })); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - vi.mock("next/headers", () => ({ headers: vi.fn(async () => ({ get: () => null })), cookies: vi.fn(async () => ({ diff --git a/src/app/api/insights/correlations/__tests__/route.test.ts b/src/app/api/insights/correlations/__tests__/route.test.ts index 37759be1d..38fd9d900 100644 --- a/src/app/api/insights/correlations/__tests__/route.test.ts +++ b/src/app/api/insights/correlations/__tests__/route.test.ts @@ -64,10 +64,6 @@ vi.mock("@/lib/rate-limit", () => ({ vi.mock("@/lib/logging/transports", () => ({ emitIfSampled: vi.fn() })); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - vi.mock("@/lib/insights/correlation-patterns", () => ({ PATTERN_FAMILIES: { discoveryRetrospective: "DISCOVERY_RETROSPECTIVE", diff --git a/src/app/api/insights/derived/__tests__/route.test.ts b/src/app/api/insights/derived/__tests__/route.test.ts index efdb4407d..b06acdf1e 100644 --- a/src/app/api/insights/derived/__tests__/route.test.ts +++ b/src/app/api/insights/derived/__tests__/route.test.ts @@ -39,9 +39,6 @@ vi.mock("@/lib/rate-limit", () => ({ }), })); vi.mock("@/lib/logging/transports", () => ({ emitIfSampled: vi.fn() })); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); vi.mock("next/headers", () => ({ headers: vi.fn(async () => ({ get: () => null })), cookies: vi.fn(async () => ({ diff --git a/src/app/api/insights/derived/batch/__tests__/route.test.ts b/src/app/api/insights/derived/batch/__tests__/route.test.ts index c3469b575..34a490f84 100644 --- a/src/app/api/insights/derived/batch/__tests__/route.test.ts +++ b/src/app/api/insights/derived/batch/__tests__/route.test.ts @@ -23,9 +23,6 @@ vi.mock("@/lib/rate-limit", () => ({ rateLimitHeaders: () => ({}), })); vi.mock("@/lib/logging/transports", () => ({ emitIfSampled: vi.fn() })); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); vi.mock("next/headers", () => ({ headers: vi.fn(async () => ({ get: () => null })), cookies: vi.fn(async () => ({ diff --git a/src/app/api/insights/ecg/[id]/__tests__/route.test.ts b/src/app/api/insights/ecg/[id]/__tests__/route.test.ts index 125e93b9c..19037f656 100644 --- a/src/app/api/insights/ecg/[id]/__tests__/route.test.ts +++ b/src/app/api/insights/ecg/[id]/__tests__/route.test.ts @@ -32,9 +32,6 @@ vi.mock("@/lib/auth/audit", () => ({ auditLog: vi.fn().mockResolvedValue(undefined), })); vi.mock("@/lib/logging/transports", () => ({ emitIfSampled: vi.fn() })); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); vi.mock("next/headers", () => ({ headers: vi.fn(async () => ({ get: () => null })), cookies: vi.fn(async () => ({ diff --git a/src/app/api/insights/ecg/__tests__/route.test.ts b/src/app/api/insights/ecg/__tests__/route.test.ts index 413465864..2b01992ae 100644 --- a/src/app/api/insights/ecg/__tests__/route.test.ts +++ b/src/app/api/insights/ecg/__tests__/route.test.ts @@ -30,9 +30,6 @@ vi.mock("@/lib/auth/audit", () => ({ auditLog: vi.fn().mockResolvedValue(undefined), })); vi.mock("@/lib/logging/transports", () => ({ emitIfSampled: vi.fn() })); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); vi.mock("next/headers", () => ({ headers: vi.fn(async () => ({ get: () => null })), cookies: vi.fn(async () => ({ diff --git a/src/app/api/insights/layout/__tests__/route.test.ts b/src/app/api/insights/layout/__tests__/route.test.ts index 341812186..5cfd660ad 100644 --- a/src/app/api/insights/layout/__tests__/route.test.ts +++ b/src/app/api/insights/layout/__tests__/route.test.ts @@ -32,10 +32,6 @@ vi.mock("@/lib/logging/transports", () => ({ emitIfSampled: vi.fn(), })); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - vi.mock("@/lib/logging/context", async (importOriginal) => { const actual = await importOriginal(); return { diff --git a/src/app/api/insights/metric-status/__tests__/route.test.ts b/src/app/api/insights/metric-status/__tests__/route.test.ts index 0ed114640..fc703ea6e 100644 --- a/src/app/api/insights/metric-status/__tests__/route.test.ts +++ b/src/app/api/insights/metric-status/__tests__/route.test.ts @@ -32,10 +32,6 @@ vi.mock("@/lib/auth/audit", () => ({ vi.mock("@/lib/logging/transports", () => ({ emitIfSampled: vi.fn() })); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - vi.mock("next/headers", () => ({ headers: vi.fn(async () => ({ get: () => null })), cookies: vi.fn(async () => ({ diff --git a/src/app/api/insights/mood-status/__tests__/route.test.ts b/src/app/api/insights/mood-status/__tests__/route.test.ts index 10c532985..5133db316 100644 --- a/src/app/api/insights/mood-status/__tests__/route.test.ts +++ b/src/app/api/insights/mood-status/__tests__/route.test.ts @@ -23,10 +23,6 @@ vi.mock("@/lib/auth/audit", () => ({ vi.mock("@/lib/logging/transports", () => ({ emitIfSampled: vi.fn() })); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - vi.mock("next/headers", () => ({ headers: vi.fn(async () => ({ get: () => null })), cookies: vi.fn(async () => ({ diff --git a/src/app/api/insights/patterns/[id]/__tests__/route.test.ts b/src/app/api/insights/patterns/[id]/__tests__/route.test.ts index dca313586..4c1d6edb1 100644 --- a/src/app/api/insights/patterns/[id]/__tests__/route.test.ts +++ b/src/app/api/insights/patterns/[id]/__tests__/route.test.ts @@ -13,9 +13,6 @@ vi.mock("@/lib/auth/audit", () => ({ auditLog: vi.fn().mockResolvedValue(undefined), })); vi.mock("@/lib/logging/transports", () => ({ emitIfSampled: vi.fn() })); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); vi.mock("@/lib/modules/gate", async (importOriginal) => ({ ...(await importOriginal()), requireModuleEnabled: vi.fn(), diff --git a/src/app/api/insights/patterns/__tests__/route.test.ts b/src/app/api/insights/patterns/__tests__/route.test.ts index a1ca0dee5..d9483b169 100644 --- a/src/app/api/insights/patterns/__tests__/route.test.ts +++ b/src/app/api/insights/patterns/__tests__/route.test.ts @@ -8,9 +8,6 @@ vi.mock("@/lib/db", () => ({ })); vi.mock("@/lib/auth/session", () => ({ getSession: vi.fn() })); vi.mock("@/lib/logging/transports", () => ({ emitIfSampled: vi.fn() })); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); vi.mock("@/lib/modules/gate", async (importOriginal) => ({ ...(await importOriginal()), requireModuleEnabled: vi.fn(), diff --git a/src/app/api/insights/pregenerate/__tests__/route.test.ts b/src/app/api/insights/pregenerate/__tests__/route.test.ts index e85491006..570240ffe 100644 --- a/src/app/api/insights/pregenerate/__tests__/route.test.ts +++ b/src/app/api/insights/pregenerate/__tests__/route.test.ts @@ -19,10 +19,6 @@ vi.mock("@/lib/auth/audit", () => ({ vi.mock("@/lib/logging/transports", () => ({ emitIfSampled: vi.fn() })); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - vi.mock("next/headers", () => ({ headers: vi.fn(async () => ({ get: () => null })), cookies: vi.fn(async () => ({ diff --git a/src/app/api/insights/rhythm-events/__tests__/route.test.ts b/src/app/api/insights/rhythm-events/__tests__/route.test.ts index 65f5c094e..f5b5ba143 100644 --- a/src/app/api/insights/rhythm-events/__tests__/route.test.ts +++ b/src/app/api/insights/rhythm-events/__tests__/route.test.ts @@ -33,9 +33,6 @@ vi.mock("@/lib/auth/audit", () => ({ auditLog: vi.fn().mockResolvedValue(undefined), })); vi.mock("@/lib/logging/transports", () => ({ emitIfSampled: vi.fn() })); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); vi.mock("next/headers", () => ({ headers: vi.fn(async () => ({ get: () => null })), cookies: vi.fn(async () => ({ diff --git a/src/app/api/insights/targets/__tests__/route.test.ts b/src/app/api/insights/targets/__tests__/route.test.ts index b948897de..bfc24c417 100644 --- a/src/app/api/insights/targets/__tests__/route.test.ts +++ b/src/app/api/insights/targets/__tests__/route.test.ts @@ -65,10 +65,6 @@ vi.mock("@/lib/auth/audit", () => ({ auditLog: vi.fn().mockResolvedValue(undefined), })); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - vi.mock("@/lib/logging/transports", () => ({ emitIfSampled: vi.fn() })); vi.mock("next/headers", () => ({ diff --git a/src/app/api/integrations/healthkit/__tests__/route.test.ts b/src/app/api/integrations/healthkit/__tests__/route.test.ts index c7d7c6176..57e944359 100644 --- a/src/app/api/integrations/healthkit/__tests__/route.test.ts +++ b/src/app/api/integrations/healthkit/__tests__/route.test.ts @@ -30,10 +30,6 @@ vi.mock("@/lib/auth/audit", () => ({ vi.mock("@/lib/logging/transports", () => ({ emitIfSampled: vi.fn() })); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - vi.mock("next/headers", () => ({ headers: vi.fn(async () => ({ get: () => null })), cookies: vi.fn(async () => ({ diff --git a/src/app/api/labs/__tests__/error-contract.test.ts b/src/app/api/labs/__tests__/error-contract.test.ts index fb2d8c4a6..ec812c84f 100644 --- a/src/app/api/labs/__tests__/error-contract.test.ts +++ b/src/app/api/labs/__tests__/error-contract.test.ts @@ -46,9 +46,6 @@ vi.mock("@/lib/labs/store", () => ({ decryptNoteFromBytes: vi.fn(), })); vi.mock("@/lib/logging/transports", () => ({ emitIfSampled: vi.fn() })); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); vi.mock("next/headers", () => ({ headers: vi.fn(async () => ({ get: () => null })), cookies: vi.fn(async () => ({ diff --git a/src/app/api/labs/ocr/commit/__tests__/route.test.ts b/src/app/api/labs/ocr/commit/__tests__/route.test.ts index 435dd77eb..8f51cc8ae 100644 --- a/src/app/api/labs/ocr/commit/__tests__/route.test.ts +++ b/src/app/api/labs/ocr/commit/__tests__/route.test.ts @@ -63,9 +63,6 @@ vi.mock("@/lib/labs/serialise", () => ({ serialiseLabResult: (created: { id: string }) => ({ id: created.id }), })); vi.mock("@/lib/logging/transports", () => ({ emitIfSampled: vi.fn() })); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); vi.mock("next/headers", () => ({ headers: vi.fn(async () => ({ get: () => null })), cookies: vi.fn(async () => ({ diff --git a/src/app/api/labs/restore/__tests__/route.test.ts b/src/app/api/labs/restore/__tests__/route.test.ts index 5a4e3bcaf..bba0026cf 100644 --- a/src/app/api/labs/restore/__tests__/route.test.ts +++ b/src/app/api/labs/restore/__tests__/route.test.ts @@ -40,9 +40,6 @@ vi.mock("@/lib/cache/invalidate", () => ({ invalidateUserHealthScore: vi.fn(), })); vi.mock("@/lib/logging/transports", () => ({ emitIfSampled: vi.fn() })); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); vi.mock("next/headers", () => ({ headers: vi.fn(async () => ({ get: () => null })), cookies: vi.fn(async () => ({ diff --git a/src/app/api/measurement-categories/__tests__/route.test.ts b/src/app/api/measurement-categories/__tests__/route.test.ts index 6db396ff7..1fd11c4e2 100644 --- a/src/app/api/measurement-categories/__tests__/route.test.ts +++ b/src/app/api/measurement-categories/__tests__/route.test.ts @@ -9,10 +9,6 @@ vi.mock("@/lib/auth/audit", () => ({ vi.mock("@/lib/logging/transports", () => ({ emitIfSampled: vi.fn() })); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - vi.mock("next/headers", () => ({ headers: vi.fn(async () => ({ get: () => null })), cookies: vi.fn(async () => ({ diff --git a/src/app/api/measurements/[id]/__tests__/route.test.ts b/src/app/api/measurements/[id]/__tests__/route.test.ts index 01b3cb23b..6ab8c132b 100644 --- a/src/app/api/measurements/[id]/__tests__/route.test.ts +++ b/src/app/api/measurements/[id]/__tests__/route.test.ts @@ -19,9 +19,6 @@ vi.mock("@/lib/auth/audit", () => ({ auditLog: vi.fn().mockResolvedValue(undefined), })); vi.mock("@/lib/logging/transports", () => ({ emitIfSampled: vi.fn() })); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); vi.mock("@/lib/cache/invalidate", () => ({ invalidateUserMeasurements: vi.fn(), })); diff --git a/src/app/api/measurements/__tests__/group-by-day.test.ts b/src/app/api/measurements/__tests__/group-by-day.test.ts index db8f542f9..4a305dd28 100644 --- a/src/app/api/measurements/__tests__/group-by-day.test.ts +++ b/src/app/api/measurements/__tests__/group-by-day.test.ts @@ -48,9 +48,6 @@ vi.mock("@/lib/db", () => ({ vi.mock("@/lib/auth/session", () => ({ getSession: vi.fn() })); vi.mock("@/lib/auth/audit", () => ({ auditLog: vi.fn() })); vi.mock("@/lib/logging/transports", () => ({ emitIfSampled: vi.fn() })); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); vi.mock("next/headers", () => ({ headers: vi.fn(async () => ({ get: () => null })), cookies: vi.fn(async () => ({ diff --git a/src/app/api/measurements/__tests__/put-duplicate-timestamp.test.ts b/src/app/api/measurements/__tests__/put-duplicate-timestamp.test.ts index 2424881af..6c6abdf48 100644 --- a/src/app/api/measurements/__tests__/put-duplicate-timestamp.test.ts +++ b/src/app/api/measurements/__tests__/put-duplicate-timestamp.test.ts @@ -16,10 +16,6 @@ vi.mock("@/lib/auth/audit", () => ({ auditLog: vi.fn() })); vi.mock("@/lib/logging/transports", () => ({ emitIfSampled: vi.fn() })); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - vi.mock("next/headers", () => ({ headers: vi.fn(async () => ({ get: () => null })), cookies: vi.fn(async () => ({ diff --git a/src/app/api/measurements/__tests__/range-aggregation-route.test.ts b/src/app/api/measurements/__tests__/range-aggregation-route.test.ts index d5f0db0d6..82360e130 100644 --- a/src/app/api/measurements/__tests__/range-aggregation-route.test.ts +++ b/src/app/api/measurements/__tests__/range-aggregation-route.test.ts @@ -48,9 +48,6 @@ vi.mock("@/lib/rollups/measurement-rollups", async () => { vi.mock("@/lib/auth/session", () => ({ getSession: vi.fn() })); vi.mock("@/lib/auth/audit", () => ({ auditLog: vi.fn() })); vi.mock("@/lib/logging/transports", () => ({ emitIfSampled: vi.fn() })); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); vi.mock("next/headers", () => ({ headers: vi.fn(async () => ({ get: () => null })), cookies: vi.fn(async () => ({ diff --git a/src/app/api/measurements/__tests__/zod-multi-issue.test.ts b/src/app/api/measurements/__tests__/zod-multi-issue.test.ts index 894a71648..695d56780 100644 --- a/src/app/api/measurements/__tests__/zod-multi-issue.test.ts +++ b/src/app/api/measurements/__tests__/zod-multi-issue.test.ts @@ -43,9 +43,6 @@ vi.mock("@/lib/db", () => ({ vi.mock("@/lib/auth/session", () => ({ getSession: vi.fn() })); vi.mock("@/lib/auth/audit", () => ({ auditLog: vi.fn() })); vi.mock("@/lib/logging/transports", () => ({ emitIfSampled: vi.fn() })); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); vi.mock("@/lib/idempotency", () => ({ withIdempotency: (fn: (...args: Args) => Promise) => diff --git a/src/app/api/measurements/batch/__tests__/aggregated-hr-wire.test.ts b/src/app/api/measurements/batch/__tests__/aggregated-hr-wire.test.ts index 085fe93d4..b8e4c6d01 100644 --- a/src/app/api/measurements/batch/__tests__/aggregated-hr-wire.test.ts +++ b/src/app/api/measurements/batch/__tests__/aggregated-hr-wire.test.ts @@ -99,9 +99,6 @@ vi.mock("@/lib/auth/audit", () => ({ auditLog: vi.fn().mockResolvedValue(undefined), })); vi.mock("@/lib/logging/transports", () => ({ emitIfSampled: vi.fn() })); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); vi.mock("@/lib/rate-limit", () => ({ checkRateLimit: vi.fn() })); vi.mock("@/lib/jobs/pr-detection", () => ({ enqueuePrDetection: vi.fn().mockResolvedValue(undefined), diff --git a/src/app/api/measurements/batch/__tests__/duplicate-prefilter.test.ts b/src/app/api/measurements/batch/__tests__/duplicate-prefilter.test.ts index af4a4a395..8f21a1f31 100644 --- a/src/app/api/measurements/batch/__tests__/duplicate-prefilter.test.ts +++ b/src/app/api/measurements/batch/__tests__/duplicate-prefilter.test.ts @@ -226,9 +226,6 @@ vi.mock("@/lib/auth/audit", () => ({ auditLog: vi.fn().mockResolvedValue(undefined), })); vi.mock("@/lib/logging/transports", () => ({ emitIfSampled: vi.fn() })); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); vi.mock("@/lib/rate-limit", () => ({ checkRateLimit: vi.fn() })); vi.mock("@/lib/jobs/pr-detection", () => ({ enqueuePrDetection: vi.fn().mockResolvedValue(undefined), diff --git a/src/app/api/measurements/batch/__tests__/hr-bucket-observability.test.ts b/src/app/api/measurements/batch/__tests__/hr-bucket-observability.test.ts index 188687af5..8d5eb4a0e 100644 --- a/src/app/api/measurements/batch/__tests__/hr-bucket-observability.test.ts +++ b/src/app/api/measurements/batch/__tests__/hr-bucket-observability.test.ts @@ -106,9 +106,6 @@ vi.mock("@/lib/auth/audit", () => ({ auditLog: vi.fn().mockResolvedValue(undefined), })); vi.mock("@/lib/logging/transports", () => ({ emitIfSampled: vi.fn() })); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); vi.mock("@/lib/rate-limit", () => ({ checkRateLimit: vi.fn() })); vi.mock("@/lib/jobs/pr-detection", () => ({ enqueuePrDetection: vi.fn().mockResolvedValue(undefined), diff --git a/src/app/api/measurements/batch/__tests__/insert-returning-arrivals.test.ts b/src/app/api/measurements/batch/__tests__/insert-returning-arrivals.test.ts index e7eb79f74..539305fb0 100644 --- a/src/app/api/measurements/batch/__tests__/insert-returning-arrivals.test.ts +++ b/src/app/api/measurements/batch/__tests__/insert-returning-arrivals.test.ts @@ -77,9 +77,6 @@ vi.mock("@/lib/auth/audit", () => ({ auditLog: vi.fn().mockResolvedValue(undefined), })); vi.mock("@/lib/logging/transports", () => ({ emitIfSampled: vi.fn() })); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); vi.mock("@/lib/rate-limit", () => ({ checkRateLimit: vi.fn() })); vi.mock("@/lib/jobs/pr-detection", () => ({ enqueuePrDetection: vi.fn().mockResolvedValue(undefined), diff --git a/src/app/api/measurements/batch/__tests__/issue-paths.test.ts b/src/app/api/measurements/batch/__tests__/issue-paths.test.ts index 8d7edf6c0..4b864ee89 100644 --- a/src/app/api/measurements/batch/__tests__/issue-paths.test.ts +++ b/src/app/api/measurements/batch/__tests__/issue-paths.test.ts @@ -38,9 +38,6 @@ vi.mock("@/lib/auth/audit", () => ({ auditLog: vi.fn().mockResolvedValue(undefined), })); vi.mock("@/lib/logging/transports", () => ({ emitIfSampled: vi.fn() })); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); vi.mock("@/lib/rate-limit", () => ({ checkRateLimit: vi.fn() })); vi.mock("@/lib/jobs/pr-detection", () => ({ enqueuePrDetection: vi.fn().mockResolvedValue(undefined), diff --git a/src/app/api/measurements/batch/__tests__/pr-detection-hook.test.ts b/src/app/api/measurements/batch/__tests__/pr-detection-hook.test.ts index e7c8f58f2..f29879bc8 100644 --- a/src/app/api/measurements/batch/__tests__/pr-detection-hook.test.ts +++ b/src/app/api/measurements/batch/__tests__/pr-detection-hook.test.ts @@ -58,10 +58,6 @@ vi.mock("@/lib/auth/audit", () => ({ vi.mock("@/lib/logging/transports", () => ({ emitIfSampled: vi.fn() })); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - vi.mock("@/lib/rate-limit", () => ({ checkRateLimit: vi.fn(), })); diff --git a/src/app/api/measurements/batch/__tests__/refusal-detail.test.ts b/src/app/api/measurements/batch/__tests__/refusal-detail.test.ts index 921cda502..34a571f02 100644 --- a/src/app/api/measurements/batch/__tests__/refusal-detail.test.ts +++ b/src/app/api/measurements/batch/__tests__/refusal-detail.test.ts @@ -45,9 +45,6 @@ vi.mock("@/lib/auth/audit", () => ({ auditLog: vi.fn().mockResolvedValue(undefined), })); vi.mock("@/lib/logging/transports", () => ({ emitIfSampled: vi.fn() })); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); vi.mock("@/lib/rate-limit", () => ({ checkRateLimit: vi.fn() })); vi.mock("@/lib/jobs/pr-detection", () => ({ enqueuePrDetection: vi.fn().mockResolvedValue(undefined), diff --git a/src/app/api/measurements/batch/__tests__/sync-trigger.test.ts b/src/app/api/measurements/batch/__tests__/sync-trigger.test.ts index 38f2318fb..b73a963fa 100644 --- a/src/app/api/measurements/batch/__tests__/sync-trigger.test.ts +++ b/src/app/api/measurements/batch/__tests__/sync-trigger.test.ts @@ -108,9 +108,6 @@ vi.mock("@/lib/auth/audit", () => ({ auditLog: vi.fn().mockResolvedValue(undefined), })); vi.mock("@/lib/logging/transports", () => ({ emitIfSampled: vi.fn() })); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); vi.mock("@/lib/rate-limit", () => ({ checkRateLimit: vi.fn() })); vi.mock("@/lib/jobs/pr-detection", () => ({ enqueuePrDetection: vi.fn().mockResolvedValue(undefined), diff --git a/src/app/api/measurements/batch/__tests__/timestamp-plausibility.test.ts b/src/app/api/measurements/batch/__tests__/timestamp-plausibility.test.ts index 8fdeb46da..b9a2ec68b 100644 --- a/src/app/api/measurements/batch/__tests__/timestamp-plausibility.test.ts +++ b/src/app/api/measurements/batch/__tests__/timestamp-plausibility.test.ts @@ -48,10 +48,6 @@ vi.mock("@/lib/auth/audit", () => ({ vi.mock("@/lib/logging/transports", () => ({ emitIfSampled: vi.fn() })); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - vi.mock("@/lib/rate-limit", () => ({ checkRateLimit: vi.fn(), })); diff --git a/src/app/api/measurements/batch/__tests__/unstable-external-id.test.ts b/src/app/api/measurements/batch/__tests__/unstable-external-id.test.ts index a68fdd012..c03197a76 100644 --- a/src/app/api/measurements/batch/__tests__/unstable-external-id.test.ts +++ b/src/app/api/measurements/batch/__tests__/unstable-external-id.test.ts @@ -46,10 +46,6 @@ vi.mock("@/lib/auth/audit", () => ({ vi.mock("@/lib/logging/transports", () => ({ emitIfSampled: vi.fn() })); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - vi.mock("@/lib/rate-limit", () => ({ checkRateLimit: vi.fn(), })); diff --git a/src/app/api/measurements/bulk-delete/__tests__/route.test.ts b/src/app/api/measurements/bulk-delete/__tests__/route.test.ts index f546f195d..55f4cb17c 100644 --- a/src/app/api/measurements/bulk-delete/__tests__/route.test.ts +++ b/src/app/api/measurements/bulk-delete/__tests__/route.test.ts @@ -68,9 +68,6 @@ vi.mock("@/lib/rollups/measurement-rollups", async () => { }; }); vi.mock("@/lib/logging/transports", () => ({ emitIfSampled: vi.fn() })); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); vi.mock("next/headers", () => ({ headers: vi.fn(async () => ({ get: () => null })), cookies: vi.fn(async () => ({ diff --git a/src/app/api/measurements/by-external-ids/__tests__/route.test.ts b/src/app/api/measurements/by-external-ids/__tests__/route.test.ts index 5cfee6105..58729c791 100644 --- a/src/app/api/measurements/by-external-ids/__tests__/route.test.ts +++ b/src/app/api/measurements/by-external-ids/__tests__/route.test.ts @@ -45,9 +45,6 @@ vi.mock("@/lib/rollups/measurement-rollups", async () => { }; }); vi.mock("@/lib/logging/transports", () => ({ emitIfSampled: vi.fn() })); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); vi.mock("next/headers", () => ({ headers: vi.fn(async () => ({ get: () => null })), cookies: vi.fn(async () => ({ diff --git a/src/app/api/measurements/restore/__tests__/route.test.ts b/src/app/api/measurements/restore/__tests__/route.test.ts index 73ce2540e..6678f068c 100644 --- a/src/app/api/measurements/restore/__tests__/route.test.ts +++ b/src/app/api/measurements/restore/__tests__/route.test.ts @@ -68,9 +68,6 @@ vi.mock("@/lib/rollups/measurement-rollups", async () => { }; }); vi.mock("@/lib/logging/transports", () => ({ emitIfSampled: vi.fn() })); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); vi.mock("next/headers", () => ({ headers: vi.fn(async () => ({ get: () => null })), cookies: vi.fn(async () => ({ diff --git a/src/app/api/measurements/series-batch/__tests__/route.test.ts b/src/app/api/measurements/series-batch/__tests__/route.test.ts index 9e34cea5d..d0184557e 100644 --- a/src/app/api/measurements/series-batch/__tests__/route.test.ts +++ b/src/app/api/measurements/series-batch/__tests__/route.test.ts @@ -15,9 +15,6 @@ import { describe, it, expect, vi, beforeEach } from "vitest"; import { NextRequest } from "next/server"; vi.mock("@/lib/auth/session", () => ({ getSession: vi.fn() })); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); vi.mock("@/lib/logging/transports", () => ({ emitIfSampled: vi.fn() })); vi.mock("@/lib/logging/context", async (importOriginal) => { const actual = await importOriginal(); diff --git a/src/app/api/measurements/series/__tests__/route.test.ts b/src/app/api/measurements/series/__tests__/route.test.ts index ea63202db..2b529b188 100644 --- a/src/app/api/measurements/series/__tests__/route.test.ts +++ b/src/app/api/measurements/series/__tests__/route.test.ts @@ -84,10 +84,6 @@ vi.mock("@/lib/rollups/measurement-read", () => ({ loadUserSourcePriority: vi.fn(async () => null), })); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - vi.mock("@/lib/logging/context", async (importOriginal) => { const actual = await importOriginal(); return { diff --git a/src/app/api/measurements/series/__tests__/unknown-query-param-open.test.ts b/src/app/api/measurements/series/__tests__/unknown-query-param-open.test.ts index b852744ff..701429dfe 100644 --- a/src/app/api/measurements/series/__tests__/unknown-query-param-open.test.ts +++ b/src/app/api/measurements/series/__tests__/unknown-query-param-open.test.ts @@ -39,10 +39,6 @@ vi.mock("@/lib/rollups/measurement-read", () => ({ loadUserSourcePriority: vi.fn(async () => null), })); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - vi.mock("@/lib/logging/context", async (importOriginal) => { const actual = await importOriginal(); return { ...actual, annotate: vi.fn() }; diff --git a/src/app/api/medications/[id]/__tests__/route.test.ts b/src/app/api/medications/[id]/__tests__/route.test.ts index 39b43f603..f78763616 100644 --- a/src/app/api/medications/[id]/__tests__/route.test.ts +++ b/src/app/api/medications/[id]/__tests__/route.test.ts @@ -104,9 +104,6 @@ vi.mock("@/lib/medication-category", () => ({ setMedicationCategory: vi.fn().mockResolvedValue("OTHER"), })); vi.mock("@/lib/logging/transports", () => ({ emitIfSampled: vi.fn() })); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); vi.mock("next/headers", () => ({ headers: vi.fn(async () => ({ get: () => null })), cookies: vi.fn(async () => ({ diff --git a/src/app/api/medications/[id]/compliance/__tests__/route.test.ts b/src/app/api/medications/[id]/compliance/__tests__/route.test.ts index 7e39647d6..b5c3258a3 100644 --- a/src/app/api/medications/[id]/compliance/__tests__/route.test.ts +++ b/src/app/api/medications/[id]/compliance/__tests__/route.test.ts @@ -54,10 +54,6 @@ vi.mock("@/lib/rate-limit", () => ({ vi.mock("@/lib/logging/transports", () => ({ emitIfSampled: vi.fn() })); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - vi.mock("next/headers", () => ({ headers: vi.fn(async () => ({ get: () => null })), cookies: vi.fn(async () => ({ diff --git a/src/app/api/medications/[id]/dose-history/__tests__/route.test.ts b/src/app/api/medications/[id]/dose-history/__tests__/route.test.ts index fe998e2a6..5c55e140a 100644 --- a/src/app/api/medications/[id]/dose-history/__tests__/route.test.ts +++ b/src/app/api/medications/[id]/dose-history/__tests__/route.test.ts @@ -42,9 +42,6 @@ vi.mock("@/lib/auth/audit", () => ({ auditLog: vi.fn().mockResolvedValue(undefined), })); vi.mock("@/lib/logging/transports", () => ({ emitIfSampled: vi.fn() })); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); vi.mock("next/headers", () => ({ headers: vi.fn(async () => ({ get: () => null })), cookies: vi.fn(async () => ({ diff --git a/src/app/api/medications/[id]/glp1/__tests__/route.test.ts b/src/app/api/medications/[id]/glp1/__tests__/route.test.ts index 2b28fec55..156492bfc 100644 --- a/src/app/api/medications/[id]/glp1/__tests__/route.test.ts +++ b/src/app/api/medications/[id]/glp1/__tests__/route.test.ts @@ -47,10 +47,6 @@ vi.mock("@/lib/rate-limit", () => ({ vi.mock("@/lib/logging/transports", () => ({ emitIfSampled: vi.fn() })); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - vi.mock("next/headers", () => ({ headers: vi.fn(async () => ({ get: () => null })), cookies: vi.fn(async () => ({ diff --git a/src/app/api/medications/[id]/intake/[eventId]/__tests__/route.test.ts b/src/app/api/medications/[id]/intake/[eventId]/__tests__/route.test.ts index cedb34685..2f4eb9b7a 100644 --- a/src/app/api/medications/[id]/intake/[eventId]/__tests__/route.test.ts +++ b/src/app/api/medications/[id]/intake/[eventId]/__tests__/route.test.ts @@ -41,9 +41,6 @@ vi.mock("@/lib/medications/dose-day-refresh", () => ({ refreshDoseSlot: vi.fn().mockResolvedValue(undefined), })); vi.mock("@/lib/logging/transports", () => ({ emitIfSampled: vi.fn() })); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); vi.mock("next/headers", () => ({ headers: vi.fn(async () => ({ get: () => null })), cookies: vi.fn(async () => ({ diff --git a/src/app/api/medications/[id]/intake/__tests__/route.test.ts b/src/app/api/medications/[id]/intake/__tests__/route.test.ts index 42b3eaf50..e5bfe0558 100644 --- a/src/app/api/medications/[id]/intake/__tests__/route.test.ts +++ b/src/app/api/medications/[id]/intake/__tests__/route.test.ts @@ -88,10 +88,6 @@ vi.mock("@/lib/auth/audit", () => ({ auditLog: vi.fn() })); vi.mock("@/lib/logging/transports", () => ({ emitIfSampled: vi.fn() })); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - vi.mock("next/headers", () => ({ headers: vi.fn(async () => ({ get: () => null })), cookies: vi.fn(async () => ({ diff --git a/src/app/api/medications/[id]/intake/__tests__/source-provenance.test.ts b/src/app/api/medications/[id]/intake/__tests__/source-provenance.test.ts index 759d6ff64..2a24675ad 100644 --- a/src/app/api/medications/[id]/intake/__tests__/source-provenance.test.ts +++ b/src/app/api/medications/[id]/intake/__tests__/source-provenance.test.ts @@ -109,10 +109,6 @@ vi.mock("@/lib/auth/audit", () => ({ auditLog: vi.fn().mockResolvedValue(undefined), })); vi.mock("@/lib/logging/transports", () => ({ emitIfSampled: vi.fn() })); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - // Default to no Authorization header; the Bearer tests override this. const headerStore = { authorization: null as string | null }; vi.mock("next/headers", () => ({ diff --git a/src/app/api/medications/[id]/intake/import/__tests__/route.test.ts b/src/app/api/medications/[id]/intake/import/__tests__/route.test.ts index e04be16be..933854051 100644 --- a/src/app/api/medications/[id]/intake/import/__tests__/route.test.ts +++ b/src/app/api/medications/[id]/intake/import/__tests__/route.test.ts @@ -45,9 +45,6 @@ vi.mock("@/lib/jobs/boss-instance", () => ({ getGlobalBoss: vi.fn(), })); vi.mock("@/lib/logging/transports", () => ({ emitIfSampled: vi.fn() })); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); vi.mock("next/headers", () => ({ headers: vi.fn(async () => ({ get: () => null })), cookies: vi.fn(async () => ({ diff --git a/src/app/api/medications/[id]/schedule-revisions/__tests__/route.test.ts b/src/app/api/medications/[id]/schedule-revisions/__tests__/route.test.ts index a54c4b903..9cffd05d0 100644 --- a/src/app/api/medications/[id]/schedule-revisions/__tests__/route.test.ts +++ b/src/app/api/medications/[id]/schedule-revisions/__tests__/route.test.ts @@ -43,9 +43,6 @@ vi.mock("@/lib/auth/audit", () => ({ auditLog: vi.fn().mockResolvedValue(undefined), })); vi.mock("@/lib/logging/transports", () => ({ emitIfSampled: vi.fn() })); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); vi.mock("next/headers", () => ({ headers: vi.fn(async () => ({ get: () => null })), cookies: vi.fn(async () => ({ diff --git a/src/app/api/medications/__tests__/route.test.ts b/src/app/api/medications/__tests__/route.test.ts index 1159f63a2..b8a7c5527 100644 --- a/src/app/api/medications/__tests__/route.test.ts +++ b/src/app/api/medications/__tests__/route.test.ts @@ -107,9 +107,6 @@ vi.mock("@/lib/tz/local-day", async (importOriginal) => ({ .mockReturnValue({ start: new Date(), end: new Date() }), })); vi.mock("@/lib/logging/transports", () => ({ emitIfSampled: vi.fn() })); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); vi.mock("next/headers", () => ({ headers: vi.fn(async () => ({ get: () => null })), cookies: vi.fn(async () => ({ diff --git a/src/app/api/medications/compliance/__tests__/route.test.ts b/src/app/api/medications/compliance/__tests__/route.test.ts index 1f7059142..15e0a3e90 100644 --- a/src/app/api/medications/compliance/__tests__/route.test.ts +++ b/src/app/api/medications/compliance/__tests__/route.test.ts @@ -38,10 +38,6 @@ vi.mock("@/lib/rate-limit", () => ({ vi.mock("@/lib/logging/transports", () => ({ emitIfSampled: vi.fn() })); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - vi.mock("next/headers", () => ({ headers: vi.fn(async () => ({ get: () => null })), cookies: vi.fn(async () => ({ diff --git a/src/app/api/medications/intake/__tests__/route.test.ts b/src/app/api/medications/intake/__tests__/route.test.ts index 87d35347f..3b0cf8ce1 100644 --- a/src/app/api/medications/intake/__tests__/route.test.ts +++ b/src/app/api/medications/intake/__tests__/route.test.ts @@ -65,10 +65,6 @@ vi.mock("@/lib/notifications/medication-intake-sync", () => ({ vi.mock("@/lib/logging/transports", () => ({ emitIfSampled: vi.fn() })); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - vi.mock("next/headers", () => ({ headers: vi.fn(async () => ({ get: () => null })), cookies: vi.fn(async () => ({ diff --git a/src/app/api/medications/intake/bulk/__tests__/dose-arrival-scope.test.ts b/src/app/api/medications/intake/bulk/__tests__/dose-arrival-scope.test.ts index 18232033f..d0c59a771 100644 --- a/src/app/api/medications/intake/bulk/__tests__/dose-arrival-scope.test.ts +++ b/src/app/api/medications/intake/bulk/__tests__/dose-arrival-scope.test.ts @@ -54,9 +54,6 @@ vi.mock("@/lib/notifications/medication-intake-sync", () => ({ queueMedicationIntakeSync: vi.fn(), })); vi.mock("@/lib/logging/transports", () => ({ emitIfSampled: vi.fn() })); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); vi.mock("next/headers", () => ({ headers: vi.fn(async () => ({ get: () => null })), cookies: vi.fn(async () => ({ diff --git a/src/app/api/medications/intake/bulk/__tests__/route.test.ts b/src/app/api/medications/intake/bulk/__tests__/route.test.ts index 006d9c7ee..ff800ad0d 100644 --- a/src/app/api/medications/intake/bulk/__tests__/route.test.ts +++ b/src/app/api/medications/intake/bulk/__tests__/route.test.ts @@ -56,9 +56,6 @@ vi.mock("@/lib/medications/dose-day-refresh", () => ({ dayKeyForScheduledFor: vi.fn().mockReturnValue("2026-01-01"), })); vi.mock("@/lib/logging/transports", () => ({ emitIfSampled: vi.fn() })); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); vi.mock("next/headers", () => ({ headers: vi.fn(async () => ({ get: () => null })), cookies: vi.fn(async () => ({ diff --git a/src/app/api/medications/intake/dose-history-import/__tests__/route.test.ts b/src/app/api/medications/intake/dose-history-import/__tests__/route.test.ts index 491f52dd5..39b3c6b1b 100644 --- a/src/app/api/medications/intake/dose-history-import/__tests__/route.test.ts +++ b/src/app/api/medications/intake/dose-history-import/__tests__/route.test.ts @@ -40,9 +40,6 @@ vi.mock("@/lib/auth/audit", () => ({ vi.mock("@/lib/rate-limit", () => ({ checkRateLimit: vi.fn() })); vi.mock("@/lib/jobs/boss-instance", () => ({ getGlobalBoss: vi.fn() })); vi.mock("@/lib/logging/transports", () => ({ emitIfSampled: vi.fn() })); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); vi.mock("next/headers", () => ({ headers: vi.fn(async () => ({ get: () => null })), cookies: vi.fn(async () => ({ diff --git a/src/app/api/medications/layout/__tests__/route.test.ts b/src/app/api/medications/layout/__tests__/route.test.ts index cc8f500b6..3d7e94637 100644 --- a/src/app/api/medications/layout/__tests__/route.test.ts +++ b/src/app/api/medications/layout/__tests__/route.test.ts @@ -32,10 +32,6 @@ vi.mock("@/lib/logging/transports", () => ({ emitIfSampled: vi.fn(), })); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - vi.mock("next/headers", () => ({ headers: vi.fn(async () => ({ get: () => null })), cookies: vi.fn(async () => ({ diff --git a/src/app/api/mental-health/assessments/[id]/__tests__/route.test.ts b/src/app/api/mental-health/assessments/[id]/__tests__/route.test.ts index be19cee4b..c1fa7bdde 100644 --- a/src/app/api/mental-health/assessments/[id]/__tests__/route.test.ts +++ b/src/app/api/mental-health/assessments/[id]/__tests__/route.test.ts @@ -34,9 +34,6 @@ vi.mock("@/lib/ai/coach/bytes-codec", () => ({ vi.mock("@/lib/auth/session", () => ({ getSession: vi.fn() })); vi.mock("@/lib/logging/transports", () => ({ emitIfSampled: vi.fn() })); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); vi.mock("next/headers", () => ({ headers: vi.fn(async () => ({ get: () => null })), cookies: vi.fn(async () => ({ diff --git a/src/app/api/mental-health/assessments/__tests__/route.test.ts b/src/app/api/mental-health/assessments/__tests__/route.test.ts index 3dfa8ded0..bc4e01570 100644 --- a/src/app/api/mental-health/assessments/__tests__/route.test.ts +++ b/src/app/api/mental-health/assessments/__tests__/route.test.ts @@ -52,9 +52,6 @@ vi.mock("@/lib/auth/audit", () => ({ auditLog: vi.fn().mockResolvedValue(undefined), })); vi.mock("@/lib/logging/transports", () => ({ emitIfSampled: vi.fn() })); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); vi.mock("next/headers", () => ({ headers: vi.fn(async () => ({ get: () => null })), cookies: vi.fn(async () => ({ diff --git a/src/app/api/meta/capabilities/__tests__/route.test.ts b/src/app/api/meta/capabilities/__tests__/route.test.ts index 1a068b6d0..c82648f28 100644 --- a/src/app/api/meta/capabilities/__tests__/route.test.ts +++ b/src/app/api/meta/capabilities/__tests__/route.test.ts @@ -29,10 +29,6 @@ vi.mock("@/lib/auth/audit", () => ({ vi.mock("@/lib/logging/transports", () => ({ emitIfSampled: vi.fn() })); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - vi.mock("next/headers", () => ({ headers: vi.fn(async () => ({ get: () => null })), cookies: vi.fn(async () => ({ diff --git a/src/app/api/mood-entries/[id]/__tests__/route.test.ts b/src/app/api/mood-entries/[id]/__tests__/route.test.ts index 19727e41f..0d0055689 100644 --- a/src/app/api/mood-entries/[id]/__tests__/route.test.ts +++ b/src/app/api/mood-entries/[id]/__tests__/route.test.ts @@ -56,9 +56,6 @@ vi.mock("@/lib/rollups/mood-rollups", () => ({ recomputeMoodBucketsForEntry: vi.fn().mockResolvedValue(undefined), })); vi.mock("@/lib/logging/transports", () => ({ emitIfSampled: vi.fn() })); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); vi.mock("next/headers", () => ({ headers: vi.fn(async () => ({ get: () => null })), cookies: vi.fn(async () => ({ diff --git a/src/app/api/mood-entries/__tests__/route.test.ts b/src/app/api/mood-entries/__tests__/route.test.ts index db99a0445..d13157028 100644 --- a/src/app/api/mood-entries/__tests__/route.test.ts +++ b/src/app/api/mood-entries/__tests__/route.test.ts @@ -88,9 +88,6 @@ vi.mock("@/lib/rollups/mood-rollups", () => ({ recomputeMoodBucketsForEntry: vi.fn().mockResolvedValue(undefined), })); vi.mock("@/lib/logging/transports", () => ({ emitIfSampled: vi.fn() })); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); vi.mock("next/headers", () => ({ headers: vi.fn(async () => ({ get: () => null })), cookies: vi.fn(async () => ({ diff --git a/src/app/api/mood-entries/bulk-delete/__tests__/route.test.ts b/src/app/api/mood-entries/bulk-delete/__tests__/route.test.ts index f90b842bc..e78b9e4f3 100644 --- a/src/app/api/mood-entries/bulk-delete/__tests__/route.test.ts +++ b/src/app/api/mood-entries/bulk-delete/__tests__/route.test.ts @@ -40,9 +40,6 @@ vi.mock("@/lib/rollups/mood-rollups", () => ({ recomputeMoodBucketsForEntry: vi.fn().mockResolvedValue(undefined), })); vi.mock("@/lib/logging/transports", () => ({ emitIfSampled: vi.fn() })); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); vi.mock("next/headers", () => ({ headers: vi.fn(async () => ({ get: () => null })), cookies: vi.fn(async () => ({ diff --git a/src/app/api/mood-entries/bulk/__tests__/route.test.ts b/src/app/api/mood-entries/bulk/__tests__/route.test.ts index e77da8c5b..a4f9f0628 100644 --- a/src/app/api/mood-entries/bulk/__tests__/route.test.ts +++ b/src/app/api/mood-entries/bulk/__tests__/route.test.ts @@ -83,9 +83,6 @@ vi.mock("@/lib/rollups/mood-rollups", () => ({ recomputeMoodBucketsForEntry: vi.fn().mockResolvedValue(undefined), })); vi.mock("@/lib/logging/transports", () => ({ emitIfSampled: vi.fn() })); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); vi.mock("next/headers", () => ({ headers: vi.fn(async () => ({ get: () => null })), cookies: vi.fn(async () => ({ diff --git a/src/app/api/mood-entries/restore/__tests__/route.test.ts b/src/app/api/mood-entries/restore/__tests__/route.test.ts index 7ff413f63..d015a817d 100644 --- a/src/app/api/mood-entries/restore/__tests__/route.test.ts +++ b/src/app/api/mood-entries/restore/__tests__/route.test.ts @@ -41,9 +41,6 @@ vi.mock("@/lib/rollups/mood-rollups", () => ({ recomputeMoodBucketsForEntry: vi.fn().mockResolvedValue(undefined), })); vi.mock("@/lib/logging/transports", () => ({ emitIfSampled: vi.fn() })); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); vi.mock("next/headers", () => ({ headers: vi.fn(async () => ({ get: () => null })), cookies: vi.fn(async () => ({ diff --git a/src/app/api/mood/analytics/__tests__/route.test.ts b/src/app/api/mood/analytics/__tests__/route.test.ts index 9e538462f..dfcefc9e7 100644 --- a/src/app/api/mood/analytics/__tests__/route.test.ts +++ b/src/app/api/mood/analytics/__tests__/route.test.ts @@ -43,10 +43,6 @@ vi.mock("@/lib/modules/gate", () => ({ requireModuleEnabled: vi.fn(async () => ({ enabled: true })), })); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - vi.mock("next/headers", () => ({ headers: vi.fn(async () => ({ get: () => null })), cookies: vi.fn(async () => ({ diff --git a/src/app/api/mood/insights/__tests__/route.test.ts b/src/app/api/mood/insights/__tests__/route.test.ts index a00ef9dbf..deea12a50 100644 --- a/src/app/api/mood/insights/__tests__/route.test.ts +++ b/src/app/api/mood/insights/__tests__/route.test.ts @@ -15,9 +15,6 @@ vi.mock("@/lib/cache/server-cache", () => ({ caches: { moodInsights: {} }, })); vi.mock("@/lib/logging/transports", () => ({ emitIfSampled: vi.fn() })); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); vi.mock("next/headers", () => ({ headers: vi.fn(async () => ({ get: () => null })), cookies: vi.fn(async () => ({ diff --git a/src/app/api/notifications/action/[token]/__tests__/route.test.ts b/src/app/api/notifications/action/[token]/__tests__/route.test.ts index 54f10d451..3de1caaba 100644 --- a/src/app/api/notifications/action/[token]/__tests__/route.test.ts +++ b/src/app/api/notifications/action/[token]/__tests__/route.test.ts @@ -27,10 +27,6 @@ vi.mock("@/lib/mood/create-from-telegram", () => ({ logTelegramMood: vi.fn(), })); vi.mock("@/lib/logging/transports", () => ({ emitIfSampled: vi.fn() })); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - import { POST } from "../route"; import { prisma } from "@/lib/db"; import { checkAuthSurfaceRateLimit, checkRateLimit } from "@/lib/rate-limit"; diff --git a/src/app/api/notifications/status/__tests__/route.test.ts b/src/app/api/notifications/status/__tests__/route.test.ts index dac4be431..28f01b7bb 100644 --- a/src/app/api/notifications/status/__tests__/route.test.ts +++ b/src/app/api/notifications/status/__tests__/route.test.ts @@ -38,10 +38,6 @@ vi.mock("@/lib/auth/audit", () => ({ vi.mock("@/lib/logging/transports", () => ({ emitIfSampled: vi.fn() })); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - vi.mock("next/headers", () => ({ headers: vi.fn(async () => ({ get: () => null })), cookies: vi.fn(async () => ({ diff --git a/src/app/api/nutrients/__tests__/route.test.ts b/src/app/api/nutrients/__tests__/route.test.ts index 8f2d5100c..0315b747a 100644 --- a/src/app/api/nutrients/__tests__/route.test.ts +++ b/src/app/api/nutrients/__tests__/route.test.ts @@ -23,9 +23,6 @@ vi.mock("@/lib/modules/gate", () => ({ vi.mock("@/lib/auth/session", () => ({ getSession: vi.fn() })); vi.mock("@/lib/logging/transports", () => ({ emitIfSampled: vi.fn() })); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); vi.mock("next/headers", () => ({ headers: vi.fn(async () => ({ get: () => null })), cookies: vi.fn(async () => ({ diff --git a/src/app/api/nutrients/batch/__tests__/route.test.ts b/src/app/api/nutrients/batch/__tests__/route.test.ts index cc6ea246a..63079a20b 100644 --- a/src/app/api/nutrients/batch/__tests__/route.test.ts +++ b/src/app/api/nutrients/batch/__tests__/route.test.ts @@ -49,9 +49,6 @@ vi.mock("@/lib/logging/transports", () => ({ emitIfSampled: vi.fn() })); vi.mock("@/lib/cache/invalidate", () => ({ invalidateUserDashboardSnapshot: vi.fn(), })); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); vi.mock("next/headers", () => ({ headers: vi.fn(async () => ({ get: () => null })), cookies: vi.fn(async () => ({ diff --git a/src/app/api/nutrients/daily/__tests__/route.test.ts b/src/app/api/nutrients/daily/__tests__/route.test.ts index af942a685..2c326657f 100644 --- a/src/app/api/nutrients/daily/__tests__/route.test.ts +++ b/src/app/api/nutrients/daily/__tests__/route.test.ts @@ -23,9 +23,6 @@ vi.mock("@/lib/modules/gate", () => ({ vi.mock("@/lib/auth/session", () => ({ getSession: vi.fn() })); vi.mock("@/lib/logging/transports", () => ({ emitIfSampled: vi.fn() })); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); vi.mock("next/headers", () => ({ headers: vi.fn(async () => ({ get: () => null })), cookies: vi.fn(async () => ({ diff --git a/src/app/api/nutrients/water/__tests__/route.test.ts b/src/app/api/nutrients/water/__tests__/route.test.ts index 354ce7cc2..b1ad8c701 100644 --- a/src/app/api/nutrients/water/__tests__/route.test.ts +++ b/src/app/api/nutrients/water/__tests__/route.test.ts @@ -44,9 +44,6 @@ vi.mock("@/lib/logging/transports", () => ({ emitIfSampled: vi.fn() })); vi.mock("@/lib/auth/audit", () => ({ auditLog: vi.fn().mockResolvedValue(undefined), })); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); vi.mock("next/headers", () => ({ headers: vi.fn(async () => ({ get: () => null })), cookies: vi.fn(async () => ({ diff --git a/src/app/api/onboarding/__tests__/error-contract.test.ts b/src/app/api/onboarding/__tests__/error-contract.test.ts index 4bbffc9b2..a219fe909 100644 --- a/src/app/api/onboarding/__tests__/error-contract.test.ts +++ b/src/app/api/onboarding/__tests__/error-contract.test.ts @@ -9,9 +9,6 @@ vi.mock("@/lib/auth/session", () => ({ setOnboardingPendingCookie: vi.fn(), })); vi.mock("@/lib/logging/transports", () => ({ emitIfSampled: vi.fn() })); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); vi.mock("next/headers", () => ({ headers: vi.fn(async () => ({ get: () => null })), cookies: vi.fn(async () => ({ diff --git a/src/app/api/onboarding/complete/__tests__/route.test.ts b/src/app/api/onboarding/complete/__tests__/route.test.ts index 4fbc8c9a8..c33b8a690 100644 --- a/src/app/api/onboarding/complete/__tests__/route.test.ts +++ b/src/app/api/onboarding/complete/__tests__/route.test.ts @@ -28,10 +28,6 @@ vi.mock("@/lib/auth/session", async (importOriginal) => { vi.mock("@/lib/logging/transports", () => ({ emitIfSampled: vi.fn() })); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - vi.mock("@/lib/logging/context", async (importOriginal) => { const actual = await importOriginal(); return { ...actual, annotate: vi.fn() }; diff --git a/src/app/api/personal-records/__tests__/route.test.ts b/src/app/api/personal-records/__tests__/route.test.ts index 2593e518d..e02a60ecb 100644 --- a/src/app/api/personal-records/__tests__/route.test.ts +++ b/src/app/api/personal-records/__tests__/route.test.ts @@ -19,10 +19,6 @@ vi.mock("@/lib/auth/audit", () => ({ vi.mock("@/lib/logging/transports", () => ({ emitIfSampled: vi.fn() })); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - vi.mock("next/headers", () => ({ headers: vi.fn(async () => ({ get: () => null })), cookies: vi.fn(async () => ({ diff --git a/src/app/api/share-links/__tests__/route.test.ts b/src/app/api/share-links/__tests__/route.test.ts index bc5e3ad24..2373645a9 100644 --- a/src/app/api/share-links/__tests__/route.test.ts +++ b/src/app/api/share-links/__tests__/route.test.ts @@ -38,9 +38,6 @@ vi.mock("@/lib/auth/hmac", () => ({ hashToken: (s: string) => `hash(${s})` })); vi.mock("@/lib/auth/audit", () => ({ auditLog: vi.fn() })); vi.mock("@/lib/rate-limit", () => ({ checkRateLimit: vi.fn() })); vi.mock("@/lib/logging/transports", () => ({ emitIfSampled: vi.fn() })); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); vi.mock("next/headers", () => ({ headers: vi.fn(async () => ({ get: () => null })), cookies: vi.fn(async () => ({ diff --git a/src/app/api/sleep/night/__tests__/route.test.ts b/src/app/api/sleep/night/__tests__/route.test.ts index 483f888ee..fb957b139 100644 --- a/src/app/api/sleep/night/__tests__/route.test.ts +++ b/src/app/api/sleep/night/__tests__/route.test.ts @@ -39,10 +39,6 @@ vi.mock("@/lib/measurements/list/sleep-nights", async (importOriginal) => { return { ...actual, latestMainSleepNight: vi.fn(async () => null) }; }); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - vi.mock("@/lib/logging/context", async (importOriginal) => { const actual = await importOriginal(); return { ...actual, annotate: vi.fn() }; diff --git a/src/app/api/sleep/rhythm/__tests__/route.test.ts b/src/app/api/sleep/rhythm/__tests__/route.test.ts index f8e3ee7b5..c712c5d6e 100644 --- a/src/app/api/sleep/rhythm/__tests__/route.test.ts +++ b/src/app/api/sleep/rhythm/__tests__/route.test.ts @@ -28,10 +28,6 @@ vi.mock("@/lib/modules/gate", () => ({ requireModuleEnabled: vi.fn(async () => ({ enabled: true })), })); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - vi.mock("@/lib/logging/context", async (importOriginal) => { const actual = await importOriginal(); return { ...actual, annotate: vi.fn() }; diff --git a/src/app/api/sync/changes/__tests__/module-gate.test.ts b/src/app/api/sync/changes/__tests__/module-gate.test.ts index 9640f30c1..a6cc395ac 100644 --- a/src/app/api/sync/changes/__tests__/module-gate.test.ts +++ b/src/app/api/sync/changes/__tests__/module-gate.test.ts @@ -15,9 +15,6 @@ import { NextRequest } from "next/server"; vi.mock("@/lib/auth/session", () => ({ getSession: vi.fn() })); vi.mock("@/lib/rate-limit", () => ({ checkRateLimit: vi.fn() })); vi.mock("@/lib/logging/transports", () => ({ emitIfSampled: vi.fn() })); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); vi.mock("@/lib/modules/gate", () => ({ isModuleEnabled: vi.fn() })); vi.mock("@/lib/db", () => ({ prisma: { diff --git a/src/app/api/user/avatar/[id]/__tests__/route.test.ts b/src/app/api/user/avatar/[id]/__tests__/route.test.ts index 0cb2596a0..7b71d3ed2 100644 --- a/src/app/api/user/avatar/[id]/__tests__/route.test.ts +++ b/src/app/api/user/avatar/[id]/__tests__/route.test.ts @@ -16,10 +16,6 @@ vi.mock("@/lib/auth/audit", () => ({ vi.mock("@/lib/logging/transports", () => ({ emitIfSampled: vi.fn() })); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - vi.mock("next/headers", () => ({ headers: vi.fn(async () => ({ get: () => null })), cookies: vi.fn(async () => ({ diff --git a/src/app/api/user/avatar/__tests__/route.test.ts b/src/app/api/user/avatar/__tests__/route.test.ts index 72e005dce..042086f44 100644 --- a/src/app/api/user/avatar/__tests__/route.test.ts +++ b/src/app/api/user/avatar/__tests__/route.test.ts @@ -17,10 +17,6 @@ vi.mock("@/lib/auth/audit", () => ({ vi.mock("@/lib/logging/transports", () => ({ emitIfSampled: vi.fn() })); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - vi.mock("@/lib/rate-limit", () => ({ checkRateLimit: vi.fn().mockResolvedValue({ allowed: true, diff --git a/src/app/api/user/profile/__tests__/route.test.ts b/src/app/api/user/profile/__tests__/route.test.ts index 03567bd91..511b6f3e5 100644 --- a/src/app/api/user/profile/__tests__/route.test.ts +++ b/src/app/api/user/profile/__tests__/route.test.ts @@ -16,10 +16,6 @@ vi.mock("@/lib/auth/audit", () => ({ vi.mock("@/lib/logging/transports", () => ({ emitIfSampled: vi.fn() })); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - // v1.18.0 — the GET alias resolves the module map. Stub it so these // tests assert the projection wiring without standing up the gate's // own DB round-trips (operator availability + assistant flags + cycle). diff --git a/src/app/api/user/thresholds/__tests__/route.test.ts b/src/app/api/user/thresholds/__tests__/route.test.ts index 573d737d2..c7865e32f 100644 --- a/src/app/api/user/thresholds/__tests__/route.test.ts +++ b/src/app/api/user/thresholds/__tests__/route.test.ts @@ -35,9 +35,6 @@ vi.mock("@/lib/logging/transports", () => ({ emitIfSampled: vi.fn() })); vi.mock("@/lib/cache/invalidate", () => ({ invalidateUserProfile: vi.fn(), })); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); vi.mock("next/headers", () => ({ headers: vi.fn(async () => ({ get: () => null })), cookies: vi.fn(async () => ({ diff --git a/src/app/api/withings/credentials/__tests__/route.test.ts b/src/app/api/withings/credentials/__tests__/route.test.ts index 737ce1a9f..09f30b1e5 100644 --- a/src/app/api/withings/credentials/__tests__/route.test.ts +++ b/src/app/api/withings/credentials/__tests__/route.test.ts @@ -28,9 +28,6 @@ vi.mock("@/lib/integrations/status", () => ({ markDisconnected: vi.fn().mockResolvedValue(undefined), })); vi.mock("@/lib/logging/transports", () => ({ emitIfSampled: vi.fn() })); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); vi.mock("next/headers", () => ({ headers: vi.fn(async () => ({ get: () => null })), cookies: vi.fn(async () => ({ diff --git a/src/app/api/workouts/__tests__/batch-create.test.ts b/src/app/api/workouts/__tests__/batch-create.test.ts index 877dee0cc..34af4f9cd 100644 --- a/src/app/api/workouts/__tests__/batch-create.test.ts +++ b/src/app/api/workouts/__tests__/batch-create.test.ts @@ -48,10 +48,6 @@ vi.mock("@/lib/auth/audit", () => ({ vi.mock("@/lib/logging/transports", () => ({ emitIfSampled: vi.fn() })); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - vi.mock("@/lib/rate-limit", () => ({ checkRateLimit: vi.fn(), })); diff --git a/src/app/api/workouts/batch/__tests__/unstable-external-id.test.ts b/src/app/api/workouts/batch/__tests__/unstable-external-id.test.ts index 1e2cd9cd1..64dc293c3 100644 --- a/src/app/api/workouts/batch/__tests__/unstable-external-id.test.ts +++ b/src/app/api/workouts/batch/__tests__/unstable-external-id.test.ts @@ -55,9 +55,6 @@ vi.mock("@/lib/arrivals/emit-shared", () => ({ emitDataArrival: vi.fn().mockResolvedValue(undefined), })); vi.mock("@/lib/logging/transports", () => ({ emitIfSampled: vi.fn() })); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); vi.mock("@/lib/logging/context", async (importOriginal) => { const actual = await importOriginal>(); return { ...actual, annotate: vi.fn() }; diff --git a/src/app/c/[token]/d/[id]/__tests__/route.test.ts b/src/app/c/[token]/d/[id]/__tests__/route.test.ts index b22022580..0018989ba 100644 --- a/src/app/c/[token]/d/[id]/__tests__/route.test.ts +++ b/src/app/c/[token]/d/[id]/__tests__/route.test.ts @@ -52,9 +52,6 @@ vi.mock("@/lib/logging/transports", () => ({ emitIfSampled: vi.fn() })); vi.mock("@/lib/modules/gate", () => ({ isModuleEnabled: vi.fn(async () => true), })); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); vi.mock("next/headers", () => ({ headers: vi.fn(async () => ({ get: () => null })), cookies: vi.fn(async () => ({ diff --git a/src/lib/__tests__/glitchtip-path-secret-redaction.test.ts b/src/lib/__tests__/glitchtip-path-secret-redaction.test.ts index b24d2dba1..a2a1f295a 100644 --- a/src/lib/__tests__/glitchtip-path-secret-redaction.test.ts +++ b/src/lib/__tests__/glitchtip-path-secret-redaction.test.ts @@ -27,10 +27,6 @@ vi.mock("@/lib/auth/audit", () => ({ auditLog: vi.fn().mockResolvedValue(undefined), })); vi.mock("@/lib/logging/transports", () => ({ emitIfSampled: vi.fn() })); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - vi.mock("@/lib/monitoring-settings", () => ({ getGlitchtipSettings: vi.fn(async () => ({ glitchtipEnabled: true, diff --git a/src/lib/analytics/__tests__/sleep-stage-composition.test.ts b/src/lib/analytics/__tests__/sleep-stage-composition.test.ts index bb6db6fb2..520aa239b 100644 --- a/src/lib/analytics/__tests__/sleep-stage-composition.test.ts +++ b/src/lib/analytics/__tests__/sleep-stage-composition.test.ts @@ -28,10 +28,6 @@ vi.mock("@/lib/modules/gate", () => ({ requireModuleEnabled: vi.fn(async () => ({ enabled: true })), })); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - vi.mock("@/lib/logging/context", async (importOriginal) => { const actual = await importOriginal(); return { ...actual, annotate: vi.fn() }; diff --git a/src/lib/auth/__tests__/session-locale-reconcile.test.ts b/src/lib/auth/__tests__/session-locale-reconcile.test.ts index 01b356880..7836216cd 100644 --- a/src/lib/auth/__tests__/session-locale-reconcile.test.ts +++ b/src/lib/auth/__tests__/session-locale-reconcile.test.ts @@ -37,10 +37,6 @@ vi.mock("@/lib/db", () => ({ }, })); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - vi.mock("@/lib/logging/context", () => ({ getEvent: () => undefined })); vi.mock("@/lib/auth/hmac", () => ({ diff --git a/src/lib/auth/__tests__/session.test.ts b/src/lib/auth/__tests__/session.test.ts index ecf516f9a..1384dcb54 100644 --- a/src/lib/auth/__tests__/session.test.ts +++ b/src/lib/auth/__tests__/session.test.ts @@ -57,10 +57,6 @@ vi.mock("@/lib/db", () => ({ }, })); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - vi.mock("@/lib/logging/context", () => ({ getEvent: () => undefined, })); diff --git a/src/lib/auth/session.ts b/src/lib/auth/session.ts index 3350c5ea8..4c8188a44 100644 --- a/src/lib/auth/session.ts +++ b/src/lib/auth/session.ts @@ -3,7 +3,6 @@ import { prisma } from "@/lib/db"; import { cookies } from "next/headers"; import { hashToken } from "@/lib/auth/hmac"; import { SESSION_USER_SELECT, type SessionUser } from "@/lib/auth/session-user"; -import { ensureDbCompatibility } from "@/lib/db-compat"; import { getEvent } from "@/lib/logging/context"; import { shouldEmitSecureCookie } from "@/lib/auth/secure-cookie"; import { isInputRefusal, isP2025 } from "@/lib/prisma-errors"; @@ -311,16 +310,6 @@ export async function getSession(): Promise<{ }; user: SessionUser; } | null> { - try { - await ensureDbCompatibility(); - } catch (error) { - getEvent()?.setError( - error instanceof Error - ? error - : new Error("DB compatibility check failed"), - ); - } - const cookieStore = await cookies(); const carried = readSessionCookie(cookieStore); if (!carried) return null; @@ -490,7 +479,7 @@ export async function getSession(): Promise<{ /** * Lightweight read of the signed-in user's persisted locale for the root * layout's first-paint language resolution. Deliberately NOT - * `getSession()`: no db-compat check, no sliding-expiry write, no cookie + * `getSession()`: no sliding-expiry write, no cookie * mutation — the root layout renders on every request in a context where * the cookie store is read-only, so the full session touch is both dead * weight and a throw hazard there. Returns null for missing/expired diff --git a/src/lib/db-compat.ts b/src/lib/db-compat.ts deleted file mode 100644 index b6e1151e0..000000000 --- a/src/lib/db-compat.ts +++ /dev/null @@ -1,277 +0,0 @@ -/** - * Schema-bootstrap path for fresh self-host containers. - * - * Production deploys run `prisma migrate deploy` from the entrypoint, - * so the canonical migration history lives in `prisma/migrations/`. - * That history is the source of truth — any new column or table must - * land there first. - * - * This file is the belt-and-suspenders companion: it issues - * idempotent `ALTER TABLE … ADD COLUMN IF NOT EXISTS` statements on - * boot so a container that came up against a database which somehow - * missed a migration (interrupted deploy, restored from an older - * dump, etc.) self-heals before the app starts taking traffic. - * - * Treat every statement here as a mirror of an existing migration — - * never invent schema in this file. If a column appears here without - * a corresponding entry under `prisma/migrations/`, that is a bug. - */ -import { prisma } from "@/lib/db"; - -let dbCompatibilityPromise: Promise | null = null; - -async function ensureUserSchema() { - await prisma.$executeRawUnsafe(` - ALTER TABLE "users" - ADD COLUMN IF NOT EXISTS "role" TEXT NOT NULL DEFAULT 'USER'; - `); - - await prisma.$executeRawUnsafe(` - ALTER TABLE "users" - ADD COLUMN IF NOT EXISTS "date_of_birth" TIMESTAMP(3); - `); - - await prisma.$executeRawUnsafe(` - ALTER TABLE "users" - ADD COLUMN IF NOT EXISTS "gender" TEXT; - `); - - await prisma.$executeRawUnsafe(` - ALTER TABLE "users" - ADD COLUMN IF NOT EXISTS "telegram_bot_token" TEXT; - `); - - await prisma.$executeRawUnsafe(` - ALTER TABLE "users" - ADD COLUMN IF NOT EXISTS "telegram_chat_id" TEXT; - `); - - await prisma.$executeRawUnsafe(` - ALTER TABLE "users" - ADD COLUMN IF NOT EXISTS "telegram_enabled" BOOLEAN NOT NULL DEFAULT false; - `); - - await prisma.$executeRawUnsafe(` - ALTER TABLE "users" - ADD COLUMN IF NOT EXISTS "withings_client_id_encrypted" TEXT; - `); - - await prisma.$executeRawUnsafe(` - ALTER TABLE "users" - ADD COLUMN IF NOT EXISTS "withings_client_secret_encrypted" TEXT; - `); - - await prisma.$executeRawUnsafe(` - ALTER TABLE "users" - ADD COLUMN IF NOT EXISTS "locale" TEXT; - `); - - await prisma.$executeRawUnsafe(` - ALTER TABLE "users" - ADD COLUMN IF NOT EXISTS "onboarding_completed_at" TIMESTAMP(3); - `); -} - -async function ensureAppSettingsSchema() { - await prisma.$executeRawUnsafe(` - CREATE TABLE IF NOT EXISTS "app_settings" ( - "id" TEXT NOT NULL DEFAULT 'singleton', - "registration_enabled" BOOLEAN NOT NULL DEFAULT true, - CONSTRAINT "app_settings_pkey" PRIMARY KEY ("id") - ); - `); - - await prisma.$executeRawUnsafe(` - INSERT INTO "app_settings" ("id", "registration_enabled") - VALUES ('singleton', true) - ON CONFLICT ("id") DO NOTHING; - `); - - await prisma.$executeRawUnsafe(` - ALTER TABLE "app_settings" - ADD COLUMN IF NOT EXISTS "default_locale" TEXT NOT NULL DEFAULT 'de'; - `); - - await prisma.$executeRawUnsafe(` - ALTER TABLE "app_settings" - ADD COLUMN IF NOT EXISTS "telegram_global" BOOLEAN NOT NULL DEFAULT true; - `); - - await prisma.$executeRawUnsafe(` - ALTER TABLE "app_settings" - ADD COLUMN IF NOT EXISTS "ntfy_global" BOOLEAN NOT NULL DEFAULT true; - `); - - await prisma.$executeRawUnsafe(` - ALTER TABLE "app_settings" - ADD COLUMN IF NOT EXISTS "web_push_global" BOOLEAN NOT NULL DEFAULT true; - `); - - await prisma.$executeRawUnsafe(` - ALTER TABLE "app_settings" - ADD COLUMN IF NOT EXISTS "api_global" BOOLEAN NOT NULL DEFAULT true; - `); - - await prisma.$executeRawUnsafe(` - ALTER TABLE "app_settings" - ADD COLUMN IF NOT EXISTS "web_push_vapid_public_key" TEXT; - `); - - await prisma.$executeRawUnsafe(` - ALTER TABLE "app_settings" - ADD COLUMN IF NOT EXISTS "web_push_vapid_private_key_encrypted" TEXT; - `); - - await prisma.$executeRawUnsafe(` - ALTER TABLE "app_settings" - ADD COLUMN IF NOT EXISTS "web_push_vapid_subject" TEXT; - `); - - await prisma.$executeRawUnsafe(` - ALTER TABLE "app_settings" - ADD COLUMN IF NOT EXISTS "umami_enabled" BOOLEAN NOT NULL DEFAULT false; - `); - - await prisma.$executeRawUnsafe(` - ALTER TABLE "app_settings" - ADD COLUMN IF NOT EXISTS "umami_script_url" TEXT; - `); - - await prisma.$executeRawUnsafe(` - ALTER TABLE "app_settings" - ADD COLUMN IF NOT EXISTS "umami_website_id" TEXT; - `); - - await prisma.$executeRawUnsafe(` - ALTER TABLE "app_settings" - ADD COLUMN IF NOT EXISTS "glitchtip_enabled" BOOLEAN NOT NULL DEFAULT false; - `); - - await prisma.$executeRawUnsafe(` - ALTER TABLE "app_settings" - ADD COLUMN IF NOT EXISTS "glitchtip_dsn" TEXT; - `); - - await prisma.$executeRawUnsafe(` - ALTER TABLE "app_settings" - ADD COLUMN IF NOT EXISTS "glitchtip_environment" TEXT; - `); -} - -async function ensureMedicationSchema() { - await prisma.$executeRawUnsafe(` - ALTER TABLE "medications" - ADD COLUMN IF NOT EXISTS "notifications_enabled" BOOLEAN NOT NULL DEFAULT true; - `); - - await prisma.$executeRawUnsafe(` - ALTER TABLE "medications" - ADD COLUMN IF NOT EXISTS "paused_at" TIMESTAMP(3); - `); -} - -async function ensureMedicationScheduleSchema() { - await prisma.$executeRawUnsafe(` - ALTER TABLE "medication_schedules" - ADD COLUMN IF NOT EXISTS "dose" TEXT; - `); - - await prisma.$executeRawUnsafe(` - ALTER TABLE "medication_schedules" - ADD COLUMN IF NOT EXISTS "days_of_week" TEXT; - `); -} - -async function ensureEnumCompatibility() { - await prisma.$executeRawUnsafe(` - ALTER TYPE "intake_source" ADD VALUE IF NOT EXISTS 'IMPORT'; - `); -} - -/** - * v1.5.0 — fresh container bootstrap for the persistent measurement- - * rollup table. Mirrors `prisma/migrations/0067_v1434_measurement_rollups` - * so a container that came up against a database which skipped the - * migration still self-heals before the app takes traffic. - * - * Idempotent: `CREATE TYPE` is guarded with a `pg_type` lookup - * (Postgres rejects `CREATE TYPE IF NOT EXISTS`), `CREATE TABLE` / - * `CREATE INDEX` carry `IF NOT EXISTS`. The FK is added via the - * `pg_constraint` lookup so re-running the bootstrap on a populated - * DB is a no-op. - */ -async function ensureMeasurementRollupsSchema() { - await prisma.$executeRawUnsafe(` - DO $$ - BEGIN - IF NOT EXISTS ( - SELECT 1 FROM pg_type - WHERE typname = 'measurement_rollup_granularity' - ) THEN - CREATE TYPE "measurement_rollup_granularity" - AS ENUM ('DAY', 'WEEK', 'MONTH', 'YEAR'); - END IF; - END - $$; - `); - - await prisma.$executeRawUnsafe(` - CREATE TABLE IF NOT EXISTS "measurement_rollups" ( - "user_id" TEXT NOT NULL, - "type" "measurement_type" NOT NULL, - "granularity" "measurement_rollup_granularity" NOT NULL, - "bucket_start" TIMESTAMPTZ(3) NOT NULL, - "count" INTEGER NOT NULL, - "mean" DOUBLE PRECISION NOT NULL, - "min_value" DOUBLE PRECISION NOT NULL, - "max_value" DOUBLE PRECISION NOT NULL, - "sd" DOUBLE PRECISION, - "slope" DOUBLE PRECISION, - "r2" DOUBLE PRECISION, - "computed_at" TIMESTAMPTZ(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, - CONSTRAINT "measurement_rollups_pkey" - PRIMARY KEY ("user_id", "type", "granularity", "bucket_start") - ); - `); - - await prisma.$executeRawUnsafe(` - CREATE INDEX IF NOT EXISTS "measurement_rollups_user_type_granularity_bucket_desc_idx" - ON "measurement_rollups" ("user_id", "type", "granularity", "bucket_start" DESC); - `); - - await prisma.$executeRawUnsafe(` - DO $$ - BEGIN - IF NOT EXISTS ( - SELECT 1 FROM pg_constraint - WHERE conname = 'measurement_rollups_user_id_fkey' - ) THEN - ALTER TABLE "measurement_rollups" - ADD CONSTRAINT "measurement_rollups_user_id_fkey" - FOREIGN KEY ("user_id") REFERENCES "users"("id") - ON DELETE CASCADE ON UPDATE CASCADE; - END IF; - END - $$; - `); -} - -export async function ensureDbCompatibility() { - if (!dbCompatibilityPromise) { - dbCompatibilityPromise = Promise.all([ - ensureUserSchema(), - ensureAppSettingsSchema(), - ensureMedicationSchema(), - ensureMedicationScheduleSchema(), - ensureEnumCompatibility(), - ensureMeasurementRollupsSchema(), - ]) - .then(() => undefined) - .catch((error) => { - dbCompatibilityPromise = null; - throw error; - }); - } - - await dbCompatibilityPromise; -} diff --git a/src/lib/jobs/boss-instance.ts b/src/lib/jobs/boss-instance.ts index ef3fa2121..169021e24 100644 --- a/src/lib/jobs/boss-instance.ts +++ b/src/lib/jobs/boss-instance.ts @@ -88,8 +88,22 @@ function databaseOptions( } as const; } -export function createWorkerBoss(connectionString: string): PgBoss { - return new PgBoss(databaseOptions(connectionString, "worker")); +/** + * The worker's pg-boss. `createSchema` says whether pg-boss's first install + * may run `CREATE SCHEMA IF NOT EXISTS pgboss`. Postgres checks the database's + * CREATE privilege before it checks whether the schema exists, so under the + * app's restricted role (`scripts/db-app-role.mjs`), which may not create + * schemas, that statement fails even though the boot already created the + * schema for it. The caller passes false when the schema is there. + */ +export function createWorkerBoss( + connectionString: string, + options: { createSchema?: boolean } = {}, +): PgBoss { + return new PgBoss({ + ...databaseOptions(connectionString, "worker"), + ...(options.createSchema === false ? { createSchema: false } : {}), + }); } function producerOptions(connectionString: string) { diff --git a/src/lib/jobs/measurement-maintenance.ts b/src/lib/jobs/measurement-maintenance.ts index a917f77a3..84afa4e9f 100644 --- a/src/lib/jobs/measurement-maintenance.ts +++ b/src/lib/jobs/measurement-maintenance.ts @@ -61,6 +61,10 @@ import type { Job } from "pg-boss"; import { sessionOptionsDisabled } from "@/lib/db"; import { withJobLock } from "@/lib/jobs/job-lock"; +import { + CONCURRENT_COPY, + RETIRED_MEASUREMENT_INDEXES as RETIRED_INDEXES_SHARED, +} from "@/lib/jobs/retired-measurement-indexes.mjs"; import { jobDone, jobFailed, @@ -170,14 +174,11 @@ export function maintenanceSessionStatements(): string[] { /** * Indexes on `measurements` the schema no longer declares, which a run drops - * when the migration that retired them could not. Each one's migration names - * it; `IF EXISTS` makes the drop a no-op once it is gone. + * when the migration that retired them could not. The list lives in a plain + * module because the boot step `scripts/db-app-role.mjs` reads it too. */ -export const RETIRED_MEASUREMENT_INDEXES: readonly string[] = [ - // 0416: a prefix of the unique key `(user_id, type, measured_at, source, - // sleep_stage)`, which plans every query it served at the same cost. - "measurements_user_id_type_measured_at_idx", -]; +export const RETIRED_MEASUREMENT_INDEXES: readonly string[] = + RETIRED_INDEXES_SHARED; /** How long a run waits for the locks that drop a retired index. */ export const RETIRED_INDEX_LOCK_TIMEOUT = "60s"; @@ -187,9 +188,6 @@ const LOCK_TIMEOUT_VALUE = /^\d{1,6}(ms|s)$/; /** The only shape an index name may have before it is spliced into SQL. */ const INDEX_NAME = /^[a-z0-9_]{1,63}$/; -/** Postgres's suffixes for the copies a concurrent rebuild leaves behind. */ -const CONCURRENT_COPY = /_ccnew\d*$|_ccold\d*$/; - const PURGE_QUEUE = "compaction-tombstone-purge"; export interface MaintenanceStep { @@ -214,6 +212,12 @@ export interface MeasurementMaintenanceSummary { tableBytesAfter: number; indexBytesBefore: number; indexBytesAfter: number; + /** + * Retired indexes and invalid rebuild copies the run found but may not + * drop, because it does not connect as the table's owner. The next start + * drops them as the owner (`scripts/db-app-role.mjs`). + */ + dropsLeftForBoot: string[]; } interface IndexRow { @@ -333,6 +337,34 @@ function errorText(err: unknown): string { return typeof code === "string" ? `${code}: ${message}` : message; } +/** + * Whether this connection may drop indexes on `measurements`, which only the + * table's owner (or a member of the owning role) may. The app's restricted + * role may not: it holds MAINTAIN on the table, which covers `VACUUM` and + * `REINDEX` but not `DROP INDEX`. Under it the drops wait for the next start, + * which runs them as the owner (`scripts/db-app-role.mjs`). + */ +export async function mayDropMeasurementIndexes( + db: MaintenanceConnection, +): Promise { + const { rows } = await db.query<{ owns: boolean }>( + `SELECT pg_has_role(current_user, c.relowner, 'USAGE') AS owns + FROM pg_class c WHERE c.oid = 'measurements'::regclass`, + ); + return rows[0]?.owns === true; +} + +/** The droppable indexes present on the table: retired ones and invalid copies. */ +async function indexesToDrop(db: MaintenanceConnection): Promise { + return (await measurementIndexes(db)) + .filter( + (index) => + RETIRED_MEASUREMENT_INDEXES.includes(index.name) || + (!index.valid && CONCURRENT_COPY.test(index.name)), + ) + .map((index) => index.name); +} + /** Drop the invalid copies an interrupted concurrent rebuild left behind. */ async function dropInvalidCopies( db: MaintenanceConnection, @@ -434,21 +466,25 @@ export async function runMeasurementMaintenance( ): Promise { const before = await relationSizes(db); const steps: MaintenanceStep[] = []; - const summary = ( + const mayDrop = await mayDropMeasurementIndexes(db); + const summary = async ( outcome: MeasurementMaintenanceSummary["outcome"], after = before, - ): MeasurementMaintenanceSummary => ({ + ): Promise => ({ outcome, steps, tableBytesBefore: before.table, tableBytesAfter: after.table, indexBytesBefore: before.indexes, indexBytesAfter: after.indexes, + dropsLeftForBoot: mayDrop ? [] : await indexesToDrop(db), }); // Every run, the nightly tick included: a retired index costs every write // until it is gone, and the drop blocks no reader or writer. - await dropRetiredIndexes(db, steps, options.retiredLockTimeout); + if (mayDrop) { + await dropRetiredIndexes(db, steps, options.retiredLockTimeout); + } if (!payload.vacuum && !payload.reindex) return summary("nothing_due"); @@ -495,7 +531,7 @@ export async function runMeasurementMaintenance( } if (payload.reindex) { - await dropInvalidCopies(db, steps); + if (mayDrop) await dropInvalidCopies(db, steps); const targets = (await measurementIndexes(db)).filter( (index) => index.valid && @@ -529,7 +565,9 @@ export async function runMeasurementMaintenance( }); // A failed concurrent rebuild leaves its half-built copy behind, // holding disk. Drop it and stop: the likeliest cause is the disk. - await dropInvalidCopies(db, steps); + // Without the owner's right to drop it, the copy stays until the next + // start and the summary names it. + if (mayDrop) await dropInvalidCopies(db, steps); return summary("failed", await relationSizes(db)); } } @@ -603,6 +641,15 @@ export async function handleMeasurementMaintenance( ); } } + if (result.dropsLeftForBoot.length > 0) { + evt.addMeta( + "maintenance_drops_left_for_boot", + result.dropsLeftForBoot.length, + ); + evt.addWarning( + `index ${result.dropsLeftForBoot.join(", ")} on measurements is due to be dropped, which only the table's owner may do; the next start drops it as the owner`, + ); + } const retiredLeft = result.steps.filter( (s) => s.step === "drop_retired" && !s.ok, ); diff --git a/src/lib/jobs/reminder-worker.ts b/src/lib/jobs/reminder-worker.ts index 715ce80b2..72991a313 100644 --- a/src/lib/jobs/reminder-worker.ts +++ b/src/lib/jobs/reminder-worker.ts @@ -11,6 +11,7 @@ * Usage: Run as a standalone process or call startReminderWorker() from a * custom server setup. In dev, use: npx tsx src/lib/jobs/reminder-worker.ts */ +import { prisma } from "@/lib/db"; import { markWorkerStarted, recordError } from "@/lib/jobs/worker-status"; import { createWorkerBoss, setGlobalBoss } from "@/lib/jobs/boss-instance"; import { reportJobsCutOffAtBoot } from "@/lib/jobs/job-observer"; @@ -47,7 +48,13 @@ export async function startReminderWorker() { return; } - const boss = createWorkerBoss(DATABASE_URL); + // The queue schema exists once a worker has started, and on every boot + // the restricted database role runs under (the entrypoint creates it for + // that role); only a fresh database without either needs pg-boss to + // create it. + const [{ present }] = await prisma.$queryRaw<{ present: boolean }[]>` + SELECT to_regnamespace('pgboss') IS NOT NULL AS present`; + const boss = createWorkerBoss(DATABASE_URL, { createSchema: !present }); boss.on("error", (error: unknown) => { workerLog("error", "boss emitted error", error); diff --git a/src/lib/jobs/retired-measurement-indexes.mjs b/src/lib/jobs/retired-measurement-indexes.mjs new file mode 100644 index 000000000..339d35660 --- /dev/null +++ b/src/lib/jobs/retired-measurement-indexes.mjs @@ -0,0 +1,21 @@ +/** + * Indexes on `measurements` the schema no longer declares, which are dropped + * when the migration that retired them could not. Each one's migration names + * it; `IF EXISTS` makes the drop a no-op once it is gone. + * + * Plain ESM with no imports, because two processes read it: the measurement + * maintenance job (`measurement-maintenance.ts`), and the boot step in + * `scripts/db-app-role.mjs`, which drops them as the database owner when the + * app itself connects as a role that may not (`DROP INDEX` belongs to the + * table's owner, not to the MAINTAIN privilege). + * + * @type {readonly string[]} + */ +export const RETIRED_MEASUREMENT_INDEXES = Object.freeze([ + // 0416: a prefix of the unique key `(user_id, type, measured_at, source, + // sleep_stage)`, which plans every query it served at the same cost. + "measurements_user_id_type_measured_at_idx", +]); + +/** Postgres's suffixes for the copies a concurrent rebuild leaves behind. */ +export const CONCURRENT_COPY = /_ccnew\d*$|_ccold\d*$/; diff --git a/tests/integration/account-deletion-grace.test.ts b/tests/integration/account-deletion-grace.test.ts index 410474e40..337331945 100644 --- a/tests/integration/account-deletion-grace.test.ts +++ b/tests/integration/account-deletion-grace.test.ts @@ -42,10 +42,6 @@ vi.mock("next/headers", async () => { }; }); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - const adminNotices = vi.hoisted(() => [] as Array>); vi.mock("@/lib/notifications/dispatch-localised", () => ({ dispatchLocalisedNotification: vi.fn( diff --git a/tests/integration/account-grant-lifecycle.test.ts b/tests/integration/account-grant-lifecycle.test.ts index eb573e09d..1224db4ed 100644 --- a/tests/integration/account-grant-lifecycle.test.ts +++ b/tests/integration/account-grant-lifecycle.test.ts @@ -65,10 +65,6 @@ vi.mock("next/headers", async () => { }; }); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - let counter = 0; async function makeUser(label: string, role: "USER" | "ADMIN" = "USER") { diff --git a/tests/integration/acting-account-resolver.test.ts b/tests/integration/acting-account-resolver.test.ts index 923088189..5a7d6f4b1 100644 --- a/tests/integration/acting-account-resolver.test.ts +++ b/tests/integration/acting-account-resolver.test.ts @@ -63,10 +63,6 @@ vi.mock("next/headers", async () => { }; }); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - import { ACCOUNT_SELECTOR_HEADER, apiHandler, diff --git a/tests/integration/activity-calendar-read.test.ts b/tests/integration/activity-calendar-read.test.ts index 2c6c86c42..43bf17c16 100644 --- a/tests/integration/activity-calendar-read.test.ts +++ b/tests/integration/activity-calendar-read.test.ts @@ -8,17 +8,13 @@ * - a workout two devices recorded counts once, its minutes once; * - the window is exact: nothing before `fromKey` or after `toKey`. */ -import { beforeAll, describe, expect, it, vi } from "vitest"; +import { beforeAll, describe, expect, it } from "vitest"; import { getPrismaClient, truncateAllTables } from "./setup"; import { readActivityDays } from "@/lib/activity/calendar-read"; import { invalidateUserTimezone } from "@/lib/tz/resolver"; import { userDayKey } from "@/lib/tz/format"; -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - const prisma = getPrismaClient(); const TZ = "Europe/Berlin"; const USER = "activity-reader"; diff --git a/tests/integration/admin-backups-audit.test.ts b/tests/integration/admin-backups-audit.test.ts index 0a68fd32a..10b7b00c9 100644 --- a/tests/integration/admin-backups-audit.test.ts +++ b/tests/integration/admin-backups-audit.test.ts @@ -48,10 +48,6 @@ vi.mock("next/headers", async () => { }; }); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - // Stub `getGlobalBoss` so the run endpoint can audit-log its happy // path without booting an actual pg-boss worker against the test DB. // The fake boss returns a deterministic job id so the audit row can be diff --git a/tests/integration/admin-backups-canonical-roundtrip.test.ts b/tests/integration/admin-backups-canonical-roundtrip.test.ts index 334f0507e..2235729ea 100644 --- a/tests/integration/admin-backups-canonical-roundtrip.test.ts +++ b/tests/integration/admin-backups-canonical-roundtrip.test.ts @@ -48,10 +48,6 @@ vi.mock("next/headers", async () => { }; }); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - vi.mock("@/lib/cache/invalidate", () => ({ invalidateUserData: vi.fn(), })); diff --git a/tests/integration/admin-backups-download.test.ts b/tests/integration/admin-backups-download.test.ts index 7ceb2f598..faa2ea064 100644 --- a/tests/integration/admin-backups-download.test.ts +++ b/tests/integration/admin-backups-download.test.ts @@ -45,10 +45,6 @@ vi.mock("next/headers", async () => { }; }); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - beforeEach(async () => { await truncateAllTables(getPrismaClient()); cookieJar.clear(); diff --git a/tests/integration/admin-backups-restore.test.ts b/tests/integration/admin-backups-restore.test.ts index a27239b1b..e9bcfb8d8 100644 --- a/tests/integration/admin-backups-restore.test.ts +++ b/tests/integration/admin-backups-restore.test.ts @@ -49,10 +49,6 @@ vi.mock("next/headers", async () => { }; }); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - beforeEach(async () => { await truncateAllTables(getPrismaClient()); cookieJar.clear(); diff --git a/tests/integration/admin-backups-upload-too-large.test.ts b/tests/integration/admin-backups-upload-too-large.test.ts index f288cfa02..4ed38dddf 100644 --- a/tests/integration/admin-backups-upload-too-large.test.ts +++ b/tests/integration/admin-backups-upload-too-large.test.ts @@ -37,9 +37,6 @@ vi.mock("next/headers", async () => { })), }; }); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); vi.mock("@/lib/export/store-backup-blob", async (importOriginal) => { const actual = await importOriginal(); diff --git a/tests/integration/admin-backups-upload.test.ts b/tests/integration/admin-backups-upload.test.ts index 26edf32f6..bbbbf7707 100644 --- a/tests/integration/admin-backups-upload.test.ts +++ b/tests/integration/admin-backups-upload.test.ts @@ -41,10 +41,6 @@ vi.mock("next/headers", async () => { }; }); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - beforeEach(async () => { await truncateAllTables(getPrismaClient()); cookieJar.clear(); diff --git a/tests/integration/admin-data-wipe.test.ts b/tests/integration/admin-data-wipe.test.ts index b8dff9919..81605562c 100644 --- a/tests/integration/admin-data-wipe.test.ts +++ b/tests/integration/admin-data-wipe.test.ts @@ -66,10 +66,6 @@ vi.mock("next/headers", async () => { }; }); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - beforeEach(async () => { await truncateAllTables(getPrismaClient()); cookieJar.clear(); diff --git a/tests/integration/admin-drain-cumulative-endpoint.test.ts b/tests/integration/admin-drain-cumulative-endpoint.test.ts index 014deb2c7..4c9969aaa 100644 --- a/tests/integration/admin-drain-cumulative-endpoint.test.ts +++ b/tests/integration/admin-drain-cumulative-endpoint.test.ts @@ -35,10 +35,6 @@ vi.mock("next/headers", async () => { }; }); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - beforeEach(async () => { await truncateAllTables(getPrismaClient()); cookieJar.clear(); diff --git a/tests/integration/admin-host-metrics.test.ts b/tests/integration/admin-host-metrics.test.ts index 523b9025a..589d89c21 100644 --- a/tests/integration/admin-host-metrics.test.ts +++ b/tests/integration/admin-host-metrics.test.ts @@ -37,10 +37,6 @@ vi.mock("next/headers", async () => { }; }); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - beforeEach(async () => { await truncateAllTables(getPrismaClient()); cookieJar.clear(); diff --git a/tests/integration/admin-reset-password.test.ts b/tests/integration/admin-reset-password.test.ts index ca33f1497..db189f7d4 100644 --- a/tests/integration/admin-reset-password.test.ts +++ b/tests/integration/admin-reset-password.test.ts @@ -42,10 +42,6 @@ vi.mock("next/headers", async () => { }; }); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - const STRONG_NEW_PW = "Adm1nReset!P@ssw0rd789"; async function seedCaller(role: "ADMIN" | "USER"): Promise<{ diff --git a/tests/integration/admin-rollups-recompute.test.ts b/tests/integration/admin-rollups-recompute.test.ts index 0ae49e279..780312dcb 100644 --- a/tests/integration/admin-rollups-recompute.test.ts +++ b/tests/integration/admin-rollups-recompute.test.ts @@ -42,10 +42,6 @@ vi.mock("next/headers", async () => { }; }); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - vi.mock("@/lib/rollups/full-backfill", async (importOriginal) => { const actual = await importOriginal(); diff --git a/tests/integration/admin-support-report.test.ts b/tests/integration/admin-support-report.test.ts index 94b0e431e..2d26b17a5 100644 --- a/tests/integration/admin-support-report.test.ts +++ b/tests/integration/admin-support-report.test.ts @@ -37,10 +37,6 @@ vi.mock("next/headers", async () => { }; }); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - import { GET } from "@/app/api/admin/support-report/route"; beforeEach(async () => { diff --git a/tests/integration/admin-user-deletion.test.ts b/tests/integration/admin-user-deletion.test.ts index 4bfdcd2a7..7c1280d59 100644 --- a/tests/integration/admin-user-deletion.test.ts +++ b/tests/integration/admin-user-deletion.test.ts @@ -33,10 +33,6 @@ vi.mock("next/headers", async () => { }; }); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - const DAY_MS = 24 * 60 * 60 * 1000; const HOUR_MS = 60 * 60 * 1000; diff --git a/tests/integration/ai-consent-explicit.test.ts b/tests/integration/ai-consent-explicit.test.ts index c10652bfc..ef3a706f0 100644 --- a/tests/integration/ai-consent-explicit.test.ts +++ b/tests/integration/ai-consent-explicit.test.ts @@ -45,10 +45,6 @@ vi.mock("next/headers", async () => { }; }); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - const providerSpy = vi.fn(async () => ({ content: JSON.stringify({ summary: "A calm and steady stretch." }), model: "spy-model", diff --git a/tests/integration/ai-extraction-capability.test.ts b/tests/integration/ai-extraction-capability.test.ts index 263eb2c48..331b2e757 100644 --- a/tests/integration/ai-extraction-capability.test.ts +++ b/tests/integration/ai-extraction-capability.test.ts @@ -59,10 +59,6 @@ vi.mock("next/headers", async () => { }; }); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - // v1.40 — a lab scan is queued for the background worker; a queue that takes // the send lets the route answer 202, and the test then runs the worker. vi.mock("@/lib/jobs/boss-instance", () => ({ diff --git a/tests/integration/ai-optional-actions.test.ts b/tests/integration/ai-optional-actions.test.ts index 255b4467a..403a21768 100644 --- a/tests/integration/ai-optional-actions.test.ts +++ b/tests/integration/ai-optional-actions.test.ts @@ -47,10 +47,6 @@ vi.mock("next/headers", async () => { }; }); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - // Provider spies: a refusal must never reach either. const runner = vi.hoisted(() => ({ raw: vi.fn(), diff --git a/tests/integration/ai-optional-data-routes.test.ts b/tests/integration/ai-optional-data-routes.test.ts index 465e775d0..303682912 100644 --- a/tests/integration/ai-optional-data-routes.test.ts +++ b/tests/integration/ai-optional-data-routes.test.ts @@ -46,10 +46,6 @@ vi.mock("next/headers", async () => { }; }); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - const DAY = 24 * 60 * 60 * 1000; const NOW = Date.now(); diff --git a/tests/integration/ai-optional-jobs.test.ts b/tests/integration/ai-optional-jobs.test.ts index f3b4c61d0..6af05fd89 100644 --- a/tests/integration/ai-optional-jobs.test.ts +++ b/tests/integration/ai-optional-jobs.test.ts @@ -23,10 +23,6 @@ import { beforeEach, describe, expect, it, vi } from "vitest"; import { getPrismaClient, truncateAllTables } from "./setup"; -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - const providerSpy = vi.fn(async () => ({ content: JSON.stringify({ summary: "A calm and steady stretch." }), model: "spy-model", diff --git a/tests/integration/ai-optional-mixed-routes.test.ts b/tests/integration/ai-optional-mixed-routes.test.ts index 2475a1ab5..3e0683969 100644 --- a/tests/integration/ai-optional-mixed-routes.test.ts +++ b/tests/integration/ai-optional-mixed-routes.test.ts @@ -46,10 +46,6 @@ vi.mock("next/headers", async () => { }; }); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - // The two enqueue seams a mixed read may reach. Spied, never run: the test // asserts they are not called while a capability is unavailable. const enqueueNarrativeWarm = vi.fn(async () => undefined); diff --git a/tests/integration/ai-provider-key-removal.test.ts b/tests/integration/ai-provider-key-removal.test.ts index c1944acf7..c307d9da9 100644 --- a/tests/integration/ai-provider-key-removal.test.ts +++ b/tests/integration/ai-provider-key-removal.test.ts @@ -37,10 +37,6 @@ vi.mock("next/headers", async () => { }; }); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - async function seedAccountWithKeys(): Promise { const prisma = getPrismaClient(); const { encrypt } = await import("@/lib/crypto"); diff --git a/tests/integration/ai-usage-levels.test.ts b/tests/integration/ai-usage-levels.test.ts index f19361326..a0c629e33 100644 --- a/tests/integration/ai-usage-levels.test.ts +++ b/tests/integration/ai-usage-levels.test.ts @@ -43,10 +43,6 @@ vi.mock("next/headers", async () => { }; }); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - // The queue is not under test: record what the invalidator enqueues. const enqueued = vi.hoisted(() => [] as Array<{ metric: string }>); vi.mock("@/lib/jobs/insight-status-generate-shared", async (orig) => ({ diff --git a/tests/integration/analytics-bp-aggregate-paged.test.ts b/tests/integration/analytics-bp-aggregate-paged.test.ts index ca33c5d19..ac8b48648 100644 --- a/tests/integration/analytics-bp-aggregate-paged.test.ts +++ b/tests/integration/analytics-bp-aggregate-paged.test.ts @@ -50,10 +50,6 @@ vi.mock("next/headers", async () => { }; }); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - // Read wide-events back out of the in-memory ring buffer the // `emitEvent` transport already populates — avoids coupling to the // Loki/stdout plumbing and works regardless of `LOG_SAMPLE_RATE`. diff --git a/tests/integration/analytics-health-score.test.ts b/tests/integration/analytics-health-score.test.ts index b2a0b0363..ac765f95c 100644 --- a/tests/integration/analytics-health-score.test.ts +++ b/tests/integration/analytics-health-score.test.ts @@ -38,10 +38,6 @@ vi.mock("next/headers", async () => { }; }); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - beforeEach(async () => { await truncateAllTables(getPrismaClient()); cookieJar.clear(); diff --git a/tests/integration/analytics-sleep-stages.test.ts b/tests/integration/analytics-sleep-stages.test.ts index a944b591c..da5cb8513 100644 --- a/tests/integration/analytics-sleep-stages.test.ts +++ b/tests/integration/analytics-sleep-stages.test.ts @@ -39,10 +39,6 @@ vi.mock("next/headers", async () => { }; }); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - beforeEach(async () => { await truncateAllTables(getPrismaClient()); cookieJar.clear(); diff --git a/tests/integration/analytics-summaries-slice.test.ts b/tests/integration/analytics-summaries-slice.test.ts index 7c88560a8..52a71b694 100644 --- a/tests/integration/analytics-summaries-slice.test.ts +++ b/tests/integration/analytics-summaries-slice.test.ts @@ -51,10 +51,6 @@ vi.mock("next/headers", async () => { }; }); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - beforeEach(async () => { await truncateAllTables(getPrismaClient()); cookieJar.clear(); diff --git a/tests/integration/analytics-weekday-tz.test.ts b/tests/integration/analytics-weekday-tz.test.ts index 2e2101d2f..1f23bc43a 100644 --- a/tests/integration/analytics-weekday-tz.test.ts +++ b/tests/integration/analytics-weekday-tz.test.ts @@ -43,10 +43,6 @@ vi.mock("next/headers", async () => { }; }); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - beforeEach(async () => { await truncateAllTables(getPrismaClient()); cookieJar.clear(); diff --git a/tests/integration/apns-dispatch.test.ts b/tests/integration/apns-dispatch.test.ts index 03b4fe0bb..9995a4f3c 100644 --- a/tests/integration/apns-dispatch.test.ts +++ b/tests/integration/apns-dispatch.test.ts @@ -55,10 +55,6 @@ vi.mock("@/lib/notifications/senders/telegram", () => ({ sendViaTelegram: (...args: unknown[]) => telegramSendMock(...args), })); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - import { getPrismaClient, truncateAllTables } from "./setup"; const TEST_USER_ID = "user-apns-dispatch-test"; diff --git a/tests/integration/apple-health-import-ecg.test.ts b/tests/integration/apple-health-import-ecg.test.ts index 2bd581f7d..751846661 100644 --- a/tests/integration/apple-health-import-ecg.test.ts +++ b/tests/integration/apple-health-import-ecg.test.ts @@ -23,10 +23,6 @@ import { } from "@/lib/jobs/apple-health-import-worker"; import { getPrismaClient, truncateAllTables } from "./setup"; -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - vi.mock("@/lib/jobs/boss-instance", () => ({ getGlobalBoss: vi.fn(() => null), })); diff --git a/tests/integration/apple-health-import-reconcile.test.ts b/tests/integration/apple-health-import-reconcile.test.ts index 7dbd7c9a4..191508724 100644 --- a/tests/integration/apple-health-import-reconcile.test.ts +++ b/tests/integration/apple-health-import-reconcile.test.ts @@ -26,10 +26,6 @@ import { _setWorkerPrismaForTests, } from "@/lib/jobs/apple-health-import-worker"; -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - // Controllable pg-boss handle: the reconcile consults `getJobById` for a // row's real queue state. const bossMock = vi.hoisted(() => ({ diff --git a/tests/integration/apple-health-import-rollup-window.test.ts b/tests/integration/apple-health-import-rollup-window.test.ts index be558605e..a42b8be96 100644 --- a/tests/integration/apple-health-import-rollup-window.test.ts +++ b/tests/integration/apple-health-import-rollup-window.test.ts @@ -24,9 +24,6 @@ import { } from "@/lib/jobs/apple-health-import-worker"; import { ROLLUP_FOLD_WINDOW_MS } from "@/lib/rollups/measurement-rollups"; -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); vi.mock("@/lib/jobs/boss-instance", () => ({ getGlobalBoss: vi.fn(() => null), })); diff --git a/tests/integration/apple-health-import-worker-failures.test.ts b/tests/integration/apple-health-import-worker-failures.test.ts index 2793396ad..51bae2417 100644 --- a/tests/integration/apple-health-import-worker-failures.test.ts +++ b/tests/integration/apple-health-import-worker-failures.test.ts @@ -34,10 +34,6 @@ import { type AppleHealthImportPayload, } from "@/lib/jobs/apple-health-import-worker"; -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - // No pg-boss attached — the end-of-import rollup fold's enqueue helpers // are silent no-ops without a boss. vi.mock("@/lib/jobs/boss-instance", () => ({ diff --git a/tests/integration/auth-flow.test.ts b/tests/integration/auth-flow.test.ts index da873f510..d57c94b55 100644 --- a/tests/integration/auth-flow.test.ts +++ b/tests/integration/auth-flow.test.ts @@ -1,9 +1,8 @@ /** * Integration regression guard for `src/lib/auth/session.ts`. * - * The session helpers couple Postgres (`Session` row), the `cookies()` - * adapter from `next/headers`, and the `db-compat` schema-migration - * fallback. A unit test with a mocked Prisma client cannot verify the + * The session helpers couple Postgres (`Session` row) and the `cookies()` + * adapter from `next/headers`. A unit test with a mocked Prisma client cannot verify the * end-to-end flow — particularly the expired-session purge behaviour, * which silently deletes the row before returning null. */ @@ -38,12 +37,6 @@ vi.mock("next/headers", async () => { }; }); -// `db-compat` runs ALTER TABLE IF NOT EXISTS statements that are no-ops -// against a freshly-migrated schema but slow tests down — short-circuit. -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - beforeEach(async () => { await truncateAllTables(getPrismaClient()); cookieJar.clear(); diff --git a/tests/integration/auth-ledger-cleanup.test.ts b/tests/integration/auth-ledger-cleanup.test.ts index 8de6fe9bd..a1a37931c 100644 --- a/tests/integration/auth-ledger-cleanup.test.ts +++ b/tests/integration/auth-ledger-cleanup.test.ts @@ -7,16 +7,12 @@ * token without an expiry all stay. The delete is batched and says when it * stopped with rows left. */ -import { beforeEach, describe, expect, it, vi } from "vitest"; +import { beforeEach, describe, expect, it } from "vitest"; import { cleanupAuthLedgers } from "@/lib/jobs/auth-ledger-cleanup"; import { getPrismaClient, truncateAllTables } from "./setup"; -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - const USER = "auth-ledger-user"; const NOW = new Date("2026-10-20T03:35:00.000Z"); const DAY = 86_400_000; diff --git a/tests/integration/auth-me-ai-capabilities.test.ts b/tests/integration/auth-me-ai-capabilities.test.ts index 090dbcb14..5fa15f6a8 100644 --- a/tests/integration/auth-me-ai-capabilities.test.ts +++ b/tests/integration/auth-me-ai-capabilities.test.ts @@ -41,10 +41,6 @@ vi.mock("next/headers", async () => { }; }); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - const ALL = [ "coach", "briefing", diff --git a/tests/integration/auth-me-coach-reasoning.test.ts b/tests/integration/auth-me-coach-reasoning.test.ts index 186352bd5..f93095591 100644 --- a/tests/integration/auth-me-coach-reasoning.test.ts +++ b/tests/integration/auth-me-coach-reasoning.test.ts @@ -40,10 +40,6 @@ vi.mock("next/headers", async () => { }; }); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - interface CoachReasoning { level: string; preference: string; diff --git a/tests/integration/auth-password-change.test.ts b/tests/integration/auth-password-change.test.ts index 90fa48f52..18cb9e89a 100644 --- a/tests/integration/auth-password-change.test.ts +++ b/tests/integration/auth-password-change.test.ts @@ -44,10 +44,6 @@ vi.mock("next/headers", async () => { }; }); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - const STRONG_CURRENT = "OldStrongP@ssw0rd!123abc"; const STRONG_NEW = "NewStrongP@ssw0rd!456xyz"; diff --git a/tests/integration/backup-chunked-storage.test.ts b/tests/integration/backup-chunked-storage.test.ts index b53e9ae51..1d2418c27 100644 --- a/tests/integration/backup-chunked-storage.test.ts +++ b/tests/integration/backup-chunked-storage.test.ts @@ -52,10 +52,6 @@ vi.mock("next/headers", async () => { })), }; }); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - const COUNT = 12_000; /** Small pieces, so a test-sized record spans many of them. */ const SMALL = { chunkBytes: 4 * 1024 }; diff --git a/tests/integration/backup-custom-cycle-symptom-restore.test.ts b/tests/integration/backup-custom-cycle-symptom-restore.test.ts index 98ff701ba..8f621afa6 100644 --- a/tests/integration/backup-custom-cycle-symptom-restore.test.ts +++ b/tests/integration/backup-custom-cycle-symptom-restore.test.ts @@ -63,10 +63,6 @@ vi.mock("next/headers", async () => { }; }); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - vi.mock("@/lib/cache/invalidate", () => ({ invalidateUserData: vi.fn(), })); diff --git a/tests/integration/backup-cycle-cross-key-restore.test.ts b/tests/integration/backup-cycle-cross-key-restore.test.ts index 4d3f50aee..0ad7ca5eb 100644 --- a/tests/integration/backup-cycle-cross-key-restore.test.ts +++ b/tests/integration/backup-cycle-cross-key-restore.test.ts @@ -46,10 +46,6 @@ vi.mock("next/headers", async () => { }; }); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - vi.mock("@/lib/cache/invalidate", () => ({ invalidateUserData: vi.fn(), })); diff --git a/tests/integration/backup-cycle-symptom-severity-restore.test.ts b/tests/integration/backup-cycle-symptom-severity-restore.test.ts index cf392785b..762193a5b 100644 --- a/tests/integration/backup-cycle-symptom-severity-restore.test.ts +++ b/tests/integration/backup-cycle-symptom-severity-restore.test.ts @@ -51,10 +51,6 @@ vi.mock("next/headers", async () => { }; }); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - vi.mock("@/lib/cache/invalidate", () => ({ invalidateUserData: vi.fn(), })); diff --git a/tests/integration/backup-document-import-ledger.test.ts b/tests/integration/backup-document-import-ledger.test.ts index fa207d3c8..228c97d89 100644 --- a/tests/integration/backup-document-import-ledger.test.ts +++ b/tests/integration/backup-document-import-ledger.test.ts @@ -45,10 +45,6 @@ vi.mock("next/headers", async () => { }; }); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - vi.mock("@/lib/cache/invalidate", async (importOriginal) => { const actual = await importOriginal(); diff --git a/tests/integration/backup-document-streaming.test.ts b/tests/integration/backup-document-streaming.test.ts index 63c087d9d..251f71c68 100644 --- a/tests/integration/backup-document-streaming.test.ts +++ b/tests/integration/backup-document-streaming.test.ts @@ -23,7 +23,7 @@ import { createHash, randomBytes } from "node:crypto"; import v8 from "node:v8"; import vm from "node:vm"; -import { afterAll, beforeAll, describe, expect, it, vi } from "vitest"; +import { afterAll, beforeAll, describe, expect, it } from "vitest"; process.env.ENCRYPTION_KEY ??= "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"; @@ -42,10 +42,6 @@ import { STORED_BACKUP_SELECT } from "@/lib/export/stored-backup"; import { parseBackupPayload } from "@/lib/validations/backup"; import { summarizeBackup } from "@/lib/validations/backup-summary"; -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - const prisma = getPrismaClient(); const OWNER_ID = "backup-document-owner"; diff --git a/tests/integration/backup-dr-stamps-and-ciphertext.test.ts b/tests/integration/backup-dr-stamps-and-ciphertext.test.ts index 512f70636..4a90e80a6 100644 --- a/tests/integration/backup-dr-stamps-and-ciphertext.test.ts +++ b/tests/integration/backup-dr-stamps-and-ciphertext.test.ts @@ -53,10 +53,6 @@ vi.mock("next/headers", async () => { }; }); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - const prisma = getPrismaClient(); const CREATED = new Date("2026-03-03T03:03:03.000Z"); const UPDATED = new Date("2026-04-04T04:04:04.000Z"); diff --git a/tests/integration/backup-erased-account-restore.test.ts b/tests/integration/backup-erased-account-restore.test.ts index 3b2ea8c7a..6eb2ae2e3 100644 --- a/tests/integration/backup-erased-account-restore.test.ts +++ b/tests/integration/backup-erased-account-restore.test.ts @@ -78,10 +78,6 @@ vi.mock("next/headers", async () => { }; }); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - vi.mock("@/lib/notifications/dispatch-localised", () => ({ dispatchLocalisedNotification: vi.fn(async () => undefined), })); diff --git a/tests/integration/backup-key-needs.test.ts b/tests/integration/backup-key-needs.test.ts index 3aeb4179c..9edbb180f 100644 --- a/tests/integration/backup-key-needs.test.ts +++ b/tests/integration/backup-key-needs.test.ts @@ -41,10 +41,6 @@ vi.mock("next/headers", async () => { }; }); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - const saved = { key: process.env.ENCRYPTION_KEY, keys: process.env.ENCRYPTION_KEYS, diff --git a/tests/integration/backup-legacy-rmssd-restore.test.ts b/tests/integration/backup-legacy-rmssd-restore.test.ts index 25a8ad4c2..45c376a23 100644 --- a/tests/integration/backup-legacy-rmssd-restore.test.ts +++ b/tests/integration/backup-legacy-rmssd-restore.test.ts @@ -39,10 +39,6 @@ vi.mock("next/headers", async () => { }; }); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - vi.mock("@/lib/cache/invalidate", async (importOriginal) => { const actual = await importOriginal(); diff --git a/tests/integration/backup-missing-section-restore.test.ts b/tests/integration/backup-missing-section-restore.test.ts index 1c3afad66..7eaaba04a 100644 --- a/tests/integration/backup-missing-section-restore.test.ts +++ b/tests/integration/backup-missing-section-restore.test.ts @@ -57,10 +57,6 @@ vi.mock("next/headers", async () => { }; }); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - vi.mock("@/lib/cache/invalidate", () => ({ invalidateUserData: vi.fn(), })); diff --git a/tests/integration/backup-mood-label-cross-key-restore.test.ts b/tests/integration/backup-mood-label-cross-key-restore.test.ts index f1a0b6719..7a52cc152 100644 --- a/tests/integration/backup-mood-label-cross-key-restore.test.ts +++ b/tests/integration/backup-mood-label-cross-key-restore.test.ts @@ -40,10 +40,6 @@ vi.mock("next/headers", async () => { }; }); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - vi.mock("@/lib/cache/invalidate", () => ({ invalidateUserData: vi.fn(), })); diff --git a/tests/integration/backup-parity.test.ts b/tests/integration/backup-parity.test.ts index 3e83e614c..c8e2d98f1 100644 --- a/tests/integration/backup-parity.test.ts +++ b/tests/integration/backup-parity.test.ts @@ -123,10 +123,6 @@ vi.mock("next/headers", async () => { }; }); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - /** What the restore asked of the world outside its transaction. */ const effects = vi.hoisted(() => ({ invalidated: [] as string[], diff --git a/tests/integration/backup-portable-file-restore.test.ts b/tests/integration/backup-portable-file-restore.test.ts index a840163ee..380f891cd 100644 --- a/tests/integration/backup-portable-file-restore.test.ts +++ b/tests/integration/backup-portable-file-restore.test.ts @@ -76,10 +76,6 @@ vi.mock("next/headers", async () => { }; }); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - vi.mock("@/lib/cache/invalidate", () => ({ invalidateUserData: vi.fn(), })); diff --git a/tests/integration/backup-preview.test.ts b/tests/integration/backup-preview.test.ts index 81757c6c7..03702b3f3 100644 --- a/tests/integration/backup-preview.test.ts +++ b/tests/integration/backup-preview.test.ts @@ -45,10 +45,6 @@ vi.mock("next/headers", async () => { }; }); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - const opened = vi.hoisted(() => ({ count: 0 })); vi.mock("@/lib/export/stored-backup", async (importOriginal) => { const actual = diff --git a/tests/integration/backup-qualitative-lab-restore.test.ts b/tests/integration/backup-qualitative-lab-restore.test.ts index c0f0dc071..232ffe4ee 100644 --- a/tests/integration/backup-qualitative-lab-restore.test.ts +++ b/tests/integration/backup-qualitative-lab-restore.test.ts @@ -44,10 +44,6 @@ vi.mock("next/headers", async () => { }; }); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - vi.mock("@/lib/cache/invalidate", async (importOriginal) => { const actual = await importOriginal(); diff --git a/tests/integration/backup-restore-job.test.ts b/tests/integration/backup-restore-job.test.ts index 29c0be93d..7d3d934ba 100644 --- a/tests/integration/backup-restore-job.test.ts +++ b/tests/integration/backup-restore-job.test.ts @@ -75,10 +75,6 @@ vi.mock("next/headers", async () => { })), }; }); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - /** A queue that records what it is sent and what it is told is finished. */ function recordingBoss() { const sent: Array<{ queue: string; data: unknown }> = []; diff --git a/tests/integration/backup-restore-memory.test.ts b/tests/integration/backup-restore-memory.test.ts index a3d00e570..e9702d61d 100644 --- a/tests/integration/backup-restore-memory.test.ts +++ b/tests/integration/backup-restore-memory.test.ts @@ -31,14 +31,10 @@ import v8 from "node:v8"; import vm from "node:vm"; -import { afterAll, beforeAll, describe, expect, it, vi } from "vitest"; +import { afterAll, beforeAll, describe, expect, it } from "vitest"; import { getPrismaClient, truncateAllTables } from "./setup"; -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - const OWNER = "restore-memory-owner"; const ROWS = 150_000; diff --git a/tests/integration/backup-restore-statement-timeout.test.ts b/tests/integration/backup-restore-statement-timeout.test.ts index 0fd6d182a..cd8ef27ce 100644 --- a/tests/integration/backup-restore-statement-timeout.test.ts +++ b/tests/integration/backup-restore-statement-timeout.test.ts @@ -71,10 +71,6 @@ vi.mock("next/headers", async () => { })), }; }); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - const COUNT = 600; /** diff --git a/tests/integration/backup-round-trip.test.ts b/tests/integration/backup-round-trip.test.ts index 0698b1bb1..cc617b2ec 100644 --- a/tests/integration/backup-round-trip.test.ts +++ b/tests/integration/backup-round-trip.test.ts @@ -147,10 +147,6 @@ vi.mock("next/headers", async () => { }; }); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - vi.mock("@/lib/cache/invalidate", () => ({ invalidateUserData: vi.fn(), })); diff --git a/tests/integration/backup-token-link-restore.test.ts b/tests/integration/backup-token-link-restore.test.ts index f5881593b..802439814 100644 --- a/tests/integration/backup-token-link-restore.test.ts +++ b/tests/integration/backup-token-link-restore.test.ts @@ -39,10 +39,6 @@ vi.mock("next/headers", async () => { }; }); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - vi.mock("@/lib/cache/invalidate", async (importOriginal) => { const actual = await importOriginal(); diff --git a/tests/integration/backup-unknown-catalogue-key-restore.test.ts b/tests/integration/backup-unknown-catalogue-key-restore.test.ts index 6347ba32f..7248b910c 100644 --- a/tests/integration/backup-unknown-catalogue-key-restore.test.ts +++ b/tests/integration/backup-unknown-catalogue-key-restore.test.ts @@ -61,10 +61,6 @@ vi.mock("next/headers", async () => { }; }); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - vi.mock("@/lib/cache/invalidate", () => ({ invalidateUserData: vi.fn(), })); diff --git a/tests/integration/backup-upload-document-memory.test.ts b/tests/integration/backup-upload-document-memory.test.ts index c3221d22f..6bd936c1e 100644 --- a/tests/integration/backup-upload-document-memory.test.ts +++ b/tests/integration/backup-upload-document-memory.test.ts @@ -42,15 +42,11 @@ import { once } from "node:events"; import v8 from "node:v8"; import vm from "node:vm"; -import { afterAll, beforeAll, describe, expect, it, vi } from "vitest"; +import { afterAll, beforeAll, describe, expect, it } from "vitest"; import { cookieJar, headerJar } from "./mock-next-headers"; import { getPrismaClient, truncateAllTables } from "./setup"; -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - const prisma = getPrismaClient(); /** A hundred documents of 2.75 MiB of base64 each: about 275 MB of vault. */ diff --git a/tests/integration/backup-visits-cross-key-restore.test.ts b/tests/integration/backup-visits-cross-key-restore.test.ts index 234f6c136..c3b11f06e 100644 --- a/tests/integration/backup-visits-cross-key-restore.test.ts +++ b/tests/integration/backup-visits-cross-key-restore.test.ts @@ -43,10 +43,6 @@ vi.mock("next/headers", async () => { }; }); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - vi.mock("@/lib/cache/invalidate", () => ({ invalidateUserData: vi.fn(), })); diff --git a/tests/integration/bearer-scope-enforcement.test.ts b/tests/integration/bearer-scope-enforcement.test.ts index 40a5b3b0d..551fbdd45 100644 --- a/tests/integration/bearer-scope-enforcement.test.ts +++ b/tests/integration/bearer-scope-enforcement.test.ts @@ -55,10 +55,6 @@ vi.mock("next/headers", async () => { }; }); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - beforeEach(async () => { await truncateAllTables(getPrismaClient()); cookieJar.clear(); diff --git a/tests/integration/biomarker-backup-completeness.test.ts b/tests/integration/biomarker-backup-completeness.test.ts index 7fe4faa53..f787d0510 100644 --- a/tests/integration/biomarker-backup-completeness.test.ts +++ b/tests/integration/biomarker-backup-completeness.test.ts @@ -44,10 +44,6 @@ vi.mock("next/headers", async () => { }; }); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - vi.mock("@/lib/cache/invalidate", async (importOriginal) => ({ ...(await importOriginal()), invalidateUserData: vi.fn(), diff --git a/tests/integration/biomarker-detail.test.ts b/tests/integration/biomarker-detail.test.ts index 2de6f2362..b9c408396 100644 --- a/tests/integration/biomarker-detail.test.ts +++ b/tests/integration/biomarker-detail.test.ts @@ -39,10 +39,6 @@ vi.mock("next/headers", async () => { }; }); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - beforeEach(async () => { await truncateAllTables(getPrismaClient()); cookieJar.clear(); diff --git a/tests/integration/biomarker-merge.test.ts b/tests/integration/biomarker-merge.test.ts index 87ac6b667..b3fdad383 100644 --- a/tests/integration/biomarker-merge.test.ts +++ b/tests/integration/biomarker-merge.test.ts @@ -35,10 +35,6 @@ vi.mock("next/headers", async () => { }; }); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - const USER_ID = "user-biomarker-merge"; const OTHER_ID = "user-biomarker-merge-other"; const DAY_MS = 86_400_000; diff --git a/tests/integration/blood-pressure-reading-delete.test.ts b/tests/integration/blood-pressure-reading-delete.test.ts index 2e930187d..445511cc8 100644 --- a/tests/integration/blood-pressure-reading-delete.test.ts +++ b/tests/integration/blood-pressure-reading-delete.test.ts @@ -44,10 +44,6 @@ vi.mock("next/headers", async () => { }; }); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - const USER = "user-bp-reading-delete"; const AT = new Date("2026-10-20T07:30:00.000Z"); const MINUTE_LATER = new Date(AT.getTime() + 60_000); diff --git a/tests/integration/body-sites.test.ts b/tests/integration/body-sites.test.ts index 77fb04830..5ec9a2f8c 100644 --- a/tests/integration/body-sites.test.ts +++ b/tests/integration/body-sites.test.ts @@ -51,10 +51,6 @@ vi.mock("next/headers", async () => { }; }); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - const OWNER_ID = "body-site-owner"; const DELEGATE_ID = "body-site-delegate"; diff --git a/tests/integration/bp-in-target.test.ts b/tests/integration/bp-in-target.test.ts index 5dac3ef43..45927342a 100644 --- a/tests/integration/bp-in-target.test.ts +++ b/tests/integration/bp-in-target.test.ts @@ -55,10 +55,6 @@ vi.mock("next/headers", async () => { }; }); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - beforeEach(async () => { await truncateAllTables(getPrismaClient()); cookieJar.clear(); diff --git a/tests/integration/briefing-cache-locale.test.ts b/tests/integration/briefing-cache-locale.test.ts index 8589571c3..6dffd1396 100644 --- a/tests/integration/briefing-cache-locale.test.ts +++ b/tests/integration/briefing-cache-locale.test.ts @@ -36,10 +36,6 @@ vi.mock("next/headers", async () => { }; }); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - const BRIEFING = { greeting: "Good morning", paragraph: "Your readings this week stayed inside their usual range.", diff --git a/tests/integration/bulk-delete-source-filter.test.ts b/tests/integration/bulk-delete-source-filter.test.ts index 5ea9af473..a3056fbe1 100644 --- a/tests/integration/bulk-delete-source-filter.test.ts +++ b/tests/integration/bulk-delete-source-filter.test.ts @@ -41,10 +41,6 @@ vi.mock("next/headers", async () => { }; }); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - async function seedUser(id: string, username: string) { const prisma = getPrismaClient(); await prisma.user.create({ diff --git a/tests/integration/bulk-writer-cache-invalidation.test.ts b/tests/integration/bulk-writer-cache-invalidation.test.ts index 81ce584cc..6225069bd 100644 --- a/tests/integration/bulk-writer-cache-invalidation.test.ts +++ b/tests/integration/bulk-writer-cache-invalidation.test.ts @@ -35,9 +35,6 @@ import { sweepStaleSleepSegments } from "@/lib/sleep/sweep-stale-segments"; import { getPrismaClient, truncateAllTables } from "./setup"; -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); vi.mock("@/lib/jobs/boss-instance", () => ({ getGlobalBoss: vi.fn(() => null), })); diff --git a/tests/integration/cache-invalidation-coverage.test.ts b/tests/integration/cache-invalidation-coverage.test.ts index 578463b94..821729db7 100644 --- a/tests/integration/cache-invalidation-coverage.test.ts +++ b/tests/integration/cache-invalidation-coverage.test.ts @@ -42,21 +42,6 @@ vi.mock("next/headers", async () => { }; }); -// `ensureDbCompatibility` is intentionally LEFT REAL for this file — -// the admin app-settings PUT touches the `app_settings` table whose -// columns land via that helper rather than the migration set in -// `prisma/migrations/`. Mocking it out (as the other integration tests -// do for speed) would make the upsert reference a `default_locale` -// column the test container doesn't carry. Letting the real helper -// run inside the route handler keeps the schema consistent for the -// admin-settings test case in this file. -// -// `isolate: false` in `vitest.integration.config.mts` shares module -// state across files, so a sibling test file that mocks db-compat -// would leak its mock here. The beforeEach below explicitly imports -// the actual implementation through `vi.importActual` and runs it on -// each test setup to defeat that bleed-through. - const PRIMARY_USER_ID = "user-cache-invalidation-primary"; const OTHER_USER_ID = "user-cache-invalidation-other"; @@ -98,12 +83,6 @@ beforeEach(async () => { headerJar.clear(); const { __resetAllCachesForTests } = await import("@/lib/cache/server-cache"); __resetAllCachesForTests(); - // Run the real db-compat helper directly so a sibling test file's - // `vi.mock("@/lib/db-compat", ...)` cannot leave the `app_settings` - // table missing columns the admin-settings PUT writes through. - const realDbCompat = - await vi.importActual("@/lib/db-compat"); - await realDbCompat.ensureDbCompatibility(); await seedUsers(); }); diff --git a/tests/integration/changepoint-extended.test.ts b/tests/integration/changepoint-extended.test.ts index d369dc6b6..32ce368c5 100644 --- a/tests/integration/changepoint-extended.test.ts +++ b/tests/integration/changepoint-extended.test.ts @@ -4,15 +4,11 @@ * (`readDayAggregates`); this proves that path finds a step, reports its * segment sizes, and leaves a switched-off module's metric unread. */ -import { beforeEach, describe, expect, it, vi } from "vitest"; +import { beforeEach, describe, expect, it } from "vitest"; import { getPrismaClient, truncateAllTables } from "./setup"; import { buildExtendedChangepointSignals } from "@/lib/insights/derived/changepoint"; -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - const DAY_MS = 24 * 60 * 60 * 1000; function at(daysAgo: number): Date { diff --git a/tests/integration/chart-all-range-meaning.test.ts b/tests/integration/chart-all-range-meaning.test.ts index bfc406909..8f2400eaf 100644 --- a/tests/integration/chart-all-range-meaning.test.ts +++ b/tests/integration/chart-all-range-meaning.test.ts @@ -18,9 +18,6 @@ import { recomputeUserRollups } from "@/lib/rollups/measurement-rollups"; import { bucketTimeSeries } from "@/lib/charts/bucket-time-series"; import type { MeasurementType } from "@/generated/prisma/client"; -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); vi.mock("@/lib/jobs/boss-instance", () => ({ getGlobalBoss: vi.fn(() => null), })); diff --git a/tests/integration/chart-overlay-prefs.test.ts b/tests/integration/chart-overlay-prefs.test.ts index d86fe392e..93ff64412 100644 --- a/tests/integration/chart-overlay-prefs.test.ts +++ b/tests/integration/chart-overlay-prefs.test.ts @@ -40,10 +40,6 @@ vi.mock("next/headers", async () => { }; }); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - beforeEach(async () => { await truncateAllTables(getPrismaClient()); cookieJar.clear(); diff --git a/tests/integration/chart-range-dense.test.ts b/tests/integration/chart-range-dense.test.ts index 5e36f45cd..e7a39d9df 100644 --- a/tests/integration/chart-range-dense.test.ts +++ b/tests/integration/chart-range-dense.test.ts @@ -37,10 +37,6 @@ vi.mock("next/headers", async () => { }; }); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - const USER = "chart-range-dense-user"; const TZ = "Europe/Berlin"; const TO = new Date("2026-09-20T18:00:00.000Z"); diff --git a/tests/integration/checkup-stays-due.test.ts b/tests/integration/checkup-stays-due.test.ts index efb3a1fde..8c2dd23e9 100644 --- a/tests/integration/checkup-stays-due.test.ts +++ b/tests/integration/checkup-stays-due.test.ts @@ -29,10 +29,6 @@ import type { DispatchOutcome } from "@/lib/notifications/dispatcher"; import { getPrismaClient, truncateAllTables } from "./setup"; -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - const MIGRATION = readFileSync( path.join( process.cwd(), diff --git a/tests/integration/coach-availability-probe.test.ts b/tests/integration/coach-availability-probe.test.ts index 4ea36eed0..7a3453725 100644 --- a/tests/integration/coach-availability-probe.test.ts +++ b/tests/integration/coach-availability-probe.test.ts @@ -11,15 +11,11 @@ * The fixture is the reported case: a fortnight of glucose readings from April * 2024, deliberately outside every window the Coach can search. */ -import { beforeEach, describe, expect, it, vi } from "vitest"; +import { beforeEach, describe, expect, it } from "vitest"; import { getPrismaClient, truncateAllTables } from "./setup"; import { probeCoachAvailability } from "@/lib/ai/coach/tools/availability"; -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - const NOW = new Date("2026-07-26T09:00:00Z"); beforeEach(async () => { diff --git a/tests/integration/coach-chat.test.ts b/tests/integration/coach-chat.test.ts index 00c6cb523..0eb20b8af 100644 --- a/tests/integration/coach-chat.test.ts +++ b/tests/integration/coach-chat.test.ts @@ -47,10 +47,6 @@ vi.mock("next/headers", async () => { }; }); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - // Stub feature extraction so we don't need a full measurement seed. vi.mock("@/lib/insights/features", () => ({ extractFeatures: vi.fn(async () => ({ diff --git a/tests/integration/coach-conversation-delete.test.ts b/tests/integration/coach-conversation-delete.test.ts index 4216ab8d8..c46de55ef 100644 --- a/tests/integration/coach-conversation-delete.test.ts +++ b/tests/integration/coach-conversation-delete.test.ts @@ -34,10 +34,6 @@ vi.mock("next/headers", async () => { }; }); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - beforeEach(async () => { await truncateAllTables(getPrismaClient()); cookieJar.clear(); diff --git a/tests/integration/coach-conversations.test.ts b/tests/integration/coach-conversations.test.ts index 7ca67f8c5..41261eec0 100644 --- a/tests/integration/coach-conversations.test.ts +++ b/tests/integration/coach-conversations.test.ts @@ -37,10 +37,6 @@ vi.mock("next/headers", async () => { }; }); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - beforeEach(async () => { await truncateAllTables(getPrismaClient()); cookieJar.clear(); diff --git a/tests/integration/coach-feedback.test.ts b/tests/integration/coach-feedback.test.ts index af7f7daad..292f6103a 100644 --- a/tests/integration/coach-feedback.test.ts +++ b/tests/integration/coach-feedback.test.ts @@ -36,10 +36,6 @@ vi.mock("next/headers", async () => { }; }); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - beforeEach(async () => { await truncateAllTables(getPrismaClient()); cookieJar.clear(); diff --git a/tests/integration/coach-history-reach.test.ts b/tests/integration/coach-history-reach.test.ts index d32a45b0c..ad726dcdb 100644 --- a/tests/integration/coach-history-reach.test.ts +++ b/tests/integration/coach-history-reach.test.ts @@ -26,9 +26,6 @@ import { readCoachReach } from "@/lib/ai/coach/history-reach-read"; import { UNBOUNDED_REACH } from "@/lib/ai/coach/history-reach"; import { assembleTurnContext } from "@/lib/ai/coach/turn/context"; -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); vi.mock("@/lib/jobs/boss-instance", () => ({ getGlobalBoss: vi.fn(() => null), })); diff --git a/tests/integration/coach-labs-history.test.ts b/tests/integration/coach-labs-history.test.ts index 7273636d4..cf8ed571a 100644 --- a/tests/integration/coach-labs-history.test.ts +++ b/tests/integration/coach-labs-history.test.ts @@ -24,9 +24,6 @@ import { } from "@/lib/ai/coach/history-reach"; import type { CoachLabsBlock } from "@/lib/ai/coach/labs-snapshot"; -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); vi.mock("@/lib/jobs/boss-instance", () => ({ getGlobalBoss: vi.fn(() => null), })); diff --git a/tests/integration/coach-metric-table.test.ts b/tests/integration/coach-metric-table.test.ts index 479725ea0..f1537ade2 100644 --- a/tests/integration/coach-metric-table.test.ts +++ b/tests/integration/coach-metric-table.test.ts @@ -26,9 +26,6 @@ import { executeCoachTool } from "@/lib/ai/coach/tools/executor"; import { appendMessage, createConversation } from "@/lib/ai/coach/persistence"; import type { CoachResultTable } from "@/lib/ai/coach/types"; -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); vi.mock("@/lib/jobs/boss-instance", () => ({ getGlobalBoss: vi.fn(() => null), })); diff --git a/tests/integration/coach-prefs.test.ts b/tests/integration/coach-prefs.test.ts index 38168275a..b5dc6a91e 100644 --- a/tests/integration/coach-prefs.test.ts +++ b/tests/integration/coach-prefs.test.ts @@ -39,10 +39,6 @@ vi.mock("next/headers", async () => { }; }); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - beforeEach(async () => { await truncateAllTables(getPrismaClient()); cookieJar.clear(); diff --git a/tests/integration/coach-series-long-window.test.ts b/tests/integration/coach-series-long-window.test.ts index f14546702..856444d19 100644 --- a/tests/integration/coach-series-long-window.test.ts +++ b/tests/integration/coach-series-long-window.test.ts @@ -33,9 +33,6 @@ import { getServerTranslator } from "@/lib/i18n/server-translator"; import { pluralKey } from "@/lib/i18n/plural"; import type { MeasurementType } from "@/generated/prisma/client"; -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); vi.mock("@/lib/jobs/boss-instance", () => ({ getGlobalBoss: vi.fn(() => null), })); diff --git a/tests/integration/coach-stale-rollup-tail.test.ts b/tests/integration/coach-stale-rollup-tail.test.ts index 60a579b4b..26e13ea4d 100644 --- a/tests/integration/coach-stale-rollup-tail.test.ts +++ b/tests/integration/coach-stale-rollup-tail.test.ts @@ -30,17 +30,13 @@ * either compare a bucket's `computedAt` against the type's in-window * MAX(`updatedAt`), or invalidate on the hard-delete path — and that is a * larger change than this honesty repair. - */ import { beforeEach, describe, expect, it, vi } from "vitest"; + */ import { beforeEach, describe, expect, it } from "vitest"; process.env.ENCRYPTION_KEY ??= "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"; import { getPrismaClient, truncateAllTables } from "./setup"; -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - import { buildCoachSnapshot } from "@/lib/ai/coach/snapshot"; import { recomputeUserRollups } from "@/lib/rollups/measurement-rollups"; diff --git a/tests/integration/coach-trail.test.ts b/tests/integration/coach-trail.test.ts index 3878e6fdd..60f568d4d 100644 --- a/tests/integration/coach-trail.test.ts +++ b/tests/integration/coach-trail.test.ts @@ -36,10 +36,6 @@ vi.mock("next/headers", async () => { }; }); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - // Whether the record's Coach text may be shown is its own suite's question // (`ai-optional-*`); here it is a switch. vi.mock("@/lib/ai/capabilities/gate", async (importOriginal) => ({ diff --git a/tests/integration/codex-credential-park.test.ts b/tests/integration/codex-credential-park.test.ts index 1eb6c4c8c..1857c5619 100644 --- a/tests/integration/codex-credential-park.test.ts +++ b/tests/integration/codex-credential-park.test.ts @@ -40,10 +40,6 @@ vi.mock("next/headers", async () => { }; }); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - vi.mock("@/lib/logging/signal", async (importOriginal) => { const actual = await importOriginal(); return { ...actual, emitSignal: vi.fn(actual.emitSignal) }; diff --git a/tests/integration/compaction-tombstones.test.ts b/tests/integration/compaction-tombstones.test.ts index a4afa1c42..d955dcbec 100644 --- a/tests/integration/compaction-tombstones.test.ts +++ b/tests/integration/compaction-tombstones.test.ts @@ -41,10 +41,6 @@ vi.mock("next/headers", async () => { })), }; }); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - const HOUR = 3_600_000; const DAY = 24 * HOUR; const NOW = Date.now(); diff --git a/tests/integration/correlation-extended-channels.test.ts b/tests/integration/correlation-extended-channels.test.ts index 30c5c8bf0..9082e4440 100644 --- a/tests/integration/correlation-extended-channels.test.ts +++ b/tests/integration/correlation-extended-channels.test.ts @@ -17,10 +17,6 @@ import { fetchTrainingSeries, } from "@/lib/insights/correlation-channel-series"; -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - const DAY_MS = 24 * 60 * 60 * 1000; const TZ = "Europe/Berlin"; diff --git a/tests/integration/correlation-findings-before-seasonal-adjustment.test.ts b/tests/integration/correlation-findings-before-seasonal-adjustment.test.ts index 91af5b9ee..409fa2563 100644 --- a/tests/integration/correlation-findings-before-seasonal-adjustment.test.ts +++ b/tests/integration/correlation-findings-before-seasonal-adjustment.test.ts @@ -7,7 +7,7 @@ * (`AppSettings.correlationSeasonalEngineSince`), which the first discovery * sync of the new engine stamps before it writes, not by a calendar date. */ -import { beforeEach, describe, expect, it, vi } from "vitest"; +import { beforeEach, describe, expect, it } from "vitest"; import { getPrismaClient, truncateAllTables } from "./setup"; import { @@ -22,10 +22,6 @@ import { restoreProfileData, } from "@/lib/export/profile-backup"; -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - const DAY_MS = 24 * 60 * 60 * 1000; const MARKER = new Date("2026-10-08T00:00:00.000Z"); const BEFORE = new Date(MARKER.getTime() - 30 * DAY_MS); diff --git a/tests/integration/correlations-rollup-swap.test.ts b/tests/integration/correlations-rollup-swap.test.ts index c160aa598..e27eba182 100644 --- a/tests/integration/correlations-rollup-swap.test.ts +++ b/tests/integration/correlations-rollup-swap.test.ts @@ -26,10 +26,6 @@ import { getPrismaClient, truncateAllTables } from "./setup"; import { recomputeUserRollups } from "@/lib/rollups/measurement-rollups"; import { fetchMeasurementDailySeriesTiered } from "@/lib/insights/correlation-channel-series"; -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - // The DAY-only recompute never touches pg-boss; leave the boss detached for // parity with the sibling rollup suites (`isolate: false` shares the mock). vi.mock("@/lib/jobs/boss-instance", () => ({ diff --git a/tests/integration/credential-enrollment-proof.test.ts b/tests/integration/credential-enrollment-proof.test.ts index 383b40a0c..78b94d0b3 100644 --- a/tests/integration/credential-enrollment-proof.test.ts +++ b/tests/integration/credential-enrollment-proof.test.ts @@ -41,10 +41,6 @@ vi.mock("next/headers", async () => { }; }); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - const USER_ID = "user-enroll-proof"; const PASSWORD = "Correct horse battery staple!42"; const HOUR = 60 * 60 * 1000; diff --git a/tests/integration/csv-import-contextless-glucose.test.ts b/tests/integration/csv-import-contextless-glucose.test.ts index 9918bd2e0..8396162fb 100644 --- a/tests/integration/csv-import-contextless-glucose.test.ts +++ b/tests/integration/csv-import-contextless-glucose.test.ts @@ -43,10 +43,6 @@ vi.mock("next/headers", async () => { }; }); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - const HEADER = "type,value,unit,measuredAt,glucoseContext,notes,externalId"; async function signIn() { diff --git a/tests/integration/csv-reimport-idempotent.test.ts b/tests/integration/csv-reimport-idempotent.test.ts index f0e8d1621..16efd8cd9 100644 --- a/tests/integration/csv-reimport-idempotent.test.ts +++ b/tests/integration/csv-reimport-idempotent.test.ts @@ -36,10 +36,6 @@ vi.mock("next/headers", async () => { }; }); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - const HEADER = "type,value,unit,measuredAt,glucoseContext,notes,externalId"; const ROWS = 9000; diff --git a/tests/integration/cumulative-pr-rederive-atomic.test.ts b/tests/integration/cumulative-pr-rederive-atomic.test.ts index 77c8509a2..a6ed49f24 100644 --- a/tests/integration/cumulative-pr-rederive-atomic.test.ts +++ b/tests/integration/cumulative-pr-rederive-atomic.test.ts @@ -29,10 +29,6 @@ vi.mock("@/lib/personal-records/pr-detection-worker", async (importActual) => { }, }; }); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - const { runCumulativePrRederivationForUser, CUMULATIVE_PR_FIX_CUTOFF } = await import("@/lib/personal-records/cumulative-pr-rederivation"); diff --git a/tests/integration/cycle-absorbed-restored.test.ts b/tests/integration/cycle-absorbed-restored.test.ts index 0d807a61c..171f9a9e7 100644 --- a/tests/integration/cycle-absorbed-restored.test.ts +++ b/tests/integration/cycle-absorbed-restored.test.ts @@ -40,10 +40,6 @@ vi.mock("next/headers", async () => { }; }); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - beforeEach(async () => { await truncateAllTables(getPrismaClient()); cookieJar.clear(); diff --git a/tests/integration/cycle-crosstab-day-aggregates.test.ts b/tests/integration/cycle-crosstab-day-aggregates.test.ts index 43a04ef05..633853b10 100644 --- a/tests/integration/cycle-crosstab-day-aggregates.test.ts +++ b/tests/integration/cycle-crosstab-day-aggregates.test.ts @@ -6,7 +6,7 @@ * with two sources on the same days, two device types within one source, * dense CGM glucose, summed steps and readings next to Berlin midnight. */ -import { beforeAll, describe, expect, it, vi } from "vitest"; +import { beforeAll, describe, expect, it } from "vitest"; import { getPrismaClient, truncateAllTables } from "./setup"; import { readSourceDayAggregates } from "@/lib/measurements/day-aggregates"; @@ -14,10 +14,6 @@ import { metricDayMap } from "@/lib/insights/mood-crosstab"; import { PHASE_CROSSTAB_METRIC_TYPES } from "@/lib/cycle/phase-crosstab"; import type { CrossMetricMeasurement } from "@/lib/insights/mood-aggregates"; -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - const prisma = getPrismaClient(); const USER = "cycle-crosstab-agg"; const SINCE = new Date("2026-06-01T00:00:00Z"); diff --git a/tests/integration/cycle-flow-opens-cycle.test.ts b/tests/integration/cycle-flow-opens-cycle.test.ts index a77156ee0..e7eb32bc6 100644 --- a/tests/integration/cycle-flow-opens-cycle.test.ts +++ b/tests/integration/cycle-flow-opens-cycle.test.ts @@ -47,10 +47,6 @@ vi.mock("next/headers", async () => { }; }); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - async function loginAs(userId: string): Promise { cookieJar.clear(); headerJar.clear(); diff --git a/tests/integration/cycle-insights-dense-reads.test.ts b/tests/integration/cycle-insights-dense-reads.test.ts index 545e1d24b..5facb4ed0 100644 --- a/tests/integration/cycle-insights-dense-reads.test.ts +++ b/tests/integration/cycle-insights-dense-reads.test.ts @@ -39,10 +39,6 @@ vi.mock("next/headers", async () => { }; }); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - /** When set, the fold is replaced by every raw reading as a one-row group. */ const mode = vi.hoisted(() => ({ raw: false })); diff --git a/tests/integration/cycle-insights-scoped-delegate.test.ts b/tests/integration/cycle-insights-scoped-delegate.test.ts index 482afc6f5..ec908a677 100644 --- a/tests/integration/cycle-insights-scoped-delegate.test.ts +++ b/tests/integration/cycle-insights-scoped-delegate.test.ts @@ -47,10 +47,6 @@ vi.mock("next/headers", async () => { }; }); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - const OWNER_ID = "cycle-insights-owner"; const DELEGATE_ID = "cycle-insights-delegate"; diff --git a/tests/integration/cycle-routes.test.ts b/tests/integration/cycle-routes.test.ts index d75c8822f..0dd4b29af 100644 --- a/tests/integration/cycle-routes.test.ts +++ b/tests/integration/cycle-routes.test.ts @@ -45,10 +45,6 @@ vi.mock("next/headers", async () => { }; }); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - async function loginAs(userId: string): Promise { cookieJar.clear(); headerJar.clear(); diff --git a/tests/integration/cycle-start-round-trip.test.ts b/tests/integration/cycle-start-round-trip.test.ts index bbb458a1e..fcd7ccbaa 100644 --- a/tests/integration/cycle-start-round-trip.test.ts +++ b/tests/integration/cycle-start-round-trip.test.ts @@ -46,10 +46,6 @@ vi.mock("next/headers", async () => { }; }); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - async function loginAs(userId: string): Promise { cookieJar.clear(); headerJar.clear(); diff --git a/tests/integration/daily-digest-today-overview.test.ts b/tests/integration/daily-digest-today-overview.test.ts index 844e73392..1b635764e 100644 --- a/tests/integration/daily-digest-today-overview.test.ts +++ b/tests/integration/daily-digest-today-overview.test.ts @@ -9,7 +9,7 @@ * AI provider is the subject on purpose: the overview has to be whole * without one. */ -import { beforeEach, describe, expect, it, vi } from "vitest"; +import { beforeEach, describe, expect, it } from "vitest"; import type { Prisma } from "@/generated/prisma/client"; import { loadDailyDigest } from "@/lib/daily/load-digest"; @@ -19,10 +19,6 @@ import { PRIORITY_ITEM_KINDS } from "@/lib/daily/priority-item"; import { getPrismaClient, truncateAllTables } from "./setup"; -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - const TZ = "Europe/Berlin"; const DAY = 24 * 60 * 60 * 1000; // 08:00 in Berlin on a Sunday morning. diff --git a/tests/integration/daily-series-user-tz.test.ts b/tests/integration/daily-series-user-tz.test.ts index 4ae147839..5b0df68d0 100644 --- a/tests/integration/daily-series-user-tz.test.ts +++ b/tests/integration/daily-series-user-tz.test.ts @@ -16,7 +16,7 @@ * the live instance has it, and asserts that the daily series (both the * rollup-backed read and the live aggregate) buckets by the user's day. */ -import { beforeEach, describe, expect, it, vi } from "vitest"; +import { beforeEach, describe, expect, it } from "vitest"; import { getPrismaClient, truncateAllTables } from "./setup"; import { @@ -28,10 +28,6 @@ import { invalidateUserTimezone } from "@/lib/tz/resolver"; import { userDayKey } from "@/lib/tz/format"; import { localHmAsUtc } from "@/lib/tz/local-day"; -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - beforeEach(async () => { await truncateAllTables(getPrismaClient()); }); diff --git a/tests/integration/dashboard-chart-overlay-concurrency.test.ts b/tests/integration/dashboard-chart-overlay-concurrency.test.ts index 7ccf4b471..c42466c27 100644 --- a/tests/integration/dashboard-chart-overlay-concurrency.test.ts +++ b/tests/integration/dashboard-chart-overlay-concurrency.test.ts @@ -40,10 +40,6 @@ vi.mock("next/headers", async () => { }; }); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - beforeEach(async () => { await truncateAllTables(getPrismaClient()); cookieJar.clear(); diff --git a/tests/integration/dashboard-glucose-untagged.test.ts b/tests/integration/dashboard-glucose-untagged.test.ts index 810696cac..b8a501eed 100644 --- a/tests/integration/dashboard-glucose-untagged.test.ts +++ b/tests/integration/dashboard-glucose-untagged.test.ts @@ -40,10 +40,6 @@ vi.mock("next/headers", async () => { }; }); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - interface AnalyticsEnvelope { data: { glucoseByContext: Record | null; diff --git a/tests/integration/dashboard-own-target-bands.test.ts b/tests/integration/dashboard-own-target-bands.test.ts index bc0c7994b..faae99863 100644 --- a/tests/integration/dashboard-own-target-bands.test.ts +++ b/tests/integration/dashboard-own-target-bands.test.ts @@ -40,10 +40,6 @@ vi.mock("next/headers", async () => { }; }); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - beforeEach(async () => { await truncateAllTables(getPrismaClient()); cookieJar.clear(); diff --git a/tests/integration/dashboard-pulse-latest-day.test.ts b/tests/integration/dashboard-pulse-latest-day.test.ts index 066e55f41..2ab6716ff 100644 --- a/tests/integration/dashboard-pulse-latest-day.test.ts +++ b/tests/integration/dashboard-pulse-latest-day.test.ts @@ -36,10 +36,6 @@ vi.mock("next/headers", async () => { }; }); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - const prisma = getPrismaClient(); const USER = "pulse-latest-day"; const now = new Date(); diff --git a/tests/integration/dashboard-widgets-save.test.ts b/tests/integration/dashboard-widgets-save.test.ts index f5e16f850..f0136a4f9 100644 --- a/tests/integration/dashboard-widgets-save.test.ts +++ b/tests/integration/dashboard-widgets-save.test.ts @@ -47,10 +47,6 @@ vi.mock("next/headers", async () => { }; }); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - beforeEach(async () => { await truncateAllTables(getPrismaClient()); cookieJar.clear(); diff --git a/tests/integration/dawarich-context.test.ts b/tests/integration/dawarich-context.test.ts index a0f8ddb1a..6cb4b905a 100644 --- a/tests/integration/dawarich-context.test.ts +++ b/tests/integration/dawarich-context.test.ts @@ -55,10 +55,6 @@ vi.mock("next/headers", async () => { }; }); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - const USER_ID = "user-dawarich"; const API_KEY = "dawarich-test-key"; const HOME = 7; diff --git a/tests/integration/day-view.test.ts b/tests/integration/day-view.test.ts index 173db8466..94c2ef33f 100644 --- a/tests/integration/day-view.test.ts +++ b/tests/integration/day-view.test.ts @@ -39,10 +39,6 @@ vi.mock("next/headers", async () => { }; }); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - type Handler = ( request: NextRequest, // eslint-disable-next-line @typescript-eslint/no-explicit-any diff --git a/tests/integration/db-app-role.test.ts b/tests/integration/db-app-role.test.ts new file mode 100644 index 000000000..0be78cf29 --- /dev/null +++ b/tests/integration/db-app-role.test.ts @@ -0,0 +1,387 @@ +/** + * The app's restricted database role, against a real Postgres. + * + * `scripts/db-app-role.mjs` runs at boot as the owner and hands the app a URL + * for `healthlog_app`. Proven here: the role does what the app does (Prisma + * reads and writes, pg-boss installing its schema and creating a queue + * partition, the measurement maintenance's VACUUM and concurrent rebuild), + * and is refused what it must not do (DDL in the app's schema, roles, + * schemas, server files and programs, the migration history). A second run is + * a no-op that keeps the same password, the index the role may not drop is + * dropped by the next run as the owner, and an owner that may not create + * roles leaves the app on the owner with a notice. + * + * On Postgres 16 (the nightly `INTEGRATION_PG_IMAGE` run) the script stays + * on the owner by design; the file proves that instead. + */ +import { PrismaPg } from "@prisma/adapter-pg"; +import { Client } from "pg"; +import { PgBoss } from "pg-boss"; +import { afterAll, beforeAll, describe, expect, it, vi } from "vitest"; + +import { PrismaClient } from "@/generated/prisma/client"; +import { + MAINTENANCE_SESSION_OPTIONS, + RETIRED_MEASUREMENT_INDEXES, + runMeasurementMaintenance, +} from "@/lib/jobs/measurement-maintenance"; +import { + APP_ROLE, + appRolePassword, + ensureAppRole, +} from "../../scripts/db-app-role.mjs"; + +const HMAC_KEY = "a".repeat(64); +const PROBE_OWNER = "app_role_probe_owner"; +const USER_ID = "user-app-role-probe"; +const RETIRED = RETIRED_MEASUREMENT_INDEXES[0]; + +function ownerUrl(): string { + const url = process.env.DATABASE_URL; + if (!url) throw new Error("DATABASE_URL is not set for the integration run"); + return url; +} + +function withoutSchema(url: string): string { + const u = new URL(url); + u.searchParams.delete("schema"); + u.searchParams.delete("pgbouncer"); + return u.toString(); +} + +async function connect(url: string, options?: string): Promise { + const client = new Client({ connectionString: withoutSchema(url), options }); + await client.connect(); + return client; +} + +/** Run the boot step and keep what it says on stderr. */ +async function boot( + env: Record, +): Promise<{ url: string | null; said: string }> { + const lines: string[] = []; + const spy = vi + .spyOn(process.stderr, "write") + .mockImplementation((chunk: string | Uint8Array) => { + lines.push(String(chunk)); + return true; + }); + try { + const url = await ensureAppRole(env as NodeJS.ProcessEnv); + return { url, said: lines.join("") }; + } finally { + spy.mockRestore(); + } +} + +async function sqlState(db: Client, sql: string): Promise { + try { + await db.query(sql); + return null; + } catch (err) { + return (err as { code?: string }).code ?? "unknown"; + } +} + +let owner: Client; +let serverVersion = 0; + +beforeAll(async () => { + owner = await connect(ownerUrl()); + const { rows } = await owner.query<{ v: number }>( + `SELECT current_setting('server_version_num')::int AS v`, + ); + serverVersion = rows[0].v; + // Each file starts from a worker database without the queue schema. + await owner.query(`DROP SCHEMA IF EXISTS pgboss CASCADE`); +}); + +afterAll(async () => { + // The role is cluster-wide: hand back what it owns here and drop it, so no + // other file or run sees it. + for (const role of [APP_ROLE, PROBE_OWNER]) { + const { rows } = await owner.query( + `SELECT 1 FROM pg_roles WHERE rolname = $1`, + [role], + ); + if (rows.length === 0) continue; + await owner.query(`REASSIGN OWNED BY "${role}" TO CURRENT_USER`); + await owner.query(`DROP OWNED BY "${role}"`); + await owner.query(`DROP ROLE "${role}"`); + } + await owner.query(`DROP SCHEMA IF EXISTS pgboss CASCADE`); + await owner.query(`DELETE FROM users WHERE id = $1`, [USER_ID]); + await owner.end(); +}); + +describe("DB_APP_ROLE=off", () => { + it("stays on the owner without touching the database", async () => { + const { url, said } = await boot({ + DATABASE_URL: ownerUrl(), + API_TOKEN_HMAC_KEY: HMAC_KEY, + DB_APP_ROLE: "off", + }); + expect(url).toBeNull(); + expect(said).toContain("DB_APP_ROLE=off"); + const { rows } = await owner.query( + `SELECT 1 FROM pg_roles WHERE rolname = $1`, + [APP_ROLE], + ); + expect(rows).toHaveLength(0); + }); +}); + +describe("an owner that may not create roles", () => { + it("leaves the app on that user, with a notice and no secret in it", async () => { + await owner.query( + `CREATE ROLE ${PROBE_OWNER} LOGIN NOSUPERUSER NOCREATEROLE PASSWORD 'probe-owner-pw'`, + ); + const url = new URL(ownerUrl()); + url.username = PROBE_OWNER; + url.password = "probe-owner-pw"; + const { url: handed, said } = await boot({ + DATABASE_URL: url.toString(), + API_TOKEN_HMAC_KEY: HMAC_KEY, + }); + expect(handed).toBeNull(); + expect(said).toContain(`the app connects as ${PROBE_OWNER}`); + if (serverVersion >= 170000) { + expect(said).toContain("may not create roles"); + } + expect(said).not.toContain("probe-owner-pw"); + expect(said).not.toContain(appRolePassword(HMAC_KEY)); + }); +}); + +describe("Postgres before 17", () => { + it("stays on the owner: no MAINTAIN privilege", async (ctx) => { + if (serverVersion >= 170000) ctx.skip(); + const { url, said } = await boot({ + DATABASE_URL: ownerUrl(), + API_TOKEN_HMAC_KEY: HMAC_KEY, + }); + expect(url).toBeNull(); + expect(said).toContain("no MAINTAIN privilege"); + }); +}); + +describe("the restricted role (Postgres 17+)", () => { + let appUrl: string; + let app: Client; + + beforeAll(async () => { + if (serverVersion < 170000) return; + // A database first created before Postgres 15 still lets PUBLIC create + // objects in `public`; the boot must take that away from the role too. + await owner.query(`GRANT CREATE ON SCHEMA public TO PUBLIC`); + // An index the role may not drop, as an instance that has not run 0416. + await owner.query( + `CREATE INDEX IF NOT EXISTS "${RETIRED}" ON "measurements" ("user_id", "type", "measured_at")`, + ); + const first = await boot({ + DATABASE_URL: ownerUrl(), + API_TOKEN_HMAC_KEY: HMAC_KEY, + }); + expect(first.url, first.said).not.toBeNull(); + expect(first.said).toContain(`the app connects as ${APP_ROLE}`); + expect(first.said).not.toContain(appRolePassword(HMAC_KEY)); + // The first run drops it as the owner; put it back for the role's turn. + expect(first.said).toContain(`dropped index ${RETIRED}`); + await owner.query( + `CREATE INDEX IF NOT EXISTS "${RETIRED}" ON "measurements" ("user_id", "type", "measured_at")`, + ); + appUrl = first.url!; + app = await connect(appUrl); + }); + + afterAll(async () => { + await app?.end(); + }); + + it("keeps the owner's host, database and parameters", async (ctx) => { + if (serverVersion < 170000) ctx.skip(); + const owned = new URL(ownerUrl()); + const handed = new URL(appUrl); + expect(handed.username).toBe(APP_ROLE); + expect(handed.password).toBe(appRolePassword(HMAC_KEY)); + expect(handed.host).toBe(owned.host); + expect(handed.pathname).toBe(owned.pathname); + expect(handed.search).toBe(owned.search); + }); + + it("reads and writes rows through Prisma", async (ctx) => { + if (serverVersion < 170000) ctx.skip(); + const db = new PrismaClient({ + adapter: new PrismaPg({ connectionString: withoutSchema(appUrl) }), + }); + try { + await db.user.create({ + data: { + id: USER_ID, + username: "app-role-probe", + email: "app-role-probe@example.test", + role: "USER", + }, + }); + await db.measurement.create({ + data: { + userId: USER_ID, + type: "WEIGHT", + value: 70, + unit: "kg", + measuredAt: new Date("2026-01-01T08:00:00Z"), + }, + }); + await db.user.update({ + where: { id: USER_ID }, + data: { username: "app-role-probe-2" }, + }); + expect(await db.measurement.count({ where: { userId: USER_ID } })).toBe( + 1, + ); + await db.measurement.deleteMany({ where: { userId: USER_ID } }); + const migrations = await db.$queryRaw<{ n: bigint }[]>` + SELECT count(*) AS n FROM _prisma_migrations`; + expect(Number(migrations[0].n)).toBeGreaterThan(100); + } finally { + await db.$disconnect(); + } + }); + + it("runs pg-boss: install, a queue partition, a job", async (ctx) => { + if (serverVersion < 170000) ctx.skip(); + const boss = new PgBoss({ + connectionString: withoutSchema(appUrl), + createSchema: false, + supervise: false, + schedule: false, + }); + boss.on("error", () => {}); + await boss.start(); + try { + await boss.createQueue("app-role-probe", { policy: "standard" }); + const id = await boss.send("app-role-probe", { n: 1 }); + const [job] = await boss.fetch("app-role-probe"); + expect(job?.id).toBe(id); + await boss.complete("app-role-probe", job.id); + } finally { + await boss.stop({ graceful: false }); + } + const { rows } = await owner.query<{ foreign: string }>( + `SELECT count(*)::text AS foreign FROM pg_class c + JOIN pg_namespace n ON n.oid = c.relnamespace + WHERE n.nspname = 'pgboss' AND c.relkind IN ('r', 'p') + AND pg_get_userbyid(c.relowner) <> $1`, + [APP_ROLE], + ); + expect(rows[0].foreign).toBe("0"); + }); + + it("vacuums and rebuilds measurements, and leaves the drop to the owner", async (ctx) => { + if (serverVersion < 170000) ctx.skip(); + const db = await connect(appUrl, MAINTENANCE_SESSION_OPTIONS); + try { + const summary = await runMeasurementMaintenance(db, { + vacuum: true, + reindex: true, + }); + expect(summary.outcome).toBe("completed"); + // A VACUUM without the privilege only warns and skips the table, so + // the step reads ok either way; the grant is what makes it real. + const { rows } = await db.query<{ maintain: boolean }>( + `SELECT has_table_privilege(current_user, 'measurements', 'MAINTAIN') AS maintain`, + ); + expect(rows[0].maintain).toBe(true); + expect(summary.steps.find((s) => s.step === "vacuum")?.ok).toBe(true); + const rebuilt = summary.steps.filter((s) => s.step === "reindex"); + expect(rebuilt.length).toBeGreaterThan(0); + expect(rebuilt.every((s) => s.ok)).toBe(true); + expect(summary.dropsLeftForBoot).toEqual([RETIRED]); + } finally { + await db.end(); + } + }); + + it("is refused schema changes, roles, schemas, server files and the migration history", async (ctx) => { + if (serverVersion < 170000) ctx.skip(); + const refused = { + dropTable: await sqlState(app, `DROP TABLE "users"`), + alterTable: await sqlState( + app, + `ALTER TABLE "users" ADD COLUMN probe text`, + ), + createTable: await sqlState(app, `CREATE TABLE public.probe (x int)`), + createFunction: await sqlState( + app, + `CREATE FUNCTION public.probe() RETURNS int LANGUAGE sql AS 'SELECT 1'`, + ), + createRole: await sqlState(app, `CREATE ROLE probe_escalation`), + createSchema: await sqlState(app, `CREATE SCHEMA probe`), + readFile: await sqlState(app, `SELECT pg_read_file('postgresql.conf')`), + program: await sqlState(app, `COPY (SELECT 1) TO PROGRAM 'true'`), + dropIndex: await sqlState(app, `DROP INDEX "${RETIRED}"`), + writeMigrations: await sqlState( + app, + `DELETE FROM _prisma_migrations WHERE false`, + ), + becomeOwner: await sqlState( + app, + `SET ROLE ${new URL(ownerUrl()).username}`, + ), + }; + expect(refused).toEqual({ + dropTable: "42501", + alterTable: "42501", + createTable: "42501", + createFunction: "42501", + createRole: "42501", + createSchema: "42501", + readFile: "42501", + program: "42501", + dropIndex: "42501", + writeMigrations: "42501", + becomeOwner: "42501", + }); + const { rows } = await app.query( + `SELECT rolsuper, rolcreaterole, rolcreatedb, rolinherit, rolreplication, rolbypassrls + FROM pg_roles WHERE rolname = current_user`, + ); + expect(rows[0]).toEqual({ + rolsuper: false, + rolcreaterole: false, + rolcreatedb: false, + rolinherit: false, + rolreplication: false, + rolbypassrls: false, + }); + }); + + it("is idempotent: a second boot keeps the password and drops what the role could not", async (ctx) => { + if (serverVersion < 170000) ctx.skip(); + // A table a later migration adds: the next boot grants it. + await owner.query(`CREATE TABLE public.app_role_probe_new (x int)`); + try { + const second = await boot({ + DATABASE_URL: ownerUrl(), + API_TOKEN_HMAC_KEY: HMAC_KEY, + }); + expect(second.url).toBe(appUrl); + expect(second.said).toContain(`dropped index ${RETIRED}`); + // The connection opened before the second boot still works. + await app.query(`INSERT INTO public.app_role_probe_new VALUES (1)`); + const third = await boot({ + DATABASE_URL: ownerUrl(), + API_TOKEN_HMAC_KEY: HMAC_KEY, + }); + expect(third.url).toBe(appUrl); + expect(third.said).not.toContain("dropped index"); + const { rows } = await owner.query( + `SELECT to_regclass($1) IS NULL AS gone`, + [RETIRED], + ); + expect(rows[0].gone).toBe(true); + } finally { + await owner.query(`DROP TABLE public.app_role_probe_new`); + } + }); +}); diff --git a/tests/integration/delegated-intake-notification.test.ts b/tests/integration/delegated-intake-notification.test.ts index c5eb0c47e..311edfad0 100644 --- a/tests/integration/delegated-intake-notification.test.ts +++ b/tests/integration/delegated-intake-notification.test.ts @@ -50,10 +50,6 @@ vi.mock("@parse/node-apn", () => { return { default: { Provider, Notification }, Provider, Notification }; }); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - import { getPrismaClient, truncateAllTables } from "./setup"; const OWNER_ID = "user-delegated-intake-owner"; diff --git a/tests/integration/demo-mode-profile-write.test.ts b/tests/integration/demo-mode-profile-write.test.ts index 5da3aa440..914e58d4f 100644 --- a/tests/integration/demo-mode-profile-write.test.ts +++ b/tests/integration/demo-mode-profile-write.test.ts @@ -42,10 +42,6 @@ vi.mock("next/headers", async () => { }; }); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - /** What the shared demo account carries before any visitor touches it. */ const SEEDED = { username: "demo", diff --git a/tests/integration/demo-seed-ai-texts.test.ts b/tests/integration/demo-seed-ai-texts.test.ts index e4481f1c6..44c24ed66 100644 --- a/tests/integration/demo-seed-ai-texts.test.ts +++ b/tests/integration/demo-seed-ai-texts.test.ts @@ -38,10 +38,6 @@ vi.mock("next/headers", async () => { }; }); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - // A warm on the demo can only fail against the seeded placeholder key, so a // fresh seed must not ask for one. const enqueueForceWarm = vi.fn(); diff --git a/tests/integration/demo-seed-shape.test.ts b/tests/integration/demo-seed-shape.test.ts index d7557b8bd..011f16933 100644 --- a/tests/integration/demo-seed-shape.test.ts +++ b/tests/integration/demo-seed-shape.test.ts @@ -18,14 +18,10 @@ * day-to-day steps around 1 to 2 mmHg outside the climb and the fall). The * peak also has a ceiling: past 148 the chart's padded axis jumps to 50-200. */ -import { beforeAll, describe, expect, it, vi } from "vitest"; +import { beforeAll, describe, expect, it } from "vitest"; import { getPrismaClient, truncateAllTables } from "./setup"; -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - let systolic: number[]; let diastolic: number[]; let means: number[]; diff --git a/tests/integration/demo-seed-sources.test.ts b/tests/integration/demo-seed-sources.test.ts index 3841c61d9..bc07ab63f 100644 --- a/tests/integration/demo-seed-sources.test.ts +++ b/tests/integration/demo-seed-sources.test.ts @@ -10,16 +10,12 @@ * holds every Withings and Apple Health row against the type maps those * integrations ingest through. */ -import { beforeAll, describe, expect, it, vi } from "vitest"; +import { beforeAll, describe, expect, it } from "vitest"; import { getPrismaClient, truncateAllTables } from "./setup"; import { APPLE_HEALTH_TYPE_MAP } from "@/lib/measurements/apple-health-mapping"; import { MEASURE_TYPE_MAP } from "@/lib/withings/client"; -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - const WITHINGS_TYPES = new Set( Object.values(MEASURE_TYPE_MAP).map((m) => m.type), ); diff --git a/tests/integration/dense-glucose-raw-window-series.test.ts b/tests/integration/dense-glucose-raw-window-series.test.ts index ceb6991a6..21e704c13 100644 --- a/tests/integration/dense-glucose-raw-window-series.test.ts +++ b/tests/integration/dense-glucose-raw-window-series.test.ts @@ -48,10 +48,6 @@ vi.mock("next/headers", async () => { }; }); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - const prisma = getPrismaClient(); const TZ = "America/New_York"; const DENSE = "dense-glucose-owner"; diff --git a/tests/integration/dense-pulse-raw-window-reads.test.ts b/tests/integration/dense-pulse-raw-window-reads.test.ts index 886507ace..962443a52 100644 --- a/tests/integration/dense-pulse-raw-window-reads.test.ts +++ b/tests/integration/dense-pulse-raw-window-reads.test.ts @@ -48,10 +48,6 @@ vi.mock("next/headers", async () => { }; }); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - const prisma = getPrismaClient(); const TZ = "America/New_York"; const DENSE = "dense-raw-window-owner"; diff --git a/tests/integration/dense-read-bounded.test.ts b/tests/integration/dense-read-bounded.test.ts index a77ec520c..81f157397 100644 --- a/tests/integration/dense-read-bounded.test.ts +++ b/tests/integration/dense-read-bounded.test.ts @@ -22,7 +22,7 @@ import v8 from "node:v8"; import vm from "node:vm"; -import { afterAll, beforeAll, describe, expect, it, vi } from "vitest"; +import { afterAll, beforeAll, describe, expect, it } from "vitest"; import { getPrismaClient, truncateAllTables } from "./setup"; import { buildGradedSeriesWithRollups } from "@/lib/insights/graded-series"; @@ -32,10 +32,6 @@ import { localHmAsUtc } from "@/lib/tz/local-day"; import { dayValue } from "@/lib/measurements/day-mean"; import { userDayKey } from "@/lib/tz/format"; -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - const prisma = getPrismaClient(); const DENSE_USER = "dense-pulse-owner"; const PARITY_USER = "dense-parity-owner"; diff --git a/tests/integration/dense-series-hrv-spo2.test.ts b/tests/integration/dense-series-hrv-spo2.test.ts index 0145a4ae2..dca6f79fb 100644 --- a/tests/integration/dense-series-hrv-spo2.test.ts +++ b/tests/integration/dense-series-hrv-spo2.test.ts @@ -41,10 +41,6 @@ vi.mock("next/headers", async () => { }; }); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - const prisma = getPrismaClient(); const TZ = "Europe/Berlin"; const DENSE = "dense-hrv-spo2-owner"; diff --git a/tests/integration/dense-targets-reads.test.ts b/tests/integration/dense-targets-reads.test.ts index f2bf0c2ce..9fb0818c1 100644 --- a/tests/integration/dense-targets-reads.test.ts +++ b/tests/integration/dense-targets-reads.test.ts @@ -27,10 +27,6 @@ import { buildVitalTargets } from "@/lib/targets/vitals-builder"; import { userDayKey } from "@/lib/tz/format"; import { invalidateUserTimezone } from "@/lib/tz/resolver"; -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - const prisma = getPrismaClient(); const TZ = "America/New_York"; const DENSE = "dense-targets-owner"; diff --git a/tests/integration/device-register.test.ts b/tests/integration/device-register.test.ts index eeaf368fe..2db21ac8e 100644 --- a/tests/integration/device-register.test.ts +++ b/tests/integration/device-register.test.ts @@ -44,10 +44,6 @@ vi.mock("next/headers", async () => { }; }); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - beforeEach(async () => { await truncateAllTables(getPrismaClient()); cookieJar.clear(); diff --git a/tests/integration/doctor-report-fixed-window.test.ts b/tests/integration/doctor-report-fixed-window.test.ts index e42ceb95c..321d892f9 100644 --- a/tests/integration/doctor-report-fixed-window.test.ts +++ b/tests/integration/doctor-report-fixed-window.test.ts @@ -17,10 +17,6 @@ import { selectionFromLeaves } from "@/lib/report-selection/selection"; import { getPrismaClient, truncateAllTables } from "./setup"; -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - const RANGE = { start: new Date("2026-01-01T00:00:00.000Z"), end: new Date("2026-03-31T23:59:59.999Z"), diff --git a/tests/integration/doctor-report-sections.test.ts b/tests/integration/doctor-report-sections.test.ts index 197beaa68..8b857cf4d 100644 --- a/tests/integration/doctor-report-sections.test.ts +++ b/tests/integration/doctor-report-sections.test.ts @@ -48,10 +48,6 @@ vi.mock("next/headers", async () => { }; }); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - beforeEach(async () => { await truncateAllTables(getPrismaClient()); cookieJar.clear(); diff --git a/tests/integration/document-ai-runs.test.ts b/tests/integration/document-ai-runs.test.ts index 177493de2..9f2c94f8e 100644 --- a/tests/integration/document-ai-runs.test.ts +++ b/tests/integration/document-ai-runs.test.ts @@ -57,10 +57,6 @@ vi.mock("next/headers", async () => { }; }); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - const queue = vi.hoisted(() => ({ up: true, send: vi.fn(async () => "job-1"), diff --git a/tests/integration/document-sources.test.ts b/tests/integration/document-sources.test.ts index 7793fab8d..4c0209f66 100644 --- a/tests/integration/document-sources.test.ts +++ b/tests/integration/document-sources.test.ts @@ -49,10 +49,6 @@ vi.mock("next/headers", async () => { }; }); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - // ── The fake Paperless-ngx behind `safeFetch` ────────────────────────────── const ORIGIN = "http://paperless.lan:8000"; diff --git a/tests/integration/document-undated-lab-value.test.ts b/tests/integration/document-undated-lab-value.test.ts index 154bb4619..6bdbcf2a0 100644 --- a/tests/integration/document-undated-lab-value.test.ts +++ b/tests/integration/document-undated-lab-value.test.ts @@ -42,10 +42,6 @@ vi.mock("next/headers", async () => { }; }); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - beforeEach(async () => { await truncateAllTables(getPrismaClient()); cookieJar.clear(); diff --git a/tests/integration/documents-content-index.test.ts b/tests/integration/documents-content-index.test.ts index 0436158f3..629b9ecda 100644 --- a/tests/integration/documents-content-index.test.ts +++ b/tests/integration/documents-content-index.test.ts @@ -37,10 +37,6 @@ vi.mock("next/headers", async () => { }; }); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - const PNG_1X1 = Buffer.from( "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR4nGNgYGBgAAAABQABXvMqOgAAAABJRU5ErkJggg==", "base64", diff --git a/tests/integration/documents-import.test.ts b/tests/integration/documents-import.test.ts index d6b82bcc7..67ef7398d 100644 --- a/tests/integration/documents-import.test.ts +++ b/tests/integration/documents-import.test.ts @@ -45,10 +45,6 @@ vi.mock("next/headers", async () => { }; }); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - const PNG_1X1 = Buffer.from( "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR4nGNgYGBgAAAABQABXvMqOgAAAABJRU5ErkJggg==", "base64", diff --git a/tests/integration/documents-recently-deleted.test.ts b/tests/integration/documents-recently-deleted.test.ts index 10e474589..6dc0028c9 100644 --- a/tests/integration/documents-recently-deleted.test.ts +++ b/tests/integration/documents-recently-deleted.test.ts @@ -40,10 +40,6 @@ vi.mock("next/headers", async () => { }; }); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - const pdf = (tag: string) => Buffer.from(`%PDF-1.7\n% ${tag}\n1 0 obj\n<<>>\nendobj\n%%EOF\n`); diff --git a/tests/integration/documents-vault.test.ts b/tests/integration/documents-vault.test.ts index 54abfc2aa..367c3a2db 100644 --- a/tests/integration/documents-vault.test.ts +++ b/tests/integration/documents-vault.test.ts @@ -54,10 +54,6 @@ vi.mock("next/headers", async () => { }; }); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - const PNG_1X1 = Buffer.from( "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR4nGNgYGBgAAAABQABXvMqOgAAAABJRU5ErkJggg==", "base64", diff --git a/tests/integration/dose-history-pre-creation-slots.test.ts b/tests/integration/dose-history-pre-creation-slots.test.ts index 3cf129004..49b9ffeb7 100644 --- a/tests/integration/dose-history-pre-creation-slots.test.ts +++ b/tests/integration/dose-history-pre-creation-slots.test.ts @@ -49,10 +49,6 @@ vi.mock("next/headers", async () => { }; }); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - const DAY_MS = 24 * 60 * 60 * 1000; type Handler = ( diff --git a/tests/integration/ecg-ingest-roundtrip.test.ts b/tests/integration/ecg-ingest-roundtrip.test.ts index 24ac2f631..c2f568e4c 100644 --- a/tests/integration/ecg-ingest-roundtrip.test.ts +++ b/tests/integration/ecg-ingest-roundtrip.test.ts @@ -41,10 +41,6 @@ vi.mock("next/headers", async () => { }; }); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - import { GET as getEcgList, POST as postEcg, diff --git a/tests/integration/emergency-profile-route.test.ts b/tests/integration/emergency-profile-route.test.ts index 1a275fdab..f5cbdc20a 100644 --- a/tests/integration/emergency-profile-route.test.ts +++ b/tests/integration/emergency-profile-route.test.ts @@ -38,10 +38,6 @@ vi.mock("next/headers", async () => { }; }); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - async function loginAs(userId: string): Promise { cookieJar.clear(); headerJar.clear(); diff --git a/tests/integration/encounter-appointment-reminder.test.ts b/tests/integration/encounter-appointment-reminder.test.ts index 2ae3e692f..388f971cb 100644 --- a/tests/integration/encounter-appointment-reminder.test.ts +++ b/tests/integration/encounter-appointment-reminder.test.ts @@ -42,10 +42,6 @@ vi.mock("next/headers", async () => { }; }); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - const OWNER_ID = "appointment-owner"; /** Far enough out that the appointment is still in the future mid-run. */ diff --git a/tests/integration/encounter-phase2-surfaces.test.ts b/tests/integration/encounter-phase2-surfaces.test.ts index 7e3e5687f..c58aa34e7 100644 --- a/tests/integration/encounter-phase2-surfaces.test.ts +++ b/tests/integration/encounter-phase2-surfaces.test.ts @@ -46,10 +46,6 @@ vi.mock("next/headers", async () => { }; }); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - const OWNER_ID = "phase2-owner"; function daysFromNow(days: number): Date { diff --git a/tests/integration/encounter-preparation.test.ts b/tests/integration/encounter-preparation.test.ts index 02c6a628e..a269c1f72 100644 --- a/tests/integration/encounter-preparation.test.ts +++ b/tests/integration/encounter-preparation.test.ts @@ -37,10 +37,6 @@ vi.mock("next/headers", async () => { }; }); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - const OWNER_ID = "prep-owner"; const DAY_MS = 24 * 60 * 60 * 1000; diff --git a/tests/integration/encounter-procedures.test.ts b/tests/integration/encounter-procedures.test.ts index 036aa2416..465b97856 100644 --- a/tests/integration/encounter-procedures.test.ts +++ b/tests/integration/encounter-procedures.test.ts @@ -59,10 +59,6 @@ vi.mock("next/headers", async () => { }; }); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - const OWNER_ID = "procedures-owner"; const STRANGER_ID = "procedures-stranger"; diff --git a/tests/integration/encounter-scoped-delegate.test.ts b/tests/integration/encounter-scoped-delegate.test.ts index c00a22c58..3fb8d713c 100644 --- a/tests/integration/encounter-scoped-delegate.test.ts +++ b/tests/integration/encounter-scoped-delegate.test.ts @@ -49,10 +49,6 @@ vi.mock("next/headers", async () => { }; }); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - const OWNER_ID = "scoped-visit-owner"; const DELEGATE_ID = "scoped-visit-delegate"; diff --git a/tests/integration/encryption-key-check.test.ts b/tests/integration/encryption-key-check.test.ts index 7e4700609..f9cb6c3fd 100644 --- a/tests/integration/encryption-key-check.test.ts +++ b/tests/integration/encryption-key-check.test.ts @@ -39,10 +39,6 @@ vi.mock("next/headers", async () => { }; }); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - /** * The start-up probe is bounded in time on purpose: ten seconds in all and * two per query, so a host with a huge table still starts. Those bounds are diff --git a/tests/integration/environment-air-quality-history.test.ts b/tests/integration/environment-air-quality-history.test.ts index 26ef059c2..87e7c32dd 100644 --- a/tests/integration/environment-air-quality-history.test.ts +++ b/tests/integration/environment-air-quality-history.test.ts @@ -29,10 +29,6 @@ import { openLocation, sealLocation } from "@/lib/environment/location-cipher"; import { handleEnvironmentAqHistory } from "@/lib/jobs/environment-air-quality-history"; import { getPrismaClient, truncateAllTables } from "./setup"; -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - const OWNER = "aq-history-owner"; const NOW = new Date("2026-10-09T03:00:00Z"); const BOCHUM = { lat: 51.5, lon: 7.2, label: "Bochum" }; diff --git a/tests/integration/environment-coarse-location.test.ts b/tests/integration/environment-coarse-location.test.ts index 07e753ae9..53a31d8cb 100644 --- a/tests/integration/environment-coarse-location.test.ts +++ b/tests/integration/environment-coarse-location.test.ts @@ -43,10 +43,6 @@ vi.mock("next/headers", async () => { }; }); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - const OWNER_ID = "environment-coarse-owner"; function jsonRequest(url: string, method: string, body: unknown) { diff --git a/tests/integration/environment-location-encryption.test.ts b/tests/integration/environment-location-encryption.test.ts index 79251745e..76b18b1b9 100644 --- a/tests/integration/environment-location-encryption.test.ts +++ b/tests/integration/environment-location-encryption.test.ts @@ -53,10 +53,6 @@ vi.mock("next/headers", async () => { }; }); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - const OWNER = "env-sealed-owner"; function jsonRequest(url: string, method: string, body: unknown) { diff --git a/tests/integration/environment-setup.ts b/tests/integration/environment-setup.ts index ac64aff72..078fd12c7 100644 --- a/tests/integration/environment-setup.ts +++ b/tests/integration/environment-setup.ts @@ -78,10 +78,6 @@ vi.mock("next/headers", async () => { }; }); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - /** * The same pin the unit setup applies (see `vitest.setup.ts`): the Fitbit * suites run before the Web API turndown, whatever the real date, and a test diff --git a/tests/integration/export-per-type.test.ts b/tests/integration/export-per-type.test.ts index 6b7b2ed08..15261893d 100644 --- a/tests/integration/export-per-type.test.ts +++ b/tests/integration/export-per-type.test.ts @@ -44,10 +44,6 @@ vi.mock("next/headers", async () => { }; }); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - beforeEach(async () => { await truncateAllTables(getPrismaClient()); cookieJar.clear(); diff --git a/tests/integration/fitbit-retirement.test.ts b/tests/integration/fitbit-retirement.test.ts index b75f0d2b3..087161cd1 100644 --- a/tests/integration/fitbit-retirement.test.ts +++ b/tests/integration/fitbit-retirement.test.ts @@ -9,9 +9,6 @@ import { beforeEach, describe, expect, it, vi } from "vitest"; import { getPrismaClient, truncateAllTables } from "./setup"; -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); vi.mock("@/lib/notifications/dispatcher", () => ({ dispatchNotification: vi.fn().mockResolvedValue({ dispatched: true, diff --git a/tests/integration/fold-complete-windows.test.ts b/tests/integration/fold-complete-windows.test.ts index 24ce9a024..9064bb4c9 100644 --- a/tests/integration/fold-complete-windows.test.ts +++ b/tests/integration/fold-complete-windows.test.ts @@ -49,10 +49,6 @@ vi.mock("next/headers", async () => { })), }; }); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - const WS_HK = "HKQuantityTypeIdentifierWalkingSpeed"; const HRV_HK = "HKQuantityTypeIdentifierHeartRateVariabilitySDNN"; const HR_HK = "HKQuantityTypeIdentifierHeartRate"; diff --git a/tests/integration/fold-horizon.test.ts b/tests/integration/fold-horizon.test.ts index f0f6d72b2..5169e538b 100644 --- a/tests/integration/fold-horizon.test.ts +++ b/tests/integration/fold-horizon.test.ts @@ -18,10 +18,6 @@ import { afterEach, beforeEach, describe, expect, it, vi } from "vitest"; import { getPrismaClient, truncateAllTables } from "./setup"; -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - const WS_HK = "HKQuantityTypeIdentifierWalkingSpeed"; const HRV_HK = "HKQuantityTypeIdentifierHeartRateVariabilitySDNN"; diff --git a/tests/integration/fold-leftover-provenance.test.ts b/tests/integration/fold-leftover-provenance.test.ts index 34052920f..2833e05c6 100644 --- a/tests/integration/fold-leftover-provenance.test.ts +++ b/tests/integration/fold-leftover-provenance.test.ts @@ -17,10 +17,6 @@ import { afterEach, beforeEach, describe, expect, it, vi } from "vitest"; import { getPrismaClient, truncateAllTables } from "./setup"; -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - const WS_HK = "HKQuantityTypeIdentifierWalkingSpeed"; const HRV_HK = "HKQuantityTypeIdentifierHeartRateVariabilitySDNN"; diff --git a/tests/integration/full-backup-nutrients.test.ts b/tests/integration/full-backup-nutrients.test.ts index 84e0b713d..27730abdb 100644 --- a/tests/integration/full-backup-nutrients.test.ts +++ b/tests/integration/full-backup-nutrients.test.ts @@ -36,10 +36,6 @@ vi.mock("next/headers", async () => { }; }); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - beforeEach(async () => { await truncateAllTables(getPrismaClient()); cookieJar.clear(); diff --git a/tests/integration/golden-backups.test.ts b/tests/integration/golden-backups.test.ts index a1cee3be6..e9d7d4a7f 100644 --- a/tests/integration/golden-backups.test.ts +++ b/tests/integration/golden-backups.test.ts @@ -60,10 +60,6 @@ vi.mock("next/headers", async () => { }; }); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - const FIXTURE_DIR = resolve(__dirname, "../fixtures/golden-backups"); const WRITE = process.env.GOLDEN_BACKUP_WRITE === "1"; const SLOW = 240_000; diff --git a/tests/integration/google-health-account-id.test.ts b/tests/integration/google-health-account-id.test.ts index 07bfd9332..854e5a597 100644 --- a/tests/integration/google-health-account-id.test.ts +++ b/tests/integration/google-health-account-id.test.ts @@ -44,10 +44,6 @@ vi.mock("next/headers", async () => { }; }); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - vi.mock("@/lib/jobs/boss-ready", () => ({ enqueueWhenBossReady: vi.fn().mockResolvedValue("skipped"), })); diff --git a/tests/integration/google-health-backfill-multi-year.test.ts b/tests/integration/google-health-backfill-multi-year.test.ts index b45003c83..659042467 100644 --- a/tests/integration/google-health-backfill-multi-year.test.ts +++ b/tests/integration/google-health-backfill-multi-year.test.ts @@ -259,10 +259,6 @@ vi.mock("@/lib/logging/transports", async (importOriginal) => ({ }, })); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - const forceGc = ((): (() => void) => { v8.setFlagsFromString("--expose-gc"); const gc = vm.runInNewContext("gc") as () => void; diff --git a/tests/integration/google-health-backfill-progress-bound.test.ts b/tests/integration/google-health-backfill-progress-bound.test.ts index ac40e43d1..c4d983d5f 100644 --- a/tests/integration/google-health-backfill-progress-bound.test.ts +++ b/tests/integration/google-health-backfill-progress-bound.test.ts @@ -137,10 +137,6 @@ vi.mock("@/lib/jobs/boss-instance", async (importOriginal) => ({ }), })); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - const OTHER_COLLECTIONS = [ "fetchSteps", "fetchDistance", diff --git a/tests/integration/google-health-backfill-rate-limit.test.ts b/tests/integration/google-health-backfill-rate-limit.test.ts index 457a00d0c..1451a91b7 100644 --- a/tests/integration/google-health-backfill-rate-limit.test.ts +++ b/tests/integration/google-health-backfill-rate-limit.test.ts @@ -195,10 +195,6 @@ vi.mock("@/lib/jobs/boss-instance", async (importOriginal) => ({ }), })); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - async function seed(): Promise { const prisma = getPrismaClient(); await truncateAllTables(prisma); diff --git a/tests/integration/google-health-dense-backfill-memory.test.ts b/tests/integration/google-health-dense-backfill-memory.test.ts index 51af6c4b4..8297ec954 100644 --- a/tests/integration/google-health-dense-backfill-memory.test.ts +++ b/tests/integration/google-health-dense-backfill-memory.test.ts @@ -105,10 +105,6 @@ vi.mock("@/lib/safe-fetch", async (importOriginal) => { }; }); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - const forceGc = ((): (() => void) => { v8.setFlagsFromString("--expose-gc"); const gc = vm.runInNewContext("gc") as () => void; diff --git a/tests/integration/google-health-sleep-overlap.test.ts b/tests/integration/google-health-sleep-overlap.test.ts index ebc1e1e6a..1cfa1ddfd 100644 --- a/tests/integration/google-health-sleep-overlap.test.ts +++ b/tests/integration/google-health-sleep-overlap.test.ts @@ -49,10 +49,6 @@ vi.mock("@/lib/safe-fetch", async (importOriginal) => { }; }); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - /** The night under test: 22:00 UTC two days ago to 06:00 UTC yesterday. */ const NIGHT_START = (() => { const d = new Date(); diff --git a/tests/integration/health-connect-import.test.ts b/tests/integration/health-connect-import.test.ts index 3c965acac..d2d10c3f3 100644 --- a/tests/integration/health-connect-import.test.ts +++ b/tests/integration/health-connect-import.test.ts @@ -42,10 +42,6 @@ import { reconcileOrphanImportJobs, } from "@/lib/jobs/apple-health-import-worker"; -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - const bossMock = vi.hoisted(() => ({ handle: null as null | { getJobById: (queue: string, id: string) => Promise; diff --git a/tests/integration/health-score-configured-flag.test.ts b/tests/integration/health-score-configured-flag.test.ts index 91a556b29..97b3d2ee5 100644 --- a/tests/integration/health-score-configured-flag.test.ts +++ b/tests/integration/health-score-configured-flag.test.ts @@ -59,10 +59,6 @@ vi.mock("next/headers", async () => { }; }); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - // The provider read touches an `app_settings` column that trails the // production schema in this environment, and no surface under test needs // a provider: the digest lifts a cached briefing, it never generates one. diff --git a/tests/integration/health-score-labs-pillars.test.ts b/tests/integration/health-score-labs-pillars.test.ts index 00c1be13a..af2f34614 100644 --- a/tests/integration/health-score-labs-pillars.test.ts +++ b/tests/integration/health-score-labs-pillars.test.ts @@ -50,10 +50,6 @@ vi.mock("next/headers", async () => { }; }); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - beforeEach(async () => { await truncateAllTables(getPrismaClient()); cookieJar.clear(); diff --git a/tests/integration/health-score-record.test.ts b/tests/integration/health-score-record.test.ts index 53a49120b..d0a55a25b 100644 --- a/tests/integration/health-score-record.test.ts +++ b/tests/integration/health-score-record.test.ts @@ -60,10 +60,6 @@ vi.mock("next/headers", async () => { }; }); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - vi.mock("@/lib/cache/invalidate", () => ({ invalidateUserData: vi.fn(), invalidateUserHealthScore: vi.fn(), diff --git a/tests/integration/health-status-implausible-values.test.ts b/tests/integration/health-status-implausible-values.test.ts index 282ed03c2..e4c093910 100644 --- a/tests/integration/health-status-implausible-values.test.ts +++ b/tests/integration/health-status-implausible-values.test.ts @@ -38,10 +38,6 @@ vi.mock("next/headers", async () => { }; }); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - const DAY_MS = 24 * 60 * 60 * 1000; /** The two numbers off the report, kept verbatim so the case stays legible. */ const IMPOSSIBLE_PULSE = 111287531.01; diff --git a/tests/integration/healthkit-type-sync.test.ts b/tests/integration/healthkit-type-sync.test.ts index fd8dd5455..9e403b194 100644 --- a/tests/integration/healthkit-type-sync.test.ts +++ b/tests/integration/healthkit-type-sync.test.ts @@ -44,10 +44,6 @@ vi.mock("next/headers", async () => { }; }); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - beforeEach(async () => { await truncateAllTables(getPrismaClient()); cookieJar.clear(); diff --git a/tests/integration/hour-buckets-and-backfill.test.ts b/tests/integration/hour-buckets-and-backfill.test.ts index 299b76dfa..30c396c12 100644 --- a/tests/integration/hour-buckets-and-backfill.test.ts +++ b/tests/integration/hour-buckets-and-backfill.test.ts @@ -38,10 +38,6 @@ vi.mock("next/headers", async () => { }; }); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - beforeEach(async () => { await truncateAllTables(getPrismaClient()); cookieJar.clear(); diff --git a/tests/integration/hrv-rmssd-fitbit-google-migration.test.ts b/tests/integration/hrv-rmssd-fitbit-google-migration.test.ts index cbbadf508..8e2742407 100644 --- a/tests/integration/hrv-rmssd-fitbit-google-migration.test.ts +++ b/tests/integration/hrv-rmssd-fitbit-google-migration.test.ts @@ -15,9 +15,6 @@ import type { Prisma } from "@/generated/prisma/client"; import { enqueueBootTimeRollupBackfill } from "@/lib/rollups/full-backfill"; import { recomputeUserRollups } from "@/lib/rollups/measurement-rollups"; -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); vi.mock("@/lib/jobs/boss-instance", () => ({ getGlobalBoss: vi.fn(() => null), })); diff --git a/tests/integration/hrv-rmssd-ingest.test.ts b/tests/integration/hrv-rmssd-ingest.test.ts index 47a932972..ce7e482a7 100644 --- a/tests/integration/hrv-rmssd-ingest.test.ts +++ b/tests/integration/hrv-rmssd-ingest.test.ts @@ -38,10 +38,6 @@ vi.mock("next/headers", async () => { }; }); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - beforeEach(async () => { await truncateAllTables(getPrismaClient()); cookieJar.clear(); diff --git a/tests/integration/idempotency-body-fingerprint.test.ts b/tests/integration/idempotency-body-fingerprint.test.ts index c0d04d93c..ebc26eedb 100644 --- a/tests/integration/idempotency-body-fingerprint.test.ts +++ b/tests/integration/idempotency-body-fingerprint.test.ts @@ -46,10 +46,6 @@ vi.mock("next/headers", async () => { }; }); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - const USER_A = "idem-fingerprint-a"; const USER_B = "idem-fingerprint-b"; const KEY = "bp-entry-5c1e2a7f"; diff --git a/tests/integration/idempotency-record-scoped-cell.test.ts b/tests/integration/idempotency-record-scoped-cell.test.ts index 9fc440c9b..d1b5a41da 100644 --- a/tests/integration/idempotency-record-scoped-cell.test.ts +++ b/tests/integration/idempotency-record-scoped-cell.test.ts @@ -41,10 +41,6 @@ vi.mock("next/headers", async () => { }; }); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - import { ACCOUNT_SELECTOR_HEADER, apiHandler, diff --git a/tests/integration/idempotency-replay.test.ts b/tests/integration/idempotency-replay.test.ts index 567760834..a8b243060 100644 --- a/tests/integration/idempotency-replay.test.ts +++ b/tests/integration/idempotency-replay.test.ts @@ -41,10 +41,6 @@ vi.mock("next/headers", async () => { }; }); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - beforeEach(async () => { await truncateAllTables(getPrismaClient()); cookieJar.clear(); diff --git a/tests/integration/insights-comprehensive-cache.test.ts b/tests/integration/insights-comprehensive-cache.test.ts index fec430c3d..84f7f5f11 100644 --- a/tests/integration/insights-comprehensive-cache.test.ts +++ b/tests/integration/insights-comprehensive-cache.test.ts @@ -41,10 +41,6 @@ vi.mock("next/headers", async () => { }; }); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - // `resolveProvider` reads `app_settings.default_locale` which trails the // production schema in this integration env. Mock the leaf: the route // only uses `provider.type !== "none"` to set the `hasProvider` flag. diff --git a/tests/integration/insights-feedback.test.ts b/tests/integration/insights-feedback.test.ts index d6c233a25..1b5173466 100644 --- a/tests/integration/insights-feedback.test.ts +++ b/tests/integration/insights-feedback.test.ts @@ -39,10 +39,6 @@ vi.mock("next/headers", async () => { }; }); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - beforeEach(async () => { await truncateAllTables(getPrismaClient()); cookieJar.clear(); diff --git a/tests/integration/insights-provider-chain-put.test.ts b/tests/integration/insights-provider-chain-put.test.ts index d3ac5aba3..c4ad6a292 100644 --- a/tests/integration/insights-provider-chain-put.test.ts +++ b/tests/integration/insights-provider-chain-put.test.ts @@ -43,10 +43,6 @@ vi.mock("next/headers", async () => { }; }); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - beforeEach(async () => { await truncateAllTables(getPrismaClient()); cookieJar.clear(); diff --git a/tests/integration/insights-provider-chain.test.ts b/tests/integration/insights-provider-chain.test.ts index 017d27094..1fccdc3cc 100644 --- a/tests/integration/insights-provider-chain.test.ts +++ b/tests/integration/insights-provider-chain.test.ts @@ -42,10 +42,6 @@ vi.mock("next/headers", async () => { }; }); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - // safeFetch's requirePublicHost path runs through undici's own `fetch` // (version-locked with its dispatcher) rather than the global. Delegate it to // the global `fetch` spy these tests install so the provider HTTP is mocked. diff --git a/tests/integration/insights-status-real-text.test.ts b/tests/integration/insights-status-real-text.test.ts index c0f9c3517..a4ac51be7 100644 --- a/tests/integration/insights-status-real-text.test.ts +++ b/tests/integration/insights-status-real-text.test.ts @@ -18,10 +18,6 @@ import { afterEach, beforeEach, describe, expect, it, vi } from "vitest"; import { getPrismaClient, truncateAllTables } from "./setup"; -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - // Stub the provider resolution so the chain runner has a deterministic // provider to walk. `runRawCompletionWithFallback` runs for real on top // of this — exercising the same plumbing the live status path uses. diff --git a/tests/integration/intake-backfill-missed-slot.test.ts b/tests/integration/intake-backfill-missed-slot.test.ts index c4b613ffa..3e8aa837f 100644 --- a/tests/integration/intake-backfill-missed-slot.test.ts +++ b/tests/integration/intake-backfill-missed-slot.test.ts @@ -45,10 +45,6 @@ vi.mock("next/headers", async () => { }; }); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - const TZ = "Europe/Berlin"; const DAY_MS = 24 * 60 * 60 * 1000; diff --git a/tests/integration/intake-late-take-future-slot.test.ts b/tests/integration/intake-late-take-future-slot.test.ts index 797d809d3..0d1f1a0c8 100644 --- a/tests/integration/intake-late-take-future-slot.test.ts +++ b/tests/integration/intake-late-take-future-slot.test.ts @@ -19,7 +19,7 @@ * dashboard composes (`computeDisplayDue` + the taken/scheduled tally) reflects * the correct state. */ -import { beforeEach, describe, expect, it, vi } from "vitest"; +import { beforeEach, describe, expect, it } from "vitest"; import { getPrismaClient, truncateAllTables } from "./setup"; @@ -38,10 +38,6 @@ import { localHmAsUtc } from "@/lib/tz/local-day"; const TEST_USER_ID = "user-late-take-future-slot"; const TZ = "Europe/Berlin"; -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - // Fixed non-DST-boundary weekday so the slot instants are deterministic. const DAY = new Date("2026-03-10T12:00:00.000Z"); const slot0900 = () => localHmAsUtc(DAY, TZ, 9, 0); diff --git a/tests/integration/intake-scheduled-for-targeting.test.ts b/tests/integration/intake-scheduled-for-targeting.test.ts index 9fe820313..c9aabf03c 100644 --- a/tests/integration/intake-scheduled-for-targeting.test.ts +++ b/tests/integration/intake-scheduled-for-targeting.test.ts @@ -16,7 +16,7 @@ * 2. Marking the morning dose does NOT mark the evening dose (the evening * slot stays pending) and vice-versa. */ -import { beforeEach, describe, expect, it, vi } from "vitest"; +import { beforeEach, describe, expect, it } from "vitest"; import { getPrismaClient, truncateAllTables } from "./setup"; @@ -28,10 +28,6 @@ import { localHmAsUtc } from "@/lib/tz/local-day"; const TEST_USER_ID = "user-intake-scheduledfor-targeting"; -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - beforeEach(async () => { const prisma = getPrismaClient(); await truncateAllTables(prisma); diff --git a/tests/integration/intake-slot-dedup.test.ts b/tests/integration/intake-slot-dedup.test.ts index 57da5c2a0..46db94780 100644 --- a/tests/integration/intake-slot-dedup.test.ts +++ b/tests/integration/intake-slot-dedup.test.ts @@ -17,7 +17,7 @@ * 4. taken > skipped tie-break keeps the taken row. * 5. Boot discovery only matches users that actually hold duplicates. */ -import { beforeEach, describe, expect, it, vi } from "vitest"; +import { beforeEach, describe, expect, it } from "vitest"; import { getPrismaClient, truncateAllTables } from "./setup"; @@ -34,10 +34,6 @@ import { localHmAsUtc } from "@/lib/tz/local-day"; const TEST_USER_ID = "user-intake-slot-dedup"; const OTHER_USER_ID = "user-intake-slot-dedup-clean"; -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - beforeEach(async () => { const prisma = getPrismaClient(); await truncateAllTables(prisma); diff --git a/tests/integration/integration-status.test.ts b/tests/integration/integration-status.test.ts index 39198b593..6b08f217e 100644 --- a/tests/integration/integration-status.test.ts +++ b/tests/integration/integration-status.test.ts @@ -22,10 +22,6 @@ process.env.ENCRYPTION_KEY ??= import { getPrismaClient, truncateAllTables } from "./setup"; -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - // The dispatcher would otherwise try to read encrypted channel // configs and call sendViaTelegram. We're not testing that path — // B3 owns it. Stub returns void so the helper's await chain diff --git a/tests/integration/integration-sync-escalation.test.ts b/tests/integration/integration-sync-escalation.test.ts index f39a66614..8423e5ec7 100644 --- a/tests/integration/integration-sync-escalation.test.ts +++ b/tests/integration/integration-sync-escalation.test.ts @@ -26,10 +26,6 @@ process.env.ENCRYPTION_KEY ??= import { getPrismaClient, truncateAllTables } from "./setup"; -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - vi.mock("@/lib/logging/signal", async (importOriginal) => { const actual = await importOriginal(); return { ...actual, emitSignal: vi.fn(actual.emitSignal) }; diff --git a/tests/integration/integration-watchdog.test.ts b/tests/integration/integration-watchdog.test.ts index 777e3ce80..d31115bd0 100644 --- a/tests/integration/integration-watchdog.test.ts +++ b/tests/integration/integration-watchdog.test.ts @@ -14,10 +14,6 @@ process.env.ENCRYPTION_KEY ??= import { getPrismaClient, truncateAllTables } from "./setup"; -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - vi.mock("@/lib/notifications/dispatcher", () => ({ dispatchNotification: vi.fn().mockResolvedValue({ dispatched: true, diff --git a/tests/integration/lab-source-reference-range.test.ts b/tests/integration/lab-source-reference-range.test.ts index 7cb112060..2591a63ea 100644 --- a/tests/integration/lab-source-reference-range.test.ts +++ b/tests/integration/lab-source-reference-range.test.ts @@ -47,10 +47,6 @@ vi.mock("next/headers", async () => { }; }); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - beforeEach(async () => { await truncateAllTables(getPrismaClient()); cookieJar.clear(); diff --git a/tests/integration/lab-unit-mismatch.test.ts b/tests/integration/lab-unit-mismatch.test.ts index 06a926202..abe0c670e 100644 --- a/tests/integration/lab-unit-mismatch.test.ts +++ b/tests/integration/lab-unit-mismatch.test.ts @@ -46,10 +46,6 @@ vi.mock("next/headers", async () => { }; }); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - beforeEach(async () => { await truncateAllTables(getPrismaClient()); cookieJar.clear(); diff --git a/tests/integration/labs-analyte-key.test.ts b/tests/integration/labs-analyte-key.test.ts index 0e17970ff..ca6c4b9fb 100644 --- a/tests/integration/labs-analyte-key.test.ts +++ b/tests/integration/labs-analyte-key.test.ts @@ -42,10 +42,6 @@ vi.mock("next/headers", async () => { }; }); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - const prisma = getPrismaClient(); const USER = "analyte-key-user"; diff --git a/tests/integration/labs-overview-long-history.test.ts b/tests/integration/labs-overview-long-history.test.ts index bf0bbaa6c..35c6704f8 100644 --- a/tests/integration/labs-overview-long-history.test.ts +++ b/tests/integration/labs-overview-long-history.test.ts @@ -38,10 +38,6 @@ vi.mock("next/headers", async () => { }; }); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - /** Days before now, so the fixture never ages out of its own windows. */ const daysAgo = (days: number) => new Date(Date.now() - days * DAY_MS); diff --git a/tests/integration/labs-unit-conversion.test.ts b/tests/integration/labs-unit-conversion.test.ts index 89af81ce8..6ff07e615 100644 --- a/tests/integration/labs-unit-conversion.test.ts +++ b/tests/integration/labs-unit-conversion.test.ts @@ -41,10 +41,6 @@ vi.mock("next/headers", async () => { }; }); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - const prisma = getPrismaClient(); const USER = "lab-conversion-user"; const MGDL_PER_MMOL = 18.0182; diff --git a/tests/integration/large-account-google-health.test.ts b/tests/integration/large-account-google-health.test.ts index 630a2898b..5faa85235 100644 --- a/tests/integration/large-account-google-health.test.ts +++ b/tests/integration/large-account-google-health.test.ts @@ -74,10 +74,6 @@ vi.mock("@/lib/safe-fetch", async (importOriginal) => { }; }); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - vi.mock("@/lib/jobs/boss-instance", () => ({ getGlobalBoss: vi.fn(() => null), })); diff --git a/tests/integration/large-backup-round-trip.test.ts b/tests/integration/large-backup-round-trip.test.ts index 13276e15c..33a58165c 100644 --- a/tests/integration/large-backup-round-trip.test.ts +++ b/tests/integration/large-backup-round-trip.test.ts @@ -49,10 +49,6 @@ vi.mock("next/headers", async () => { })), }; }); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - const COUNT = 7_300; // more than one read page and several write batches beforeEach(async () => { diff --git a/tests/integration/life-circumstances.test.ts b/tests/integration/life-circumstances.test.ts index 508c8a53c..2a738add8 100644 --- a/tests/integration/life-circumstances.test.ts +++ b/tests/integration/life-circumstances.test.ts @@ -35,10 +35,6 @@ vi.mock("next/headers", async () => { }; }); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - type Handler = (request: Request, ctx?: unknown) => Promise; let counter = 0; diff --git a/tests/integration/list-pagination-tiebreaker.test.ts b/tests/integration/list-pagination-tiebreaker.test.ts index 171aa9aad..3f4336989 100644 --- a/tests/integration/list-pagination-tiebreaker.test.ts +++ b/tests/integration/list-pagination-tiebreaker.test.ts @@ -48,10 +48,6 @@ vi.mock("next/headers", async () => { }; }); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - /** * Insertion order deliberately unrelated to id order: 04, 09, 01, 06, 00, … * A scan that ignores the secondary key returns this sequence; one that diff --git a/tests/integration/local-day-keys.test.ts b/tests/integration/local-day-keys.test.ts index 5f9d2e5ef..61333afa4 100644 --- a/tests/integration/local-day-keys.test.ts +++ b/tests/integration/local-day-keys.test.ts @@ -8,16 +8,12 @@ * 23:30 UTC is the next day in Berlin and still the same day in Los Angeles, * a reading at 03:00 UTC is the previous day in Los Angeles. */ -import { beforeEach, describe, expect, it, vi } from "vitest"; +import { beforeEach, describe, expect, it } from "vitest"; import { getPrismaClient, truncateAllTables } from "./setup"; import { readActivityDayKeys } from "@/lib/dashboard/summary-reads"; import { userDayKey } from "@/lib/tz/format"; -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - const prisma = getPrismaClient(); const USER = "local-day-keys"; const now = new Date(); diff --git a/tests/integration/login-insecure-transport.test.ts b/tests/integration/login-insecure-transport.test.ts index c23df31ba..f675eceb7 100644 --- a/tests/integration/login-insecure-transport.test.ts +++ b/tests/integration/login-insecure-transport.test.ts @@ -42,10 +42,6 @@ vi.mock("next/headers", async () => { }; }); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - const { hashPassword } = await import("@/lib/auth/password"); const { encrypt } = await import("@/lib/crypto"); const { generateTotpSecret } = await import("@/lib/auth/mfa/totp"); diff --git a/tests/integration/managed-profile-edit.test.ts b/tests/integration/managed-profile-edit.test.ts index afb9fdcf0..0f905bc28 100644 --- a/tests/integration/managed-profile-edit.test.ts +++ b/tests/integration/managed-profile-edit.test.ts @@ -48,10 +48,6 @@ vi.mock("next/headers", async () => { }; }); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - let sequence = 0; interface Person { diff --git a/tests/integration/managed-profile-handover-sso.test.ts b/tests/integration/managed-profile-handover-sso.test.ts index 842e9e8c7..2beab6343 100644 --- a/tests/integration/managed-profile-handover-sso.test.ts +++ b/tests/integration/managed-profile-handover-sso.test.ts @@ -54,10 +54,6 @@ vi.mock("next/headers", async () => { }; }); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - vi.mock("@/lib/password-breach-check", () => ({ checkPasswordBreachIfEnabled: vi.fn().mockResolvedValue(null), })); diff --git a/tests/integration/managed-profile-handover-stepup-sso.test.ts b/tests/integration/managed-profile-handover-stepup-sso.test.ts index bcb8f6d63..f4da13f7b 100644 --- a/tests/integration/managed-profile-handover-stepup-sso.test.ts +++ b/tests/integration/managed-profile-handover-stepup-sso.test.ts @@ -67,10 +67,6 @@ vi.mock("next/headers", async () => { }; }); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - vi.mock("@/lib/notifications/dispatch-localised", () => ({ dispatchLocalisedNotification: vi.fn(async () => {}), })); diff --git a/tests/integration/managed-profile-handover.test.ts b/tests/integration/managed-profile-handover.test.ts index 6a6c5a5c7..de881e84c 100644 --- a/tests/integration/managed-profile-handover.test.ts +++ b/tests/integration/managed-profile-handover.test.ts @@ -78,10 +78,6 @@ vi.mock("next/headers", async () => { }; }); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - // The breach corpus is a network call; the claim's own logic is the subject. vi.mock("@/lib/password-breach-check", () => ({ checkPasswordBreachIfEnabled: vi.fn().mockResolvedValue(null), diff --git a/tests/integration/managed-profile-lifecycle.test.ts b/tests/integration/managed-profile-lifecycle.test.ts index b1367db2d..d97a7419e 100644 --- a/tests/integration/managed-profile-lifecycle.test.ts +++ b/tests/integration/managed-profile-lifecycle.test.ts @@ -40,10 +40,6 @@ vi.mock("next/headers", async () => { }; }); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - let sequence = 0; async function createFreshMfaUser(label = "guardian") { diff --git a/tests/integration/managed-profile-oauth-connect.test.ts b/tests/integration/managed-profile-oauth-connect.test.ts index be879252e..7c6828cfa 100644 --- a/tests/integration/managed-profile-oauth-connect.test.ts +++ b/tests/integration/managed-profile-oauth-connect.test.ts @@ -38,10 +38,6 @@ vi.mock("next/headers", async () => { }; }); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - const OURA_TOKEN_URL = "https://moi.ouraring.com/oauth/v2/ext/oauth-token"; const OURA_ISS = "https://moi.ouraring.com/oauth/v2/ext/oauth-anonymous"; const GUARDIAN = "guardian-oauth"; diff --git a/tests/integration/managed-profile-passkey-step-up.test.ts b/tests/integration/managed-profile-passkey-step-up.test.ts index 06651bbb8..36e1bca54 100644 --- a/tests/integration/managed-profile-passkey-step-up.test.ts +++ b/tests/integration/managed-profile-passkey-step-up.test.ts @@ -44,10 +44,6 @@ vi.mock("next/headers", async () => { }; }); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - vi.mock("@/lib/notifications/dispatch-localised", () => ({ dispatchLocalisedNotification: vi.fn(async () => {}), })); diff --git a/tests/integration/managed-profile-surface.test.ts b/tests/integration/managed-profile-surface.test.ts index b135ce059..57ed68f4b 100644 --- a/tests/integration/managed-profile-surface.test.ts +++ b/tests/integration/managed-profile-surface.test.ts @@ -58,10 +58,6 @@ vi.mock("next/headers", async () => { }; }); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - let sequence = 0; interface Person { diff --git a/tests/integration/managed-record-capabilities.test.ts b/tests/integration/managed-record-capabilities.test.ts index 66458e9ff..a2ef88e52 100644 --- a/tests/integration/managed-record-capabilities.test.ts +++ b/tests/integration/managed-record-capabilities.test.ts @@ -49,10 +49,6 @@ vi.mock("next/headers", async () => { }; }); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - import { delegatedDomains } from "@/lib/sharing/domain-write-support"; import type { ShareDomain } from "@/lib/sharing/scope"; diff --git a/tests/integration/managed-record-modules.test.ts b/tests/integration/managed-record-modules.test.ts index 181607419..c9d6db1bc 100644 --- a/tests/integration/managed-record-modules.test.ts +++ b/tests/integration/managed-record-modules.test.ts @@ -50,10 +50,6 @@ vi.mock("next/headers", async () => { }; }); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - let counter = 0; async function makeUser(label: string) { diff --git a/tests/integration/manual-workout-edit.test.ts b/tests/integration/manual-workout-edit.test.ts index 1abf71e2a..5cbfb8d20 100644 --- a/tests/integration/manual-workout-edit.test.ts +++ b/tests/integration/manual-workout-edit.test.ts @@ -43,10 +43,6 @@ vi.mock("next/headers", async () => { }; }); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - beforeEach(async () => { await truncateAllTables(getPrismaClient()); cookieJar.clear(); diff --git a/tests/integration/mcp-metric-series-source-snapshot.test.ts b/tests/integration/mcp-metric-series-source-snapshot.test.ts index ab95bc21a..37e6a3148 100644 --- a/tests/integration/mcp-metric-series-source-snapshot.test.ts +++ b/tests/integration/mcp-metric-series-source-snapshot.test.ts @@ -26,9 +26,6 @@ import { ensureUserMoodRollupsFresh } from "@/lib/rollups/mood-rollups"; import type { CoachScopeSource, CoachScopeWindow } from "@/lib/ai/coach/types"; import type { MeasurementType, SleepStage } from "@/generated/prisma/client"; -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); vi.mock("@/lib/jobs/boss-instance", () => ({ getGlobalBoss: vi.fn(() => null), })); diff --git a/tests/integration/measurement-rollups.test.ts b/tests/integration/measurement-rollups.test.ts index 795b30c2a..10441641a 100644 --- a/tests/integration/measurement-rollups.test.ts +++ b/tests/integration/measurement-rollups.test.ts @@ -41,10 +41,6 @@ import { aggregateBuckets } from "@/lib/rollups/measurement-read"; import { buildComprehensiveAggregate } from "@/lib/insights/comprehensive-aggregator"; import { windowWeighting } from "@/lib/measurements/day-statistic"; -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - // Stub boss-instance with a vi.fn so we can swap the return per test. // The integration suite runs with `isolate: false`, so the mock state // is shared with sibling files (e.g. admin-backups-audit.test.ts also diff --git a/tests/integration/measurement-soft-delete.test.ts b/tests/integration/measurement-soft-delete.test.ts index 8703b9e46..7071e7612 100644 --- a/tests/integration/measurement-soft-delete.test.ts +++ b/tests/integration/measurement-soft-delete.test.ts @@ -60,10 +60,6 @@ vi.mock("next/headers", async () => { }; }); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - beforeEach(async () => { await truncateAllTables(getPrismaClient()); cookieJar.clear(); diff --git a/tests/integration/measurement-source-write-smoke.test.ts b/tests/integration/measurement-source-write-smoke.test.ts index d117bd576..d2aa00ea3 100644 --- a/tests/integration/measurement-source-write-smoke.test.ts +++ b/tests/integration/measurement-source-write-smoke.test.ts @@ -52,10 +52,6 @@ vi.mock("next/headers", async () => { }; }); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - const USER_ID = "measurement-source-write-smoke"; const MEASURED_AT = new Date("2026-07-20T08:00:00.000Z"); diff --git a/tests/integration/measurements-aggregate-daily.test.ts b/tests/integration/measurements-aggregate-daily.test.ts index 041ce9716..2783efcc6 100644 --- a/tests/integration/measurements-aggregate-daily.test.ts +++ b/tests/integration/measurements-aggregate-daily.test.ts @@ -42,10 +42,6 @@ vi.mock("next/headers", async () => { }; }); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - beforeEach(async () => { await truncateAllTables(getPrismaClient()); cookieJar.clear(); diff --git a/tests/integration/measurements-batch-delete.test.ts b/tests/integration/measurements-batch-delete.test.ts index a3a3f9d55..1c62f9a88 100644 --- a/tests/integration/measurements-batch-delete.test.ts +++ b/tests/integration/measurements-batch-delete.test.ts @@ -44,10 +44,6 @@ vi.mock("next/headers", async () => { }; }); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - beforeEach(async () => { await truncateAllTables(getPrismaClient()); cookieJar.clear(); diff --git a/tests/integration/measurements-batch-perf.test.ts b/tests/integration/measurements-batch-perf.test.ts index 900a4e4d1..2553f7739 100644 --- a/tests/integration/measurements-batch-perf.test.ts +++ b/tests/integration/measurements-batch-perf.test.ts @@ -43,10 +43,6 @@ vi.mock("next/headers", async () => { }; }); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - const rollupCalls = vi.hoisted(() => ({ count: 0 })); vi.mock("@/lib/rollups/after-measurement-mutation", async () => { const actual = await vi.importActual< diff --git a/tests/integration/measurements-batch-set-insert-golden.test.ts b/tests/integration/measurements-batch-set-insert-golden.test.ts index 1d1b8eaf6..260a2447f 100644 --- a/tests/integration/measurements-batch-set-insert-golden.test.ts +++ b/tests/integration/measurements-batch-set-insert-golden.test.ts @@ -38,10 +38,6 @@ vi.mock("next/headers", async () => { }; }); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - const SET_USER = "golden-set-based"; const RECONCILER_USER = "golden-reconciler"; diff --git a/tests/integration/measurements-batch.test.ts b/tests/integration/measurements-batch.test.ts index 91c1b0295..4e1cab34e 100644 --- a/tests/integration/measurements-batch.test.ts +++ b/tests/integration/measurements-batch.test.ts @@ -41,10 +41,6 @@ vi.mock("next/headers", async () => { }; }); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - beforeEach(async () => { await truncateAllTables(getPrismaClient()); cookieJar.clear(); diff --git a/tests/integration/measurements-day-grouped-paging.test.ts b/tests/integration/measurements-day-grouped-paging.test.ts index 17adde8f9..8ab4fd79a 100644 --- a/tests/integration/measurements-day-grouped-paging.test.ts +++ b/tests/integration/measurements-day-grouped-paging.test.ts @@ -32,10 +32,6 @@ vi.mock("next/headers", async () => { }; }); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - beforeEach(async () => { await truncateAllTables(getPrismaClient()); cookieJar.clear(); diff --git a/tests/integration/measurements-duplicate-conflict.test.ts b/tests/integration/measurements-duplicate-conflict.test.ts index 98425868e..ce12ea7f8 100644 --- a/tests/integration/measurements-duplicate-conflict.test.ts +++ b/tests/integration/measurements-duplicate-conflict.test.ts @@ -51,10 +51,6 @@ vi.mock("next/headers", async () => { }; }); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - let counter = 0; const MEASURED_AT = "2026-03-04T07:30:00.000Z"; diff --git a/tests/integration/measurements-named-sleep-stage.test.ts b/tests/integration/measurements-named-sleep-stage.test.ts index 809206262..c604e749a 100644 --- a/tests/integration/measurements-named-sleep-stage.test.ts +++ b/tests/integration/measurements-named-sleep-stage.test.ts @@ -47,10 +47,6 @@ vi.mock("next/headers", async () => { }; }); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - const { POST } = await import("@/app/api/measurements/route"); const { POST: POST_BATCH } = await import("@/app/api/measurements/batch/route"); diff --git a/tests/integration/measurements-sleep-list.test.ts b/tests/integration/measurements-sleep-list.test.ts index 673347319..c71a34789 100644 --- a/tests/integration/measurements-sleep-list.test.ts +++ b/tests/integration/measurements-sleep-list.test.ts @@ -29,10 +29,6 @@ vi.mock("next/headers", async () => { }; }); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - beforeEach(async () => { await truncateAllTables(getPrismaClient()); cookieJar.clear(); diff --git a/tests/integration/medication-auto-mark-taken.test.ts b/tests/integration/medication-auto-mark-taken.test.ts index 6719dd9c2..8279113f7 100644 --- a/tests/integration/medication-auto-mark-taken.test.ts +++ b/tests/integration/medication-auto-mark-taken.test.ts @@ -39,9 +39,6 @@ vi.mock("next/headers", async () => { })), }; }); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); vi.mock("@/lib/notifications/dispatcher", () => ({ dispatchNotification: vi.fn().mockResolvedValue({ dispatched: true, diff --git a/tests/integration/medication-cadence-worker.test.ts b/tests/integration/medication-cadence-worker.test.ts index f0c6b6600..0f296ef09 100644 --- a/tests/integration/medication-cadence-worker.test.ts +++ b/tests/integration/medication-cadence-worker.test.ts @@ -66,10 +66,6 @@ vi.mock("next/headers", async () => { }; }); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - // Side-effects on the create-intake hot path that the one-shot test // exercises but doesn't care about — keep them inert so the test // stays focused on the schedule-resolution + lifecycle contract. diff --git a/tests/integration/medication-course-end.test.ts b/tests/integration/medication-course-end.test.ts index 714e9e4f8..1e6c9c806 100644 --- a/tests/integration/medication-course-end.test.ts +++ b/tests/integration/medication-course-end.test.ts @@ -42,9 +42,6 @@ vi.mock("next/headers", async () => { })), }; }); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); vi.mock("@/lib/notifications/dispatcher", () => ({ dispatchNotification: vi.fn().mockResolvedValue({ dispatched: true, diff --git a/tests/integration/medication-courses.test.ts b/tests/integration/medication-courses.test.ts index dc9682456..21cdd5c02 100644 --- a/tests/integration/medication-courses.test.ts +++ b/tests/integration/medication-courses.test.ts @@ -45,10 +45,6 @@ vi.mock("next/headers", async () => { }; }); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - beforeEach(async () => { const prisma = getPrismaClient(); await truncateAllTables(prisma); diff --git a/tests/integration/medication-custom-categories.test.ts b/tests/integration/medication-custom-categories.test.ts index 262ea7e75..a711fbb56 100644 --- a/tests/integration/medication-custom-categories.test.ts +++ b/tests/integration/medication-custom-categories.test.ts @@ -39,10 +39,6 @@ vi.mock("next/headers", async () => { }; }); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - async function signIn(userId: string) { const session = await getPrismaClient().session.create({ data: { userId, expiresAt: new Date(Date.now() + 60 * 60 * 1000) }, diff --git a/tests/integration/medication-extra-dose-apple-health.test.ts b/tests/integration/medication-extra-dose-apple-health.test.ts index 4e58ba78d..30ed71fc9 100644 --- a/tests/integration/medication-extra-dose-apple-health.test.ts +++ b/tests/integration/medication-extra-dose-apple-health.test.ts @@ -46,10 +46,6 @@ vi.mock("next/headers", async () => { }; }); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - const TZ = "Europe/Berlin"; const DAY_MS = 24 * 60 * 60 * 1000; const MIN = 60_000; diff --git a/tests/integration/medication-intake-tracking.test.ts b/tests/integration/medication-intake-tracking.test.ts index 68ab45991..7ec5617d3 100644 --- a/tests/integration/medication-intake-tracking.test.ts +++ b/tests/integration/medication-intake-tracking.test.ts @@ -35,9 +35,6 @@ vi.mock("next/headers", async () => { })), }; }); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); vi.mock("@/lib/notifications/dispatcher", () => ({ dispatchNotification: vi.fn().mockResolvedValue({ dispatched: true, diff --git a/tests/integration/medication-put-course-race.test.ts b/tests/integration/medication-put-course-race.test.ts index 5b6410394..7864cff89 100644 --- a/tests/integration/medication-put-course-race.test.ts +++ b/tests/integration/medication-put-course-race.test.ts @@ -40,10 +40,6 @@ vi.mock("next/headers", async () => { }; }); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - // The check the concurrent request outran: it saw no conflict. vi.mock("@/lib/medications/courses", async (importOriginal) => ({ ...(await importOriginal()), diff --git a/tests/integration/medication-rolling-overdue-consumers.test.ts b/tests/integration/medication-rolling-overdue-consumers.test.ts index 2565b58bf..064df492c 100644 --- a/tests/integration/medication-rolling-overdue-consumers.test.ts +++ b/tests/integration/medication-rolling-overdue-consumers.test.ts @@ -28,10 +28,6 @@ const LAST_TAKEN = new Date("2026-07-21T06:00:00.000Z"); const OVERDUE_OCCURRENCE = new Date("2026-07-28T06:00:00.000Z"); const NEXT_OCCURRENCE = new Date("2026-08-04T06:00:00.000Z"); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - beforeEach(async () => { vi.useFakeTimers({ toFake: ["Date"] }); vi.setSystemTime(NOW); diff --git a/tests/integration/medication-write-idempotency.test.ts b/tests/integration/medication-write-idempotency.test.ts index b83a9d138..6c42a9723 100644 --- a/tests/integration/medication-write-idempotency.test.ts +++ b/tests/integration/medication-write-idempotency.test.ts @@ -55,10 +55,6 @@ vi.mock("next/headers", async () => { }; }); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - beforeEach(async () => { await truncateAllTables(getPrismaClient()); cookieJar.clear(); diff --git a/tests/integration/medications-intake-bulk.test.ts b/tests/integration/medications-intake-bulk.test.ts index 886e2dc90..df63bb077 100644 --- a/tests/integration/medications-intake-bulk.test.ts +++ b/tests/integration/medications-intake-bulk.test.ts @@ -38,10 +38,6 @@ vi.mock("next/headers", async () => { }; }); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - let ownedMedId = ""; let foreignMedId = ""; diff --git a/tests/integration/mental-health-wording.test.ts b/tests/integration/mental-health-wording.test.ts index 5414872b9..03fc2a6cc 100644 --- a/tests/integration/mental-health-wording.test.ts +++ b/tests/integration/mental-health-wording.test.ts @@ -28,10 +28,6 @@ import { callRoute } from "../kit/call-route"; import { makeSession, makeUser, type SessionFixture } from "../kit/factories"; import { getPrismaClient, truncateAllTables } from "./setup"; -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - // The reminder satisfy and the rollup tail hand work to pg-boss; the queue is // not what this file is about. vi.mock("@/lib/jobs/boss-instance", () => ({ diff --git a/tests/integration/mfa-login-flow.test.ts b/tests/integration/mfa-login-flow.test.ts index 43e53ccfc..aadf2cbd3 100644 --- a/tests/integration/mfa-login-flow.test.ts +++ b/tests/integration/mfa-login-flow.test.ts @@ -6,7 +6,7 @@ * that the recovery-code burn is durable and one-time, and that the challenge * ticket can be claimed exactly once. This exercises all three end to end. */ -import { beforeAll, beforeEach, describe, expect, it, vi } from "vitest"; +import { beforeAll, beforeEach, describe, expect, it } from "vitest"; import * as OTPAuth from "otpauth"; import { getPrismaClient, truncateAllTables } from "./setup"; @@ -15,10 +15,6 @@ import { getPrismaClient, truncateAllTables } from "./setup"; process.env.API_TOKEN_HMAC_KEY ??= "test-hmac-key-test-hmac-key-test-hmac-key-0123456789"; -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - function codeAt(secretBase32: string, atMs: number): string { const totp = new OTPAuth.TOTP({ issuer: "HealthLog", diff --git a/tests/integration/mood-backup-round-trip.test.ts b/tests/integration/mood-backup-round-trip.test.ts index 7317d44c0..ae20ff812 100644 --- a/tests/integration/mood-backup-round-trip.test.ts +++ b/tests/integration/mood-backup-round-trip.test.ts @@ -53,10 +53,6 @@ vi.mock("next/headers", async () => { }; }); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - vi.mock("@/lib/cache/invalidate", () => ({ invalidateUserData: vi.fn(), })); diff --git a/tests/integration/mood-context-linkage.test.ts b/tests/integration/mood-context-linkage.test.ts index e3230ec3f..eb9645656 100644 --- a/tests/integration/mood-context-linkage.test.ts +++ b/tests/integration/mood-context-linkage.test.ts @@ -41,10 +41,6 @@ vi.mock("next/headers", async () => { }; }); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - beforeEach(async () => { await truncateAllTables(getPrismaClient()); cookieJar.clear(); diff --git a/tests/integration/mood-context.test.ts b/tests/integration/mood-context.test.ts index c5222f1db..42a5e9ae3 100644 --- a/tests/integration/mood-context.test.ts +++ b/tests/integration/mood-context.test.ts @@ -45,10 +45,6 @@ vi.mock("next/headers", async () => { }; }); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - beforeEach(async () => { await truncateAllTables(getPrismaClient()); cookieJar.clear(); diff --git a/tests/integration/mood-entries-bulk.test.ts b/tests/integration/mood-entries-bulk.test.ts index 50818240e..b0048e416 100644 --- a/tests/integration/mood-entries-bulk.test.ts +++ b/tests/integration/mood-entries-bulk.test.ts @@ -35,10 +35,6 @@ vi.mock("next/headers", async () => { }; }); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - beforeEach(async () => { await truncateAllTables(getPrismaClient()); cookieJar.clear(); diff --git a/tests/integration/mood-entries-external-id.test.ts b/tests/integration/mood-entries-external-id.test.ts index 6945419ab..223648ee7 100644 --- a/tests/integration/mood-entries-external-id.test.ts +++ b/tests/integration/mood-entries-external-id.test.ts @@ -45,10 +45,6 @@ vi.mock("next/headers", async () => { }; }); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - async function createUserSession(userId: string, username: string) { await getPrismaClient().user.create({ data: { diff --git a/tests/integration/mood-entries-note-column.test.ts b/tests/integration/mood-entries-note-column.test.ts index 3fb786d07..543513f7b 100644 --- a/tests/integration/mood-entries-note-column.test.ts +++ b/tests/integration/mood-entries-note-column.test.ts @@ -40,10 +40,6 @@ vi.mock("next/headers", async () => { }; }); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - beforeEach(async () => { await truncateAllTables(getPrismaClient()); cookieJar.clear(); diff --git a/tests/integration/mood-insights-crosstab.test.ts b/tests/integration/mood-insights-crosstab.test.ts index 54428f853..3b91e8b50 100644 --- a/tests/integration/mood-insights-crosstab.test.ts +++ b/tests/integration/mood-insights-crosstab.test.ts @@ -8,15 +8,11 @@ * Exercises the widened measurement `type: { in: [...] }` filter and the * structured-tag join end-to-end against Postgres. */ -import { beforeEach, describe, expect, it, vi } from "vitest"; +import { beforeEach, describe, expect, it } from "vitest"; import { getPrismaClient, truncateAllTables } from "./setup"; import { fetchMoodAggregates } from "@/lib/insights/mood-aggregates"; -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - const TEST_USER_ID = "user-crosstab"; const dayMs = 24 * 60 * 60 * 1000; const NOW = new Date("2026-06-01T12:00:00.000Z"); diff --git a/tests/integration/mood-prognosis-ladder.test.ts b/tests/integration/mood-prognosis-ladder.test.ts index 294941871..7123f3bb4 100644 --- a/tests/integration/mood-prognosis-ladder.test.ts +++ b/tests/integration/mood-prognosis-ladder.test.ts @@ -41,10 +41,6 @@ vi.mock("next/headers", async () => { }; }); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - /** Fixed clock: a ladder test that slides with the calendar is a date bomb. */ const FIXED_NOW = new Date("2026-08-08T09:00:00.000Z"); /** diff --git a/tests/integration/mood-tag-groups.test.ts b/tests/integration/mood-tag-groups.test.ts index 58b1081dc..418476ee3 100644 --- a/tests/integration/mood-tag-groups.test.ts +++ b/tests/integration/mood-tag-groups.test.ts @@ -46,10 +46,6 @@ vi.mock("next/headers", async () => { }; }); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - async function createUserSession(userId: string, username: string) { await getPrismaClient().user.create({ data: { diff --git a/tests/integration/mood-writers-agree.test.ts b/tests/integration/mood-writers-agree.test.ts index 5978d7311..603e0a43b 100644 --- a/tests/integration/mood-writers-agree.test.ts +++ b/tests/integration/mood-writers-agree.test.ts @@ -47,10 +47,6 @@ vi.mock("next/headers", async () => { }; }); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - async function createUserSession() { await getPrismaClient().user.create({ data: { diff --git a/tests/integration/notification-action-mood.test.ts b/tests/integration/notification-action-mood.test.ts index 59fd707f7..cb7584409 100644 --- a/tests/integration/notification-action-mood.test.ts +++ b/tests/integration/notification-action-mood.test.ts @@ -14,10 +14,6 @@ import { getPrismaClient, truncateAllTables } from "./setup"; const USER = "user-notification-action"; -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - function call(token: string) { return import("@/app/api/notifications/action/[token]/route").then( ({ POST }) => diff --git a/tests/integration/notification-event-defaults.test.ts b/tests/integration/notification-event-defaults.test.ts index fee0d689b..588a4700b 100644 --- a/tests/integration/notification-event-defaults.test.ts +++ b/tests/integration/notification-event-defaults.test.ts @@ -44,10 +44,6 @@ vi.mock("next/headers", async () => { }; }); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - const USERNAME = "event-defaults"; async function seedAccount(moodReminderEnabled: boolean): Promise { diff --git a/tests/integration/notification-global-channel-switch.test.ts b/tests/integration/notification-global-channel-switch.test.ts index ef66389b1..7216b486b 100644 --- a/tests/integration/notification-global-channel-switch.test.ts +++ b/tests/integration/notification-global-channel-switch.test.ts @@ -18,10 +18,6 @@ vi.mock("@/lib/notifications/senders/ntfy", () => ({ sendViaNtfy: (...args: unknown[]) => ntfySendMock(...args), })); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - import { getPrismaClient, truncateAllTables } from "./setup"; const TEST_USER_ID = "user-global-channel-switch"; diff --git a/tests/integration/nutrients-batch.test.ts b/tests/integration/nutrients-batch.test.ts index 75400f8c0..8587ad74a 100644 --- a/tests/integration/nutrients-batch.test.ts +++ b/tests/integration/nutrients-batch.test.ts @@ -40,10 +40,6 @@ vi.mock("next/headers", async () => { }; }); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - async function signIn(userId: string): Promise { const session = await getPrismaClient().session.create({ data: { diff --git a/tests/integration/oauth-callback-single-use.test.ts b/tests/integration/oauth-callback-single-use.test.ts index 6f71de311..150121b3a 100644 --- a/tests/integration/oauth-callback-single-use.test.ts +++ b/tests/integration/oauth-callback-single-use.test.ts @@ -44,10 +44,6 @@ vi.mock("next/headers", async () => { }; }); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - const USER = "user-oauth-single-use"; const OURA_TOKEN_URL = "https://moi.ouraring.com/oauth/v2/ext/oauth-token"; const OURA_ISS = "https://moi.ouraring.com/oauth/v2/ext/oauth-anonymous"; diff --git a/tests/integration/offhost-purge-on-deletion.test.ts b/tests/integration/offhost-purge-on-deletion.test.ts index 4e141292b..8ca5af4ca 100644 --- a/tests/integration/offhost-purge-on-deletion.test.ts +++ b/tests/integration/offhost-purge-on-deletion.test.ts @@ -64,10 +64,6 @@ vi.mock("next/headers", async () => { }; }); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - beforeEach(async () => { await truncateAllTables(getPrismaClient()); cookieJar.clear(); diff --git a/tests/integration/oidc-pending-link.test.ts b/tests/integration/oidc-pending-link.test.ts index 4bc34c225..d98afa310 100644 --- a/tests/integration/oidc-pending-link.test.ts +++ b/tests/integration/oidc-pending-link.test.ts @@ -34,10 +34,6 @@ vi.mock("next/headers", async () => { }; }); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - const { hashPassword } = await import("@/lib/auth/password"); const { encrypt } = await import("@/lib/crypto"); diff --git a/tests/integration/oidc-reproof.test.ts b/tests/integration/oidc-reproof.test.ts index cc5f728dc..d59622006 100644 --- a/tests/integration/oidc-reproof.test.ts +++ b/tests/integration/oidc-reproof.test.ts @@ -36,10 +36,6 @@ vi.mock("next/headers", async () => { }; }); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - const ISSUER = "https://idp.example.test"; const METADATA = { issuer: ISSUER, diff --git a/tests/integration/onboarding-needs.test.ts b/tests/integration/onboarding-needs.test.ts index b45732e56..49b54f12d 100644 --- a/tests/integration/onboarding-needs.test.ts +++ b/tests/integration/onboarding-needs.test.ts @@ -47,10 +47,6 @@ vi.mock("next/headers", async () => { }; }); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - import { acceptGrant, inviteGrant } from "@/lib/sharing/grants"; import { DEFAULT_DASHBOARD_LAYOUT, diff --git a/tests/integration/openapi-get-contract.test.ts b/tests/integration/openapi-get-contract.test.ts index f21ed4cbc..477749079 100644 --- a/tests/integration/openapi-get-contract.test.ts +++ b/tests/integration/openapi-get-contract.test.ts @@ -77,10 +77,6 @@ vi.mock("@/lib/jobs/worker-status", async (importOriginal) => { }; }); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - // No request leaves the process. An operation that needs the network to // answer belongs in NOT_CALLED with that reason; one that merely tries and // copes with the failure is checked on the path it takes when it cannot. diff --git a/tests/integration/openapi-response-shape.test.ts b/tests/integration/openapi-response-shape.test.ts index 59c640c99..40a39a6c3 100644 --- a/tests/integration/openapi-response-shape.test.ts +++ b/tests/integration/openapi-response-shape.test.ts @@ -59,10 +59,6 @@ vi.mock("next/headers", async () => { }; }); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - beforeEach(async () => { const prisma = getPrismaClient(); await truncateAllTables(prisma); diff --git a/tests/integration/oura-backfill.test.ts b/tests/integration/oura-backfill.test.ts index 8dd616149..1a6337d61 100644 --- a/tests/integration/oura-backfill.test.ts +++ b/tests/integration/oura-backfill.test.ts @@ -51,10 +51,6 @@ const fake = vi.hoisted(() => ({ sends: [] as Array<{ queue: string; payload: unknown; options: unknown }>, })); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - vi.mock("@/lib/jobs/boss-instance", () => ({ getGlobalBoss: () => ({ send: async (queue: string, payload: unknown, options: unknown) => { diff --git a/tests/integration/partial-unique-live-rows.test.ts b/tests/integration/partial-unique-live-rows.test.ts index 109a0c674..238b51a20 100644 --- a/tests/integration/partial-unique-live-rows.test.ts +++ b/tests/integration/partial-unique-live-rows.test.ts @@ -20,7 +20,7 @@ * Postgres cannot arbiter against a partial unique). See migration 0121's * header for the full rationale. */ -import { beforeEach, describe, expect, it, vi } from "vitest"; +import { beforeEach, describe, expect, it } from "vitest"; process.env.ENCRYPTION_KEY ??= "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"; @@ -29,10 +29,6 @@ import { applyCanonicalSlotWrite } from "@/lib/medications/scheduling/slot-upser import { getPrismaClient, truncateAllTables } from "./setup"; -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - beforeEach(async () => { await truncateAllTables(getPrismaClient()); }); diff --git a/tests/integration/passkey-register.test.ts b/tests/integration/passkey-register.test.ts index eeb054816..2566b9323 100644 --- a/tests/integration/passkey-register.test.ts +++ b/tests/integration/passkey-register.test.ts @@ -42,10 +42,6 @@ vi.mock("next/headers", async () => { }; }); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - vi.mock("@/lib/auth/passkey", async () => { const actual = await vi.importActual( diff --git a/tests/integration/pr-detection-cumulative-paged.test.ts b/tests/integration/pr-detection-cumulative-paged.test.ts index 9bfc38159..b28910248 100644 --- a/tests/integration/pr-detection-cumulative-paged.test.ts +++ b/tests/integration/pr-detection-cumulative-paged.test.ts @@ -12,14 +12,10 @@ * best day sits in the middle of the history, and no read of the history is * unbounded. */ -import { beforeEach, describe, expect, it, vi } from "vitest"; +import { beforeEach, describe, expect, it } from "vitest"; import { getPrismaClient, truncateAllTables } from "./setup"; -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - const { detectPersonalRecordsForUser } = await import("@/lib/personal-records/pr-detection-worker"); diff --git a/tests/integration/pr-detection-end-to-end.test.ts b/tests/integration/pr-detection-end-to-end.test.ts index 2efb51c63..4f5beab14 100644 --- a/tests/integration/pr-detection-end-to-end.test.ts +++ b/tests/integration/pr-detection-end-to-end.test.ts @@ -18,14 +18,10 @@ * of going through pg-boss so the integration suite stays free of * out-of-process job-queue plumbing. */ -import { beforeEach, describe, expect, it, vi } from "vitest"; +import { beforeEach, describe, expect, it } from "vitest"; import { getPrismaClient, truncateAllTables } from "./setup"; -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - const TEST_USER_ID = "user-pr-detection-e2e"; const { detectPersonalRecordsForUser, PR_DETECTION_WARMUP_THRESHOLD } = diff --git a/tests/integration/practitioner-contact-encryption.test.ts b/tests/integration/practitioner-contact-encryption.test.ts index 82df5cb39..7465e871c 100644 --- a/tests/integration/practitioner-contact-encryption.test.ts +++ b/tests/integration/practitioner-contact-encryption.test.ts @@ -44,10 +44,6 @@ vi.mock("next/headers", async () => { }; }); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - const OWNER_ID = "practitioner-contact-owner"; const PHONE = "+49 30 9876543"; const ADDRESS = "Lindenweg 12, 10115 Berlin"; diff --git a/tests/integration/practitioner-specialty-search.test.ts b/tests/integration/practitioner-specialty-search.test.ts index 5448c0103..1b0e2d996 100644 --- a/tests/integration/practitioner-specialty-search.test.ts +++ b/tests/integration/practitioner-specialty-search.test.ts @@ -34,10 +34,6 @@ vi.mock("next/headers", async () => { }; }); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - const OWNER_ID = "practitioner-search-owner"; function daysFromNow(days: number): Date { diff --git a/tests/integration/profile-display-name.test.ts b/tests/integration/profile-display-name.test.ts index 42c2092ec..f2479812b 100644 --- a/tests/integration/profile-display-name.test.ts +++ b/tests/integration/profile-display-name.test.ts @@ -38,10 +38,6 @@ vi.mock("next/headers", async () => { }; }); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - async function seed(displayName: string | null): Promise { const prisma = getPrismaClient(); const user = await prisma.user.create({ diff --git a/tests/integration/provider-dense-fold.test.ts b/tests/integration/provider-dense-fold.test.ts index d25d0a9f6..b786eda3a 100644 --- a/tests/integration/provider-dense-fold.test.ts +++ b/tests/integration/provider-dense-fold.test.ts @@ -16,7 +16,7 @@ * day, deleted outright, expires the account's delta cursors. An Apple * Health fold expires nothing. */ -import { beforeEach, describe, expect, it, vi } from "vitest"; +import { beforeEach, describe, expect, it } from "vitest"; import { upsertGoogleHealthMeasurements } from "@/lib/google-health/sync-core"; import { runDenseIntradayRetention } from "@/lib/measurements/dense-intraday-retention"; @@ -30,10 +30,6 @@ import { makeUser } from "../kit/factories"; import { getPrismaClient, truncateAllTables } from "./setup"; -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - const prisma = getPrismaClient(); const DAY_MS = 86_400_000; const MIN_MS = 60_000; diff --git a/tests/integration/provider-pause.test.ts b/tests/integration/provider-pause.test.ts index 7926d84ef..5f82db3b1 100644 --- a/tests/integration/provider-pause.test.ts +++ b/tests/integration/provider-pause.test.ts @@ -11,10 +11,6 @@ import { afterEach, beforeEach, describe, expect, it, vi } from "vitest"; import { getPrismaClient, truncateAllTables } from "./setup"; -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - import { HARD_FAILURE_COOLDOWN_MS, PROVIDER_PAUSE_BASE_MS, diff --git a/tests/integration/pulse-day-mean-zones.test.ts b/tests/integration/pulse-day-mean-zones.test.ts index da0bdc286..2157070ac 100644 --- a/tests/integration/pulse-day-mean-zones.test.ts +++ b/tests/integration/pulse-day-mean-zones.test.ts @@ -48,10 +48,6 @@ vi.mock("next/headers", async () => { }; }); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - const prisma = getPrismaClient(); const DAY = 86_400_000; const now = new Date(); diff --git a/tests/integration/pulse-hourly-mean-day.test.ts b/tests/integration/pulse-hourly-mean-day.test.ts index 5d87bbc8a..0cae7b067 100644 --- a/tests/integration/pulse-hourly-mean-day.test.ts +++ b/tests/integration/pulse-hourly-mean-day.test.ts @@ -45,10 +45,6 @@ vi.mock("next/headers", async () => { }; }); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - const prisma = getPrismaClient(); const USER = "pulse-hourly-mean"; const DAY = 86_400_000; diff --git a/tests/integration/pulse-window-mean-readers.test.ts b/tests/integration/pulse-window-mean-readers.test.ts index 086adfef8..85819cb9c 100644 --- a/tests/integration/pulse-window-mean-readers.test.ts +++ b/tests/integration/pulse-window-mean-readers.test.ts @@ -46,10 +46,6 @@ vi.mock("next/headers", async () => { }; }); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - // The reads kick off a background rollup refresh; keep it off so the live // user stays on the live path for the whole file. vi.mock("@/lib/rollups/measurement-rollups", async (importOriginal) => { diff --git a/tests/integration/query-budget-hot-routes.test.ts b/tests/integration/query-budget-hot-routes.test.ts index 0a50202d6..6d8a6af4c 100644 --- a/tests/integration/query-budget-hot-routes.test.ts +++ b/tests/integration/query-budget-hot-routes.test.ts @@ -54,10 +54,6 @@ vi.mock("next/headers", async () => { }; }); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - const USER_ID = "user-query-budget"; const DAY_MS = 86_400_000; diff --git a/tests/integration/rate-limit-429-headers.test.ts b/tests/integration/rate-limit-429-headers.test.ts index db4608027..23bb31d3a 100644 --- a/tests/integration/rate-limit-429-headers.test.ts +++ b/tests/integration/rate-limit-429-headers.test.ts @@ -53,10 +53,6 @@ vi.mock("next/headers", async () => { }; }); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - beforeEach(async () => { await truncateAllTables(getPrismaClient()); cookieJar.clear(); diff --git a/tests/integration/recent-proof.test.ts b/tests/integration/recent-proof.test.ts index 1a1325823..0349fc5c3 100644 --- a/tests/integration/recent-proof.test.ts +++ b/tests/integration/recent-proof.test.ts @@ -35,10 +35,6 @@ vi.mock("next/headers", async () => { }; }); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - const USER_ID = "user-recent-proof"; const PASSWORD = "Correct horse battery staple!42"; const HOUR = 60 * 60 * 1000; diff --git a/tests/integration/record-csv-import.test.ts b/tests/integration/record-csv-import.test.ts index de25d0251..e04587f97 100644 --- a/tests/integration/record-csv-import.test.ts +++ b/tests/integration/record-csv-import.test.ts @@ -22,9 +22,6 @@ import { medicationsCsvQuerySchema, } from "@/lib/validations/record-import"; -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); vi.mock("@/lib/jobs/boss-instance", () => ({ getGlobalBoss: vi.fn(() => null), })); diff --git a/tests/integration/record-search.test.ts b/tests/integration/record-search.test.ts index f3f915254..a1e5e3f03 100644 --- a/tests/integration/record-search.test.ts +++ b/tests/integration/record-search.test.ts @@ -49,10 +49,6 @@ vi.mock("next/headers", async () => { }; }); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - let counter = 0; async function makeUser(label: string, modules: Record = {}) { diff --git a/tests/integration/record-session-fence-idempotency.test.ts b/tests/integration/record-session-fence-idempotency.test.ts index c0691cb9a..1071018b7 100644 --- a/tests/integration/record-session-fence-idempotency.test.ts +++ b/tests/integration/record-session-fence-idempotency.test.ts @@ -51,10 +51,6 @@ vi.mock("next/headers", async () => { }; }); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - import { apiHandler, requireRecordAuth } from "@/lib/api-handler"; import { prisma } from "@/lib/db"; import { withIdempotency } from "@/lib/idempotency"; diff --git a/tests/integration/record-session-fence.test.ts b/tests/integration/record-session-fence.test.ts index 881877328..7a5561a10 100644 --- a/tests/integration/record-session-fence.test.ts +++ b/tests/integration/record-session-fence.test.ts @@ -61,10 +61,6 @@ vi.mock("next/headers", async () => { }; }); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - import { apiHandler, requireRecordAuth } from "@/lib/api-handler"; import { hashToken } from "@/lib/auth/hmac"; import { prisma } from "@/lib/db"; diff --git a/tests/integration/record-settings-integrations-health.test.ts b/tests/integration/record-settings-integrations-health.test.ts index bbd8a61c6..2ceace31b 100644 --- a/tests/integration/record-settings-integrations-health.test.ts +++ b/tests/integration/record-settings-integrations-health.test.ts @@ -30,10 +30,6 @@ vi.mock("next/headers", async () => { }; }); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - interface ManagedIntegration { integration: string; state: string; diff --git a/tests/integration/recovery-kit.test.ts b/tests/integration/recovery-kit.test.ts index d100f1d4e..8e939fb8b 100644 --- a/tests/integration/recovery-kit.test.ts +++ b/tests/integration/recovery-kit.test.ts @@ -44,10 +44,6 @@ vi.mock("next/headers", async () => { }; }); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - import { _resetCryptoCacheForTests, getKeyFingerprint } from "@/lib/crypto"; import { offhostKeyId } from "@/lib/jobs/offhost-key"; import type { RecoveryKit } from "@/lib/recovery/kit-rules"; diff --git a/tests/integration/recovery-readiness-dump-retention.test.ts b/tests/integration/recovery-readiness-dump-retention.test.ts index b2f0eeb3b..9fedd424a 100644 --- a/tests/integration/recovery-readiness-dump-retention.test.ts +++ b/tests/integration/recovery-readiness-dump-retention.test.ts @@ -19,10 +19,6 @@ vi.mock("@/lib/jobs/offhost-backup", async (importOriginal) => ({ probeOffhostLifecycle: () => probe(), })); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - import { getPrismaClient, truncateAllTables } from "./setup"; const NOW = new Date(); diff --git a/tests/integration/recovery-readiness-notify.test.ts b/tests/integration/recovery-readiness-notify.test.ts index 863f2220b..317adf29b 100644 --- a/tests/integration/recovery-readiness-notify.test.ts +++ b/tests/integration/recovery-readiness-notify.test.ts @@ -55,10 +55,6 @@ vi.mock("@/lib/recovery/database-dump-health", () => ({ readDatabaseBackupHealth: async () => null, })); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - import { getPrismaClient, truncateAllTables } from "./setup"; const ADMIN_ID = "user-readiness-admin"; diff --git a/tests/integration/relation-links-portable-restore.test.ts b/tests/integration/relation-links-portable-restore.test.ts index 308369684..0c3e95438 100644 --- a/tests/integration/relation-links-portable-restore.test.ts +++ b/tests/integration/relation-links-portable-restore.test.ts @@ -51,10 +51,6 @@ vi.mock("next/headers", async () => { }; }); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - vi.mock("@/lib/cache/invalidate", () => ({ invalidateUserData: vi.fn(), })); diff --git a/tests/integration/request-clock-windows-session-tz.test.ts b/tests/integration/request-clock-windows-session-tz.test.ts index 3b0d9aea7..7e2a1f2a1 100644 --- a/tests/integration/request-clock-windows-session-tz.test.ts +++ b/tests/integration/request-clock-windows-session-tz.test.ts @@ -12,10 +12,6 @@ vi.mock("@/lib/db-session", async (importOriginal) => { return { ...actual, TIME_ZONE_OPTION: "-c TimeZone=Pacific/Auckland" }; }); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - // The read path's fire-and-forget refresh would build the rollup tier behind // the live case; the cases build it themselves when they mean to. vi.mock("@/lib/rollups/measurement-rollups", async (importOriginal) => ({ diff --git a/tests/integration/rest-mode-chronic.test.ts b/tests/integration/rest-mode-chronic.test.ts index 201d458fc..413cd9d84 100644 --- a/tests/integration/rest-mode-chronic.test.ts +++ b/tests/integration/rest-mode-chronic.test.ts @@ -10,7 +10,7 @@ * digest's Day N, and the achievements streak freeze, which runs its own * episode query. */ -import { beforeEach, describe, expect, it, vi } from "vitest"; +import { beforeEach, describe, expect, it } from "vitest"; import type { Prisma } from "@/generated/prisma/client"; import { __resetAllCachesForTests } from "@/lib/cache/server-cache"; @@ -21,10 +21,6 @@ import type { ModuleKey } from "@/lib/modules/registry"; import { getPrismaClient, truncateAllTables } from "./setup"; -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - const USER = "rest-mode-chronic"; const DAY = 24 * 60 * 60 * 1000; diff --git a/tests/integration/restore-consolidation-deadlock.test.ts b/tests/integration/restore-consolidation-deadlock.test.ts index 82b6b991b..0374db4c0 100644 --- a/tests/integration/restore-consolidation-deadlock.test.ts +++ b/tests/integration/restore-consolidation-deadlock.test.ts @@ -28,23 +28,11 @@ * consolidation's day transaction and the first test fails with the * consolidation rejected on `40P01`. */ -import { - afterAll, - afterEach, - beforeEach, - describe, - expect, - it, - vi, -} from "vitest"; +import { afterAll, afterEach, beforeEach, describe, expect, it } from "vitest"; import { getPrismaClient, truncateAllTables } from "./setup"; import { acceptingBoss } from "./restore-job-driver"; -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - const OWNER = "restore-deadlock-owner"; const DAY = "2026-01-10"; const TOTAL_ID = "deadlock-total"; diff --git a/tests/integration/rollup-concurrent-recompute.test.ts b/tests/integration/rollup-concurrent-recompute.test.ts index d9ea3d6b3..c98f3b890 100644 --- a/tests/integration/rollup-concurrent-recompute.test.ts +++ b/tests/integration/rollup-concurrent-recompute.test.ts @@ -40,10 +40,6 @@ import { recomputeUserRollups, } from "@/lib/rollups/measurement-rollups"; -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - // No pg-boss in the integration harness — the WEEK/MONTH/YEAR enqueue // inside the write hook is a silent no-op when no boss is attached. vi.mock("@/lib/jobs/boss-instance", () => ({ diff --git a/tests/integration/rollup-coverage-probe.test.ts b/tests/integration/rollup-coverage-probe.test.ts index 05f99cf44..936d57b63 100644 --- a/tests/integration/rollup-coverage-probe.test.ts +++ b/tests/integration/rollup-coverage-probe.test.ts @@ -14,9 +14,6 @@ import { getPrismaClient, truncateAllTables } from "./setup"; import { probeRollupCoverage } from "@/lib/rollups/measurement-coverage"; import type { MeasurementType } from "@/generated/prisma/client"; -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); vi.mock("@/lib/jobs/boss-instance", () => ({ getGlobalBoss: vi.fn(() => null), })); diff --git a/tests/integration/rollup-keyed-refold-session-tz.test.ts b/tests/integration/rollup-keyed-refold-session-tz.test.ts index 30e88bb3c..45cfc04b8 100644 --- a/tests/integration/rollup-keyed-refold-session-tz.test.ts +++ b/tests/integration/rollup-keyed-refold-session-tz.test.ts @@ -15,10 +15,6 @@ vi.mock("@/lib/db-session", async (importOriginal) => { return { ...actual, TIME_ZONE_OPTION: "-c TimeZone=Pacific/Auckland" }; }); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - import { getPrismaClient, truncateAllTables } from "./setup"; import { prisma } from "@/lib/db"; import { diff --git a/tests/integration/rollup-per-day-canonical.test.ts b/tests/integration/rollup-per-day-canonical.test.ts index c24606ade..b0278bd65 100644 --- a/tests/integration/rollup-per-day-canonical.test.ts +++ b/tests/integration/rollup-per-day-canonical.test.ts @@ -25,9 +25,6 @@ import { readAllTimeExtremes } from "@/lib/insights/feature-blocks"; import { computeSummariesSlice } from "@/lib/analytics/summaries-slice"; import type { MeasurementType } from "@/generated/prisma/client"; -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); vi.mock("@/lib/jobs/boss-instance", () => ({ getGlobalBoss: vi.fn(() => null), })); diff --git a/tests/integration/rollup-regression-parity.integration.test.ts b/tests/integration/rollup-regression-parity.integration.test.ts index 27a105734..71bf9ae43 100644 --- a/tests/integration/rollup-regression-parity.integration.test.ts +++ b/tests/integration/rollup-regression-parity.integration.test.ts @@ -43,10 +43,6 @@ import { type RegressionAccumulators, } from "@/lib/rollups/measurement-read"; -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - vi.mock("@/lib/jobs/boss-instance", () => ({ getGlobalBoss: vi.fn(() => null), })); diff --git a/tests/integration/score-history.test.ts b/tests/integration/score-history.test.ts index 7049a3594..433fb2697 100644 --- a/tests/integration/score-history.test.ts +++ b/tests/integration/score-history.test.ts @@ -37,10 +37,6 @@ vi.mock("next/headers", async () => { }; }); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - type Handler = ( request: NextRequest, // eslint-disable-next-line @typescript-eslint/no-explicit-any diff --git a/tests/integration/second-factor-ends-other-sessions.test.ts b/tests/integration/second-factor-ends-other-sessions.test.ts index d0afaeab0..4007ffcc0 100644 --- a/tests/integration/second-factor-ends-other-sessions.test.ts +++ b/tests/integration/second-factor-ends-other-sessions.test.ts @@ -31,10 +31,6 @@ vi.mock("next/headers", async () => { }; }); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - const USER_ID = "user-second-factor"; const HOUR = 60 * 60 * 1000; diff --git a/tests/integration/series-source-ladder.test.ts b/tests/integration/series-source-ladder.test.ts index 440d9fc71..566b3b109 100644 --- a/tests/integration/series-source-ladder.test.ts +++ b/tests/integration/series-source-ladder.test.ts @@ -46,10 +46,6 @@ vi.mock("next/headers", async () => { }; }); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - const prisma = getPrismaClient(); const TZ = "Europe/Berlin"; const DUAL = "ladder-dual"; diff --git a/tests/integration/server-cache-routes.test.ts b/tests/integration/server-cache-routes.test.ts index 64ad40cf2..53349ebb7 100644 --- a/tests/integration/server-cache-routes.test.ts +++ b/tests/integration/server-cache-routes.test.ts @@ -50,10 +50,6 @@ vi.mock("next/headers", async () => { }; }); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - beforeEach(async () => { await truncateAllTables(getPrismaClient()); cookieJar.clear(); diff --git a/tests/integration/settings-account-delete.test.ts b/tests/integration/settings-account-delete.test.ts index 2ba87b9cd..e33bf1d7f 100644 --- a/tests/integration/settings-account-delete.test.ts +++ b/tests/integration/settings-account-delete.test.ts @@ -41,10 +41,6 @@ vi.mock("next/headers", async () => { }; }); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - beforeEach(async () => { await truncateAllTables(getPrismaClient()); cookieJar.clear(); diff --git a/tests/integration/settings-data-wipe.test.ts b/tests/integration/settings-data-wipe.test.ts index eda115f08..59a391330 100644 --- a/tests/integration/settings-data-wipe.test.ts +++ b/tests/integration/settings-data-wipe.test.ts @@ -65,10 +65,6 @@ vi.mock("next/headers", async () => { }; }); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - async function managedProfileLockIsHeld( prisma: PrismaClient, profileId: string, diff --git a/tests/integration/settings-erasure-bearer-step-up.test.ts b/tests/integration/settings-erasure-bearer-step-up.test.ts index 9ecabde82..3a04a9f2e 100644 --- a/tests/integration/settings-erasure-bearer-step-up.test.ts +++ b/tests/integration/settings-erasure-bearer-step-up.test.ts @@ -47,10 +47,6 @@ vi.mock("next/headers", async () => { }; }); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - beforeEach(async () => { await truncateAllTables(getPrismaClient()); cookieJar.clear(); diff --git a/tests/integration/settings-prefs-routes.test.ts b/tests/integration/settings-prefs-routes.test.ts index 2a18cdf04..b0b91739d 100644 --- a/tests/integration/settings-prefs-routes.test.ts +++ b/tests/integration/settings-prefs-routes.test.ts @@ -35,10 +35,6 @@ vi.mock("next/headers", async () => { }; }); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - beforeEach(async () => { await truncateAllTables(getPrismaClient()); cookieJar.clear(); diff --git a/tests/integration/share-link-documents.test.ts b/tests/integration/share-link-documents.test.ts index c2dfc0097..0d7c3861b 100644 --- a/tests/integration/share-link-documents.test.ts +++ b/tests/integration/share-link-documents.test.ts @@ -42,10 +42,6 @@ vi.mock("next/headers", async () => { }; }); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - const PDF_SMALL = Buffer.from("%PDF-1.7\n1 0 obj\n<<>>\nendobj\n%%EOF\n"); async function seedVaultUser(username: string) { diff --git a/tests/integration/sharing-account-access.test.ts b/tests/integration/sharing-account-access.test.ts index 204e2e4de..d02ec5aa3 100644 --- a/tests/integration/sharing-account-access.test.ts +++ b/tests/integration/sharing-account-access.test.ts @@ -36,10 +36,6 @@ vi.mock("next/headers", async () => { }; }); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - import { ACCOUNT_SELECTOR_HEADER } from "@/lib/api-handler"; import { hashToken } from "@/lib/auth/hmac"; diff --git a/tests/integration/sharing-audit-actor.test.ts b/tests/integration/sharing-audit-actor.test.ts index 57874c92f..1d789e94a 100644 --- a/tests/integration/sharing-audit-actor.test.ts +++ b/tests/integration/sharing-audit-actor.test.ts @@ -43,10 +43,6 @@ vi.mock("next/headers", async () => { }; }); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - import { apiHandler, requireRecordAuth } from "@/lib/api-handler"; import { auditLog, DELEGATED_ACCESS_ACTION } from "@/lib/auth/audit"; import { acceptGrant, inviteGrant } from "@/lib/sharing/grants"; diff --git a/tests/integration/sharing-delegable-routes.test.ts b/tests/integration/sharing-delegable-routes.test.ts index de4647e82..9a277462d 100644 --- a/tests/integration/sharing-delegable-routes.test.ts +++ b/tests/integration/sharing-delegable-routes.test.ts @@ -53,10 +53,6 @@ vi.mock("next/headers", async () => { }; }); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - let counter = 0; async function makeUser(label: string) { diff --git a/tests/integration/sharing-delegable-writes.test.ts b/tests/integration/sharing-delegable-writes.test.ts index 5d698aade..76ddb68b3 100644 --- a/tests/integration/sharing-delegable-writes.test.ts +++ b/tests/integration/sharing-delegable-writes.test.ts @@ -62,10 +62,6 @@ vi.mock("next/headers", async () => { }; }); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - /** * The one collaborator this file stubs, and only at the seam it is testing. * diff --git a/tests/integration/sharing-front-door.test.ts b/tests/integration/sharing-front-door.test.ts index 16f1a0d28..de425efd1 100644 --- a/tests/integration/sharing-front-door.test.ts +++ b/tests/integration/sharing-front-door.test.ts @@ -56,10 +56,6 @@ vi.mock("next/headers", async () => { }; }); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - let counter = 0; async function makeUser(label: string) { diff --git a/tests/integration/sharing-idempotency-revocation.test.ts b/tests/integration/sharing-idempotency-revocation.test.ts index b944ae5bc..f8f120676 100644 --- a/tests/integration/sharing-idempotency-revocation.test.ts +++ b/tests/integration/sharing-idempotency-revocation.test.ts @@ -33,10 +33,6 @@ vi.mock("next/headers", async () => { }; }); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - import { ACCOUNT_SELECTOR_HEADER, apiHandler, diff --git a/tests/integration/sharing-lifecycle.test.ts b/tests/integration/sharing-lifecycle.test.ts index c9a1cd724..895acee73 100644 --- a/tests/integration/sharing-lifecycle.test.ts +++ b/tests/integration/sharing-lifecycle.test.ts @@ -44,10 +44,6 @@ vi.mock("next/headers", async () => { }; }); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - import { apiHandler, requireRecordAuth } from "@/lib/api-handler"; import { hashToken } from "@/lib/auth/hmac"; import { prisma } from "@/lib/db"; diff --git a/tests/integration/sharing-manage-handler-matrix.test.ts b/tests/integration/sharing-manage-handler-matrix.test.ts index abc6f0f37..247513c75 100644 --- a/tests/integration/sharing-manage-handler-matrix.test.ts +++ b/tests/integration/sharing-manage-handler-matrix.test.ts @@ -66,10 +66,6 @@ vi.mock("next/headers", async () => { }; }); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - // Import admissions have a durable database effect plus an asynchronous queue // hand-off. Keep the hand-off deterministic here so each route test can prove // the persisted job and actor audit without requiring a running worker. diff --git a/tests/integration/sharing-provider-origin.test.ts b/tests/integration/sharing-provider-origin.test.ts index d433804e9..b8c2503e7 100644 --- a/tests/integration/sharing-provider-origin.test.ts +++ b/tests/integration/sharing-provider-origin.test.ts @@ -33,10 +33,6 @@ vi.mock("@/lib/jobs/boss-instance", () => ({ getGlobalBoss: vi.fn(() => ({ send })), })); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - import { ACCOUNT_SELECTOR_HEADER, apiHandler, diff --git a/tests/integration/sharing-scope-fence.test.ts b/tests/integration/sharing-scope-fence.test.ts index f8d88f3e8..6ec2dd6a3 100644 --- a/tests/integration/sharing-scope-fence.test.ts +++ b/tests/integration/sharing-scope-fence.test.ts @@ -57,10 +57,6 @@ vi.mock("next/headers", async () => { }; }); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - let counter = 0; async function makeUser(label: string) { diff --git a/tests/integration/sleep-entry-hours-round-trip.test.ts b/tests/integration/sleep-entry-hours-round-trip.test.ts index 9389eb742..6ea00020e 100644 --- a/tests/integration/sleep-entry-hours-round-trip.test.ts +++ b/tests/integration/sleep-entry-hours-round-trip.test.ts @@ -46,10 +46,6 @@ vi.mock("next/headers", async () => { }; }); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - let counter = 0; async function makeUser() { diff --git a/tests/integration/sleep-night-sql-parity.test.ts b/tests/integration/sleep-night-sql-parity.test.ts index b6a11b0d7..c35ea37e4 100644 --- a/tests/integration/sleep-night-sql-parity.test.ts +++ b/tests/integration/sleep-night-sql-parity.test.ts @@ -29,10 +29,6 @@ vi.mock("next/headers", async () => { }; }); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - beforeEach(async () => { await truncateAllTables(getPrismaClient()); cookieJar.clear(); diff --git a/tests/integration/soft-delete-copy-parity.test.ts b/tests/integration/soft-delete-copy-parity.test.ts index 052cc1c63..cff137e12 100644 --- a/tests/integration/soft-delete-copy-parity.test.ts +++ b/tests/integration/soft-delete-copy-parity.test.ts @@ -46,10 +46,6 @@ vi.mock("next/headers", async () => { }; }); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - async function signIn(username: string): Promise { const prisma = getPrismaClient(); const user = await prisma.user.create({ diff --git a/tests/integration/soft-delete-purge.test.ts b/tests/integration/soft-delete-purge.test.ts index d84cc7b01..3b2db4433 100644 --- a/tests/integration/soft-delete-purge.test.ts +++ b/tests/integration/soft-delete-purge.test.ts @@ -9,7 +9,7 @@ * it; a purged visit cascades its links; a start folded into a live cycle * stays; the coach facts keep their longer horizon. */ -import { beforeEach, describe, expect, it, vi } from "vitest"; +import { beforeEach, describe, expect, it } from "vitest"; import { TOMBSTONE_RETENTION_DAYS } from "@/lib/auth/native-client"; import { @@ -20,10 +20,6 @@ import { import { getPrismaClient, truncateAllTables } from "./setup"; -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - const USER = "soft-delete-purge-user"; const NOW = new Date("2026-10-20T03:42:00.000Z"); const DAY = 86_400_000; diff --git a/tests/integration/source-aware-rollups.integration.test.ts b/tests/integration/source-aware-rollups.integration.test.ts index f180dab39..5bceaeab8 100644 --- a/tests/integration/source-aware-rollups.integration.test.ts +++ b/tests/integration/source-aware-rollups.integration.test.ts @@ -37,10 +37,6 @@ import { readRollupBuckets, } from "@/lib/rollups/measurement-rollups"; -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - // `recomputeBucketsForMeasurement` enqueues WEEK/MONTH/YEAR jobs via pg-boss; // the DAY-only `recomputeUserRollups` calls here never touch the queue, but the // sibling rollups test mocks the boss instance and the integration suite runs diff --git a/tests/integration/source-ladder-new-sources.test.ts b/tests/integration/source-ladder-new-sources.test.ts index 963ca9d00..406b3dbaf 100644 --- a/tests/integration/source-ladder-new-sources.test.ts +++ b/tests/integration/source-ladder-new-sources.test.ts @@ -9,7 +9,7 @@ * Health, and a day between two sources that were on the ladder before * resolves exactly as it did. */ -import { beforeAll, describe, expect, it, vi } from "vitest"; +import { beforeAll, describe, expect, it } from "vitest"; import { getPrismaClient, truncateAllTables } from "./setup"; import type { @@ -22,10 +22,6 @@ import { } from "@/lib/analytics/source-rank-sql"; import { boundInstantSql } from "@/lib/analytics/request-clock-sql"; -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - const prisma = getPrismaClient(); const USER = "ladder-new-sources"; const DAY = 86_400_000; diff --git a/tests/integration/source-priority-two-axis.test.ts b/tests/integration/source-priority-two-axis.test.ts index aa10d6c63..baa194bc9 100644 --- a/tests/integration/source-priority-two-axis.test.ts +++ b/tests/integration/source-priority-two-axis.test.ts @@ -64,10 +64,6 @@ vi.mock("next/headers", async () => { }; }); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - beforeEach(async () => { await truncateAllTables(getPrismaClient()); cookieJar.clear(); diff --git a/tests/integration/source-provenance.test.ts b/tests/integration/source-provenance.test.ts index 14b04ae3c..5bb8dd767 100644 --- a/tests/integration/source-provenance.test.ts +++ b/tests/integration/source-provenance.test.ts @@ -8,7 +8,7 @@ * day values count asleep stages only, and the comparison lines the two * sources up per day. */ -import { beforeAll, describe, expect, it, vi } from "vitest"; +import { beforeAll, describe, expect, it } from "vitest"; import { getPrismaClient, truncateAllTables } from "./setup"; import { @@ -22,10 +22,6 @@ import { } from "@/lib/provenance/source-provenance"; import type { Prisma } from "@/generated/prisma/client"; -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - const prisma = getPrismaClient(); const USER = "provenance-user"; const DAY = 86_400_000; diff --git a/tests/integration/step-up-elevation.test.ts b/tests/integration/step-up-elevation.test.ts index 7e6294853..aba5a7901 100644 --- a/tests/integration/step-up-elevation.test.ts +++ b/tests/integration/step-up-elevation.test.ts @@ -51,10 +51,6 @@ vi.mock("next/headers", async () => { }; }); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - beforeEach(async () => { await truncateAllTables(getPrismaClient()); cookieJar.clear(); diff --git a/tests/integration/supplement-nutrients.test.ts b/tests/integration/supplement-nutrients.test.ts index 75f698b0e..d746fe44b 100644 --- a/tests/integration/supplement-nutrients.test.ts +++ b/tests/integration/supplement-nutrients.test.ts @@ -49,9 +49,6 @@ vi.mock("next/headers", async () => { })), }; }); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); vi.mock("@/lib/notifications/medication-intake-sync", () => ({ queueMedicationIntakeSync: vi.fn(), })); diff --git a/tests/integration/switched-session-destructive-refusal.test.ts b/tests/integration/switched-session-destructive-refusal.test.ts index dfd48f675..8664b39c0 100644 --- a/tests/integration/switched-session-destructive-refusal.test.ts +++ b/tests/integration/switched-session-destructive-refusal.test.ts @@ -43,10 +43,6 @@ vi.mock("next/headers", async () => { }; }); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - const OWNER_ID = "switch-destructive-owner"; const DELEGATE_ID = "switch-destructive-delegate"; diff --git a/tests/integration/symptoms.test.ts b/tests/integration/symptoms.test.ts index 3271ec9ea..53c4b0a27 100644 --- a/tests/integration/symptoms.test.ts +++ b/tests/integration/symptoms.test.ts @@ -66,10 +66,6 @@ vi.mock("next/headers", async () => { }; }); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - const OWNER_ID = "symptoms-owner"; const OTHER_ID = "symptoms-other"; diff --git a/tests/integration/sync-changes.test.ts b/tests/integration/sync-changes.test.ts index 671161f3f..b7092d344 100644 --- a/tests/integration/sync-changes.test.ts +++ b/tests/integration/sync-changes.test.ts @@ -41,10 +41,6 @@ vi.mock("next/headers", async () => { }; }); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - beforeEach(async () => { await truncateAllTables(getPrismaClient()); cookieJar.clear(); diff --git a/tests/integration/sync-reset-after-restore.test.ts b/tests/integration/sync-reset-after-restore.test.ts index d0d8f90d0..65f1a12f7 100644 --- a/tests/integration/sync-reset-after-restore.test.ts +++ b/tests/integration/sync-reset-after-restore.test.ts @@ -44,10 +44,6 @@ vi.mock("next/headers", async () => { })), }; }); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - beforeEach(async () => { await truncateAllTables(getPrismaClient()); cookieJar.clear(); diff --git a/tests/integration/sync-state.test.ts b/tests/integration/sync-state.test.ts index b3318519f..ecaa6578a 100644 --- a/tests/integration/sync-state.test.ts +++ b/tests/integration/sync-state.test.ts @@ -36,10 +36,6 @@ vi.mock("next/headers", async () => { }; }); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - beforeEach(async () => { await truncateAllTables(getPrismaClient()); cookieJar.clear(); diff --git a/tests/integration/tiered-context-local-day.test.ts b/tests/integration/tiered-context-local-day.test.ts index a7dd40527..e34f22229 100644 --- a/tests/integration/tiered-context-local-day.test.ts +++ b/tests/integration/tiered-context-local-day.test.ts @@ -14,14 +14,10 @@ * readings on that local day, 08:00 PDT (15:00Z) and 23:30 PDT (06:30Z on * the 9th), must form one bucket for the 8th. */ -import { beforeAll, describe, expect, it, vi } from "vitest"; +import { beforeAll, describe, expect, it } from "vitest"; import { getPrismaClient, truncateAllTables } from "./setup"; -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - import { buildTieredSeries } from "@/lib/rollups/tiered-context"; const prisma = getPrismaClient(); diff --git a/tests/integration/timeline-lab-series.test.ts b/tests/integration/timeline-lab-series.test.ts index 48a71e6ca..8f31406d2 100644 --- a/tests/integration/timeline-lab-series.test.ts +++ b/tests/integration/timeline-lab-series.test.ts @@ -42,10 +42,6 @@ vi.mock("next/headers", async () => { }; }); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - type Handler = ( request: NextRequest, // eslint-disable-next-line @typescript-eslint/no-explicit-any diff --git a/tests/integration/timeline-rollup-boundary-zone.test.ts b/tests/integration/timeline-rollup-boundary-zone.test.ts index 1fb74bd51..dc4f838b5 100644 --- a/tests/integration/timeline-rollup-boundary-zone.test.ts +++ b/tests/integration/timeline-rollup-boundary-zone.test.ts @@ -12,10 +12,6 @@ import { afterEach, beforeEach, describe, expect, it, vi } from "vitest"; import { getPrismaClient, truncateAllTables } from "./setup"; -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - /** * Five years before this the fold boundary falls on 2021-10-10, so the first * rolled-up month is November 2021 and the first rolled-up quarter Q1 2022. diff --git a/tests/integration/timeline-sleep-nights.test.ts b/tests/integration/timeline-sleep-nights.test.ts index d6ee07a80..3401039f8 100644 --- a/tests/integration/timeline-sleep-nights.test.ts +++ b/tests/integration/timeline-sleep-nights.test.ts @@ -9,14 +9,10 @@ * call one: CORE + DEEP + REM of the night's winning writer, IN_BED and * AWAKE left out, keyed by its wake day. */ -import { beforeEach, describe, expect, it, vi } from "vitest"; +import { beforeEach, describe, expect, it } from "vitest"; import { getPrismaClient, truncateAllTables } from "./setup"; -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - const TZ = "Europe/Berlin"; const NOW = new Date("2026-10-09T12:00:00.000Z"); diff --git a/tests/integration/timezone-per-user.test.ts b/tests/integration/timezone-per-user.test.ts index 30a1861d3..938c40f01 100644 --- a/tests/integration/timezone-per-user.test.ts +++ b/tests/integration/timezone-per-user.test.ts @@ -53,10 +53,6 @@ vi.mock("next/headers", async () => { }; }); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - beforeEach(async () => { await truncateAllTables(getPrismaClient()); cookieJar.clear(); diff --git a/tests/integration/tombstone-cleanup-restore-lock.test.ts b/tests/integration/tombstone-cleanup-restore-lock.test.ts index a639df410..3fe3737f9 100644 --- a/tests/integration/tombstone-cleanup-restore-lock.test.ts +++ b/tests/integration/tombstone-cleanup-restore-lock.test.ts @@ -17,14 +17,10 @@ * `purgeTombstonesByAccount` and the purge waits out the hold, then deletes * the restoring account's tombstones once the stand-in rolls back. */ -import { afterAll, beforeEach, describe, expect, it, vi } from "vitest"; +import { afterAll, beforeEach, describe, expect, it } from "vitest"; import { getPrismaClient, truncateAllTables } from "./setup"; -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - const RESTORING = "tombstone-restoring"; const OTHER = "tombstone-other"; const HOLD_MS = 3_000; diff --git a/tests/integration/user-avatar.test.ts b/tests/integration/user-avatar.test.ts index dbecb31a0..1f3c0df19 100644 --- a/tests/integration/user-avatar.test.ts +++ b/tests/integration/user-avatar.test.ts @@ -43,10 +43,6 @@ vi.mock("next/headers", async () => { }; }); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - const PNG_1X1 = Buffer.from( "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR4nGNgYGBgAAAABQABXvMqOgAAAABJRU5ErkJggg==", "base64", diff --git a/tests/integration/vaccination-booster-mint.test.ts b/tests/integration/vaccination-booster-mint.test.ts index 1e89514a5..3386bd2aa 100644 --- a/tests/integration/vaccination-booster-mint.test.ts +++ b/tests/integration/vaccination-booster-mint.test.ts @@ -41,10 +41,6 @@ vi.mock("next/headers", async () => { }; }); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - const OWNER_ID = "mint-owner"; const DAY_MS = 24 * 60 * 60 * 1000; diff --git a/tests/integration/vaccination-booster-satisfy.test.ts b/tests/integration/vaccination-booster-satisfy.test.ts index 8de0be3ef..f6d1db2a3 100644 --- a/tests/integration/vaccination-booster-satisfy.test.ts +++ b/tests/integration/vaccination-booster-satisfy.test.ts @@ -45,10 +45,6 @@ vi.mock("next/headers", async () => { }; }); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - const OWNER_ID = "booster-owner"; const DAY_MS = 24 * 60 * 60 * 1000; diff --git a/tests/integration/vaccination-booster-scoped-delegate.test.ts b/tests/integration/vaccination-booster-scoped-delegate.test.ts index 3427956f0..6d6dadb5b 100644 --- a/tests/integration/vaccination-booster-scoped-delegate.test.ts +++ b/tests/integration/vaccination-booster-scoped-delegate.test.ts @@ -44,10 +44,6 @@ vi.mock("next/headers", async () => { }; }); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - const OWNER_ID = "booster-scope-owner"; const DELEGATE_ID = "booster-scope-delegate"; diff --git a/tests/integration/vaccination-custom.test.ts b/tests/integration/vaccination-custom.test.ts index c7e7b1e06..70e69f226 100644 --- a/tests/integration/vaccination-custom.test.ts +++ b/tests/integration/vaccination-custom.test.ts @@ -50,10 +50,6 @@ vi.mock("next/headers", async () => { }; }); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - const DAY_MS = 24 * 60 * 60 * 1000; const daysAgo = (days: number) => new Date(Date.now() - days * DAY_MS); const daysFromNow = (days: number) => new Date(Date.now() + days * DAY_MS); diff --git a/tests/integration/vaccination-managed-profile.test.ts b/tests/integration/vaccination-managed-profile.test.ts index a49ddc77a..6bcf8c8c0 100644 --- a/tests/integration/vaccination-managed-profile.test.ts +++ b/tests/integration/vaccination-managed-profile.test.ts @@ -50,10 +50,6 @@ vi.mock("next/headers", async () => { }; }); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - const DAY_MS = 24 * 60 * 60 * 1000; function daysAgo(days: number): Date { diff --git a/tests/integration/vaccination-renewal.test.ts b/tests/integration/vaccination-renewal.test.ts index a51e0025b..a95cf9d37 100644 --- a/tests/integration/vaccination-renewal.test.ts +++ b/tests/integration/vaccination-renewal.test.ts @@ -32,10 +32,6 @@ vi.mock("next/headers", async () => { }; }); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - const OWNER_ID = "renewal-owner"; const DELEGATE_ID = "renewal-delegate"; diff --git a/tests/integration/visit-link-picker-long-history.test.ts b/tests/integration/visit-link-picker-long-history.test.ts index e67f629dd..cbb7ff090 100644 --- a/tests/integration/visit-link-picker-long-history.test.ts +++ b/tests/integration/visit-link-picker-long-history.test.ts @@ -56,10 +56,6 @@ vi.mock("next/headers", async () => { }; }); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - const OWNER_ID = "long-history-owner"; const DAY_MS = 24 * 60 * 60 * 1000; /** Historical on purpose: the visit and its panel sit years back. */ diff --git a/tests/integration/visit-link-picker-period-search.test.ts b/tests/integration/visit-link-picker-period-search.test.ts index 8c11213fa..82fcac854 100644 --- a/tests/integration/visit-link-picker-period-search.test.ts +++ b/tests/integration/visit-link-picker-period-search.test.ts @@ -58,10 +58,6 @@ vi.mock("next/headers", async () => { }; }); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - const OWNER_ID = "period-search-owner"; const DAY_MS = 24 * 60 * 60 * 1000; const TZ = "Europe/Berlin"; diff --git a/tests/integration/whoop-connect-ticket.test.ts b/tests/integration/whoop-connect-ticket.test.ts index 915e88348..ce7104f65 100644 --- a/tests/integration/whoop-connect-ticket.test.ts +++ b/tests/integration/whoop-connect-ticket.test.ts @@ -50,10 +50,6 @@ vi.mock("next/headers", async () => { }; }); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - const TEST_USER_ID = "user-whoop-connect-ticket"; const RAW_BEARER = "hlk_whoopconnectticketintegrationrawtokenvalue00000001"; const WHOOP_AUTH_URL = "https://api.prod.whoop.com/oauth/oauth2/auth"; diff --git a/tests/integration/withings-oauth-flow.test.ts b/tests/integration/withings-oauth-flow.test.ts index 1ba5e6197..a95a17e71 100644 --- a/tests/integration/withings-oauth-flow.test.ts +++ b/tests/integration/withings-oauth-flow.test.ts @@ -52,10 +52,6 @@ vi.mock("next/headers", async () => { }; }); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - const TEST_USER_ID = "user-withings-oauth-flow"; const WITHINGS_OAUTH_URL = diff --git a/tests/integration/withings-oauth.test.ts b/tests/integration/withings-oauth.test.ts index d8275fce0..7d3d3c9fd 100644 --- a/tests/integration/withings-oauth.test.ts +++ b/tests/integration/withings-oauth.test.ts @@ -51,10 +51,6 @@ vi.mock("next/headers", async () => { }; }); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - const TEST_USER_ID = "user-withings-oauth"; const WITHINGS_TOKEN_URL = "https://wbsapi.withings.net/v2/oauth2"; diff --git a/tests/integration/withings-sync-volume.test.ts b/tests/integration/withings-sync-volume.test.ts index c2b97d9aa..ea4069bf1 100644 --- a/tests/integration/withings-sync-volume.test.ts +++ b/tests/integration/withings-sync-volume.test.ts @@ -20,10 +20,6 @@ import { encrypt } from "@/lib/crypto"; import { getPrismaClient, truncateAllTables } from "./setup"; -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - vi.mock("@/lib/withings/client", async (importOriginal) => { const actual = await importOriginal(); return { ...actual, fetchMeasurements: vi.fn() }; diff --git a/tests/integration/workout-batch-create.test.ts b/tests/integration/workout-batch-create.test.ts index 00e431dfd..da4fda1a3 100644 --- a/tests/integration/workout-batch-create.test.ts +++ b/tests/integration/workout-batch-create.test.ts @@ -56,10 +56,6 @@ vi.mock("next/headers", async () => { }; }); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - beforeEach(async () => { await truncateAllTables(getPrismaClient()); cookieJar.clear(); diff --git a/tests/integration/workout-batch-enrich.test.ts b/tests/integration/workout-batch-enrich.test.ts index 3b80f526e..d0f1838dc 100644 --- a/tests/integration/workout-batch-enrich.test.ts +++ b/tests/integration/workout-batch-enrich.test.ts @@ -53,10 +53,6 @@ vi.mock("next/headers", async () => { }; }); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - beforeEach(async () => { await truncateAllTables(getPrismaClient()); cookieJar.clear(); diff --git a/tests/integration/workout-batch-race.test.ts b/tests/integration/workout-batch-race.test.ts index d55aed62b..5d4cd0ac6 100644 --- a/tests/integration/workout-batch-race.test.ts +++ b/tests/integration/workout-batch-race.test.ts @@ -45,10 +45,6 @@ vi.mock("next/headers", async () => { }; }); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - beforeEach(async () => { await truncateAllTables(getPrismaClient()); cookieJar.clear(); diff --git a/tests/integration/workout-detail-hr-series.test.ts b/tests/integration/workout-detail-hr-series.test.ts index 7f3d904be..ac616d76e 100644 --- a/tests/integration/workout-detail-hr-series.test.ts +++ b/tests/integration/workout-detail-hr-series.test.ts @@ -56,10 +56,6 @@ vi.mock("next/headers", async () => { }; }); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - const { GET } = await import("@/app/api/workouts/[id]/route"); /** diff --git a/tests/integration/workout-manual-entry.test.ts b/tests/integration/workout-manual-entry.test.ts index 434d4839c..ff28f18ac 100644 --- a/tests/integration/workout-manual-entry.test.ts +++ b/tests/integration/workout-manual-entry.test.ts @@ -53,10 +53,6 @@ vi.mock("next/headers", async () => { const emitDataArrival = vi.hoisted(() => vi.fn(async () => undefined)); vi.mock("@/lib/arrivals/emit-shared", () => ({ emitDataArrival })); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - const { POST: postBatch } = await import("@/app/api/workouts/batch/route"); const { GET: listWorkouts } = await import("@/app/api/workouts/route"); const { DELETE: deleteWorkout } = await import("@/app/api/workouts/[id]/route"); diff --git a/tests/integration/write-meter.test.ts b/tests/integration/write-meter.test.ts index cd945a9c1..56b6abe57 100644 --- a/tests/integration/write-meter.test.ts +++ b/tests/integration/write-meter.test.ts @@ -41,10 +41,6 @@ vi.mock("next/headers", async () => { }; }); -vi.mock("@/lib/db-compat", () => ({ - ensureDbCompatibility: vi.fn().mockResolvedValue(undefined), -})); - const USER_ID = "user-write-meter"; const BUCKET = `${RECORD_WRITE_BUCKET_PREFIX}:${USER_ID}`;