Merge branch 'release/v1.46.0' into feat/v146-ui

This commit is contained in:
Marc-André Bombeck committed 2026-10-23 16:44:26 +02:00
commit 551fbbbdec
445 files changed
+164623 -24087

No files matched your search

@@ -312,7 +312,7 @@ describe("workout route geometry never reaches an AI path", () => {
/\breadRouteGeometry\s*\(|\bencryptRouteGeometry\s*\(|\bgeometryEncrypted\b|\bgeometry\s*:\s*true\b/;
const ROUTE_READERS: Record<string, string> = {
"app/api/workouts/[id]/route.ts":
"lib/workouts/detail.ts":
"The workout detail read: serves the track to the person's own map.",
"lib/workouts/batch-ingest/write.ts":
"The workout batch ingest's write: stores a kept track (opt-in), sealed.",
@@ -41,7 +41,7 @@ const ADMITTED: Record<string, { jobs: string[]; why: string }> = {
jobs: ["daily_briefing"],
why: "The daily briefing's generation and its phrasing re-roll; the JSON and grounding repairs do not reason.",
},
"app/api/insights/generate/route.ts": {
"lib/insights/briefing-request/completion.ts": {
jobs: ["daily_briefing"],
why: "A briefing asked for by hand reasons like the scheduled one; its JSON and grounding repairs do not.",
},
@@ -1,13 +1,8 @@
{
"$comment": "Production files over 800 lines and their length. Maintained by src/__tests__/source-size-ratchet.test.ts.",
"count": 96,
"total": 106730,
"count": 91,
"total": 101359,
"entries": {
"app/api/dashboard/summary/route.ts": 1032,
"app/api/documents/inbound/route.ts": 811,
"app/api/insights/generate/route.ts": 1214,
"app/api/medications/[id]/route.ts": 1270,
"app/api/medications/intake/bulk/route.ts": 1044,
"app/medications/page-client.tsx": 839,
"components/charts/mood-chart.tsx": 1166,
"components/cycle/log-day-sheet.tsx": 1639,
@@ -1,35 +1,27 @@
{
"$comment": "Production functions over 200 lines, keyed \"file :: name\", and their length. Maintained by src/__tests__/source-size-ratchet.test.ts.",
"count": 373,
"total": 124458,
"count": 355,
"total": 114858,
"entries": {
"app/achievements/page.tsx :: AchievementsPage": 206,
"app/api/admin/backups/upload/route.ts :: apiHandler(arg)": 314,
"app/api/admin/notifications/reminder-check/route.ts :: apiHandler(arg)": 208,
"app/api/admin/settings/route.ts :: apiHandler(arg) #2": 211,
"app/api/analytics/route.ts :: buildAnalyticsResponse": 446,
"app/api/auth/login/route.ts :: apiHandler(arg)": 262,
"app/api/auth/me/route.ts :: apiHandler(arg)": 386,
"app/api/auth/oidc/callback/route.ts :: apiHandler(arg)": 499,
"app/api/auth/oidc/callback/route.ts :: apiHandler(arg)": 294,
"app/api/auth/register/route.ts :: apiHandler(arg)": 268,
"app/api/coach/about-me/route.ts :: apiHandler(arg) #2": 309,
"app/api/cycle/calendar/route.ts :: apiHandler(arg)": 230,
"app/api/cycle/day-logs/bulk/route.ts :: postBulk": 213,
"app/api/cycle/insights/route.ts :: apiHandler(arg)": 226,
"app/api/dashboard/summary/route.ts :: buildDashboardSummary": 606,
"app/api/devices/route.ts :: apiHandler(arg)": 231,
"app/api/documents/inbound/bulk/route.ts :: apiHandler(arg)": 207,
"app/api/documents/inbound/route.ts :: processUpload": 309,
"app/api/encounters/[id]/route.ts :: apiHandler(arg) #2": 269,
"app/api/environment/route.ts :: apiHandler(arg)": 201,
"app/api/export/health-record/route.ts :: apiHandler(arg)": 241,
"app/api/import/csv/route.ts :: apiHandler(arg)": 407,
"app/api/import/route.ts :: apiHandler(arg)": 364,
"app/api/ingest/medication/route.ts :: apiHandler(arg)": 267,
"app/api/insights/cards/route.ts :: apiHandler(arg)": 211,
"app/api/insights/comprehensive/route.ts :: buildComprehensiveResponse": 505,
"app/api/insights/generate/route.ts :: apiHandler(arg) #2": 866,
"app/api/insights/generate/route.ts :: apiHandler(arg) > withFeatureCacheScope(arg)": 862,
"app/api/integrations/status/route.ts :: apiHandler(arg)": 451,
"app/api/labs/[id]/route.ts :: apiHandler(arg) #2": 239,
"app/api/labs/ocr/commit/route.ts :: commitOcrRows": 285,
@@ -37,28 +29,18 @@
"app/api/mcp/oauth/token/route.ts :: POST": 250,
"app/api/mcp/oauth/token/route.ts :: POST > withBackgroundEvent(arg)": 248,
"app/api/measurement-reminders/[id]/route.ts :: apiHandler(arg) #2": 239,
"app/api/measurements/series/route.ts :: apiHandler(arg)": 549,
"app/api/medications/[id]/dose-history/route.ts :: apiHandler(arg)": 256,
"app/api/medications/[id]/intake/route.ts :: postIntake": 607,
"app/api/medications/[id]/inventory/[itemId]/route.ts :: apiHandler(arg)": 204,
"app/api/medications/[id]/route.ts :: apiHandler(arg)": 214,
"app/api/medications/[id]/route.ts :: apiHandler(arg) #2": 886,
"app/api/medications/[id]/route.ts :: apiHandler(arg) > prisma.$transaction(arg)": 293,
"app/api/medications/[id]/schedule-revisions/[revisionId]/route.ts :: apiHandler(arg)": 250,
"app/api/medications/extract/route.ts :: handleExtract": 201,
"app/api/medications/intake/bulk/route.ts :: postBulk": 846,
"app/api/medications/intake/route.ts :: apiHandler(arg) #2": 432,
"app/api/mental-health/assessments/route.ts :: postAssessment": 249,
"app/api/mood-entries/[id]/route.ts :: apiHandler(arg) #2": 296,
"app/api/mood-entries/bulk/route.ts :: postBulk": 479,
"app/api/mood-entries/route.ts :: postMoodEntry": 324,
"app/api/nutrients/batch/route.ts :: postBatch": 304,
"app/api/onboarding/complete/route.ts :: completeNeedsFlow": 218,
"app/api/record-settings/[family]/route.ts :: apiHandler(arg) #2": 262,
"app/api/sync/changes/route.ts :: apiHandler(arg)": 427,
"app/api/user/ai-provider/route.ts :: apiHandler(arg) #2": 248,
"app/api/withings/callback/route.ts :: apiHandler(arg)": 247,
"app/api/workouts/[id]/route.ts :: apiHandler(arg)": 297,
"app/auth/login/page.tsx :: LoginPage": 576,
"app/auth/register/page.tsx :: RegisterPage": 285,
"app/coach/conversations/page.tsx :: CoachConversationsBody": 249,
@@ -1,7 +1,7 @@
{
"$comment": "Comment lines that open with a release version, per file under src/. Maintained by src/__tests__/version-stamp-ratchet.test.ts.",
"count": 2904,
"total": 9630,
"count": 2898,
"total": 9297,
"entries": {
"__tests__/account-payload-consumer-guard.test.ts": 2,
"__tests__/acting-account-boundary-guard.test.ts": 7,
@@ -128,7 +128,7 @@
"app/api/allergies/route.ts": 1,
"app/api/analytics/__tests__/route.test.ts": 27,
"app/api/analytics/range/route.ts": 2,
"app/api/analytics/route.ts": 39,
"app/api/analytics/route.ts": 10,
"app/api/anamnesis/facts/__tests__/route.test.ts": 1,
"app/api/auth/claim/__tests__/route.test.ts": 1,
"app/api/auth/claim/preview/route.ts": 1,
@@ -163,7 +163,7 @@
"app/api/auth/mfa/verify/route.ts": 1,
"app/api/auth/mfa/webauthn/verify/route.ts": 1,
"app/api/auth/oidc/callback/__tests__/route.test.ts": 1,
"app/api/auth/oidc/callback/route.ts": 7,
"app/api/auth/oidc/callback/route.ts": 3,
"app/api/auth/oidc/login/route.ts": 2,
"app/api/auth/passkey/login-options/route.ts": 1,
"app/api/auth/passkey/login-verify/__tests__/native-token.test.ts": 2,
@@ -220,7 +220,7 @@
"app/api/dashboard/snapshot/__tests__/route.test.ts": 2,
"app/api/dashboard/snapshot/route.ts": 1,
"app/api/dashboard/summary/__tests__/route.test.ts": 16,
"app/api/dashboard/summary/route.ts": 31,
"app/api/dashboard/summary/route.ts": 5,
"app/api/dashboard/widgets/__tests__/route.test.ts": 4,
"app/api/dashboard/widgets/route.ts": 14,
"app/api/devices/__tests__/route.test.ts": 1,
@@ -243,7 +243,7 @@
"app/api/documents/inbound/[id]/summary/route.ts": 2,
"app/api/documents/inbound/[id]/thumbnail/route.ts": 1,
"app/api/documents/inbound/reindex/route.ts": 1,
"app/api/documents/inbound/route.ts": 3,
"app/api/documents/inbound/route.ts": 2,
"app/api/documents/inbound/usage/route.ts": 1,
"app/api/environment/backfill/__tests__/route.test.ts": 1,
"app/api/environment/route.ts": 1,
@@ -284,7 +284,7 @@
"app/api/illness/episodes/route.ts": 1,
"app/api/import/__tests__/route.test.ts": 3,
"app/api/import/csv/__tests__/route.test.ts": 2,
"app/api/import/route.ts": 8,
"app/api/import/route.ts": 4,
"app/api/ingest/medication/__tests__/route.test.ts": 1,
"app/api/ingest/medication/route.ts": 7,
"app/api/insights/biomarker-assessment/route.ts": 1,
@@ -321,7 +321,6 @@
"app/api/insights/coach/nudge-status/route.ts": 1,
"app/api/insights/coach/seen/route.ts": 1,
"app/api/insights/comprehensive/__tests__/route.test.ts": 9,
"app/api/insights/comprehensive/route.ts": 24,
"app/api/insights/correlations/__tests__/route.test.ts": 10,
"app/api/insights/correlations/route.ts": 9,
"app/api/insights/derived/__tests__/route.test.ts": 4,
@@ -334,7 +333,6 @@
"app/api/insights/ecg/route.ts": 1,
"app/api/insights/feedback/route.ts": 2,
"app/api/insights/generate/__tests__/route.test.ts": 12,
"app/api/insights/generate/route.ts": 57,
"app/api/insights/glp1-plateau/route.ts": 2,
"app/api/insights/glp1-timeline/route.ts": 4,
"app/api/insights/health-status/route.ts": 3,
@@ -413,7 +411,7 @@
"app/api/measurements/series-batch/__tests__/route.test.ts": 1,
"app/api/measurements/series-batch/route.ts": 1,
"app/api/measurements/series/__tests__/route.test.ts": 5,
"app/api/measurements/series/route.ts": 21,
"app/api/measurements/series/route.ts": 6,
"app/api/medications/__tests__/route.test.ts": 10,
"app/api/medications/[id]/__tests__/route.test.ts": 8,
"app/api/medications/[id]/api-endpoint/route.ts": 2,
@@ -434,11 +432,9 @@
"app/api/medications/[id]/intake/import/__tests__/route.test.ts": 2,
"app/api/medications/[id]/intake/import/route.ts": 6,
"app/api/medications/[id]/intake/purge/route.ts": 4,
"app/api/medications/[id]/intake/route.ts": 30,
"app/api/medications/[id]/inventory/[itemId]/route.ts": 8,
"app/api/medications/[id]/inventory/route.ts": 4,
"app/api/medications/[id]/phase-config/route.ts": 4,
"app/api/medications/[id]/route.ts": 58,
"app/api/medications/[id]/schedule-revisions/__tests__/route.test.ts": 1,
"app/api/medications/[id]/schedule-revisions/[revisionId]/route.ts": 9,
"app/api/medications/[id]/schedule-revisions/route.ts": 3,
@@ -453,9 +449,8 @@
"app/api/medications/intake/__tests__/route.test.ts": 21,
"app/api/medications/intake/bulk/__tests__/dose-arrival-scope.test.ts": 1,
"app/api/medications/intake/bulk/__tests__/route.test.ts": 10,
"app/api/medications/intake/bulk/route.ts": 42,
"app/api/medications/intake/bulk/route.ts": 9,
"app/api/medications/intake/dose-history-import/route.ts": 2,
"app/api/medications/intake/route.ts": 34,
"app/api/medications/layout/__tests__/route.test.ts": 3,
"app/api/medications/layout/route.ts": 3,
"app/api/medications/route.ts": 2,
@@ -467,7 +462,7 @@
"app/api/mood-entries/bulk-delete/__tests__/route.test.ts": 1,
"app/api/mood-entries/bulk-delete/route.ts": 4,
"app/api/mood-entries/bulk/__tests__/route.test.ts": 5,
"app/api/mood-entries/bulk/route.ts": 16,
"app/api/mood-entries/bulk/route.ts": 6,
"app/api/mood-entries/restore/__tests__/route.test.ts": 1,
"app/api/mood-entries/restore/route.ts": 3,
"app/api/mood-entries/route.ts": 22,
@@ -533,7 +528,6 @@
"app/api/strava/credentials/route.ts": 1,
"app/api/strava/disconnect/route.ts": 1,
"app/api/strava/status/route.ts": 1,
"app/api/sync/changes/route.ts": 5,
"app/api/sync/state/route.ts": 2,
"app/api/telegram/webhook/__tests__/route.test.ts": 3,
"app/api/user/ai-provider/__tests__/legacy-private-host.test.ts": 1,
@@ -559,7 +553,7 @@
"app/api/withings/webhook/route.ts": 2,
"app/api/workouts/__tests__/batch-create.test.ts": 3,
"app/api/workouts/__tests__/canonical-dedup.test.ts": 3,
"app/api/workouts/[id]/route.ts": 5,
"app/api/workouts/[id]/route.ts": 2,
"app/api/workouts/batch/route.ts": 3,
"app/api/workouts/route.ts": 2,
"app/auth/claim/page.tsx": 1,
@@ -25,7 +25,8 @@ import { readFileSync } from "node:fs";
import { join } from "node:path";
const READS = join(process.cwd(), "src/lib/dashboard/summary-reads.ts");
const ROUTE = join(process.cwd(), "src/app/api/dashboard/summary/route.ts");
/** The summary's builder, moved out of its route; it makes the reads. */
const ROUTE = join(process.cwd(), "src/lib/dashboard/summary/build.ts");
/**
* Source with every comment removed, so a guard matches the SQL the
@@ -69,6 +69,15 @@ const SCOPED_DIRS = [
"lib/measurements/batch-ingest/",
"lib/measurements/create/",
"lib/measurements/list/measurement-list.ts",
"lib/medications/read-medication.ts",
"lib/medications/update-medication/",
"lib/medications/delete-medication.ts",
"lib/medications/record-intake/",
"lib/medications/list-intake-events.ts",
"lib/medications/intake-today.ts",
"lib/medications/intake-compliance.ts",
"lib/medications/update-intake-status/",
"lib/medications/intake-bulk/",
];
/** Types a device writes at sampling rate rather than a few times a day. */
@@ -106,7 +115,7 @@ const ALLOWED: Record<string, string> = {
"Same 30-day clinical glucose panel as the coach snapshot (per-reading metrics), grouped by meal context.",
"lib/analytics/score/reader.ts::{ in: types":
"Health-score inputs: steps (drained to one row per day nightly), sleep, waist, weight, blood pressure, fasting glucose only.",
'app/api/analytics/route.ts::"BLOOD_GLUCOSE"':
'lib/analytics/response/glucose.ts::"BLOOD_GLUCOSE"':
"The 30-day per-context glucose summary, the same window and bound as the dashboard and coach glucose panels: at a sensor's fixed rate, below 45 000 rows.",
"lib/measurements/batch-ingest/write-measurements.ts::p.row.type as MeasurementType":
"Cross-source merge probe: one ±tolerance window around each posted reading's instant, so the rows found are bounded by the batch size.",
@@ -365,7 +365,7 @@ describe("the intake idempotency key is never read across users", () => {
const found = intakeQueriesFilteringOnTheKey();
expect(found.length).toBeGreaterThanOrEqual(6);
expect(found.map((f) => f.file)).toContain(
"app/api/medications/intake/bulk/route.ts",
"lib/medications/intake-bulk/entry-write.ts",
);
});
@@ -402,14 +402,21 @@ describe("the batch surfaces refuse per entry, never whole-batch", () => {
"lib/measurements/batch-ingest/prepare.ts",
"lib/measurements/batch-ingest/ingest.ts",
],
"app/api/mood-entries/bulk/route.ts": [],
"app/api/medications/intake/bulk/route.ts": [],
"app/api/mood-entries/bulk/route.ts": ["lib/mood/bulk-ingest.ts"],
"app/api/medications/intake/bulk/route.ts": [
"lib/medications/intake-bulk/entry.ts",
"lib/medications/intake-bulk/ingest.ts",
],
"app/api/workouts/batch/route.ts": [
"lib/workouts/batch-ingest/entries.ts",
"lib/workouts/batch-ingest/ingest.ts",
],
"app/api/cycle/day-logs/bulk/route.ts": [],
"app/api/import/route.ts": [],
"app/api/import/route.ts": [
"lib/import/json/measurements.ts",
"lib/import/json/mood.ts",
"lib/import/json/run.ts",
],
};
const BATCH_ROUTES = Object.keys(BATCH_SURFACES);
@@ -309,9 +309,44 @@ function actionsReachableFrom(
out.push(...packageActions(reexported, read));
}
}
for (const body of HANDLER_BODY_MODULES[relative(SRC, file)] ?? []) {
out.push(...actionsReachableFrom(join(SRC, body), read));
}
return out;
}
/**
* Delegated routes whose handler bodies live in service modules under
* `src/lib/`, keyed by the route relative to `src/`. A handler body is the
* route's own code moved, so it counts at the route's level: its actions and
* those of its direct imports (the medication lifecycle a dose write
* reconciles through) are reached as they were before the move. Each module
* has to be a direct import of its route (leg below), so an entry cannot
* outlive the delegation it describes.
*/
const HANDLER_BODY_MODULES: Record<string, readonly string[]> = {
"app/api/medications/route.ts": ["lib/medications/create-medication.ts"],
"app/api/medications/[id]/route.ts": [
"lib/medications/read-medication.ts",
"lib/medications/update-medication/update-medication.ts",
"lib/medications/delete-medication.ts",
],
"app/api/medications/[id]/intake/route.ts": [
"lib/medications/record-intake/record-intake.ts",
"lib/medications/list-intake-events.ts",
],
"app/api/medications/[id]/intake/[eventId]/route.ts": [
"lib/medications/update-intake-event.ts",
"lib/medications/delete-intake-event.ts",
],
"app/api/medications/intake/route.ts": [
"lib/medications/intake-today.ts",
"lib/medications/intake-compliance.ts",
"lib/medications/update-intake-status/admission.ts",
"lib/medications/update-intake-status/update-intake-status.ts",
],
};
/**
* The actions of a re-exported module together with the sibling modules it
* imports from its own folder. The re-exported module is a package's public
@@ -553,6 +588,21 @@ describe("every delegated action has a sentence of its own", () => {
expect(manageOnly).not.toContain(anchor);
});
it("reads each moved handler body where its route imports it from", () => {
const entries = Object.entries(HANDLER_BODY_MODULES);
expect(entries.length).toBeGreaterThan(0);
for (const [route, bodies] of entries) {
const file = join(SRC, route);
expect(delegatedModules, route).toContain(file);
for (const body of bodies) {
expect(
read(file).imports,
`${route} does not import ${body}`,
).toContain(join(SRC, body));
}
}
});
it("reaches the actions a route files through what it imports", () => {
// Both halves of the fix, pinned against the two that were invisible.
expect(actions).toContain("medication.intake.import.kickoff.denied");
@@ -73,7 +73,10 @@ const WRITERS: Record<string, Disposition> = {
kind: "upstream",
validatedIn: "lib/validations/measurement.ts",
},
"app/api/import/route.ts": { kind: "validator" },
"lib/import/json/measurements.ts": {
kind: "upstream",
validatedIn: "app/api/import/route.ts",
},
// The batch ingest's set-based insert writes rows that already passed
// `validateMeasurementRange` per entry in its first pass; everything else
// goes through the reconciler, which gates itself.
@@ -88,7 +91,7 @@ const WRITERS: Record<string, Disposition> = {
// insert after `validateMeasurementRange`; day totals through the gated
// reconcile seam.
"lib/import/health-connect/import.ts": { kind: "validator" },
"app/api/import/csv/route.ts": {
"lib/import/csv-write.ts": {
kind: "upstream",
validatedIn: "lib/import/csv-measurements.ts",
},
@@ -52,8 +52,8 @@ const PROVIDER_TAIL = "runs afterProviderWrite";
* fails too).
*/
const WRITE_SITES: Record<string, string> = {
"app/api/import/csv/route.ts": TAIL,
"app/api/import/route.ts": TAIL,
"lib/import/csv-write.ts": TAIL,
"lib/import/json/measurements.ts": TAIL_VIA("lib/import/json/run.ts"),
"app/api/measurements/[id]/route.ts": TAIL,
"app/api/measurements/bulk-delete/route.ts": TAIL,
"app/api/measurements/by-external-ids/route.ts": TAIL,
@@ -30,7 +30,7 @@ import { describe, it, expect } from "vitest";
import { readFileSync } from "node:fs";
import { join } from "node:path";
import { walkSourceFiles } from "./helpers/source-files";
import { stripComments, walkSourceFiles } from "./helpers/source-files";
const SRC = join(process.cwd(), "src");
@@ -57,22 +57,24 @@ const INTAKE_READ =
*/
const INTAKE_MAY_SEE_EVERY_ROW: Record<string, string> = {
"app/api/admin/status/route.ts": "instance row counts",
"app/api/dashboard/summary/route.ts":
"lib/dashboard/summary/build.ts":
"engagement streak of days with any logged action, no rate",
"app/api/export/medications/route.ts": "export of the recorded history",
"app/api/export/route.ts": "export of the recorded history",
"lib/export/medications-backup.ts": "backup of the recorded history",
"app/api/sync/state/route.ts": "sync watermarks, no rate",
"lib/sync/changes/read-rows.ts":
"delta feed mirroring the recorded rows to a paired client, no rate",
"lib/jobs/measurement-tombstone-cleanup.ts": "tombstone purge",
"lib/ai/coach/tools/availability.ts":
"whether any intake history exists, and its date range",
"app/api/medications/[id]/intake/route.ts":
"one medication's recorded history, listed or written",
"lib/medications/list-intake-events.ts":
"one medication's recorded history, listed",
"app/api/medications/[id]/intake/bulk-delete/route.ts":
"deletes rows the person chose",
"app/api/medications/[id]/route.ts":
"one medication's slots; tombstones on the tracking switch",
"app/api/medications/intake/bulk/route.ts": "writes recorded doses",
"lib/medications/update-medication/write.ts":
"one medication's open slots, tombstoned on a schedule replace or the tracking switch",
"lib/medications/intake-bulk/ingest.ts": "writes recorded doses",
"lib/medications/scheduling/slot-upsert.ts":
"binds a recorded dose to its slot",
"lib/medications/scheduling/worker-helpers.ts":
@@ -113,6 +115,14 @@ const MAY_READ_EVERY_ROW: Record<string, string> = {
"units consumed by a recorded dose",
"lib/medications/intake-slot-dedup.ts":
"folds duplicate rows of doses already recorded",
// The medication edit: the schedule count and the primary schedule's id
// for the reminder-window bridge, and the replaced rows archived as an era
// whose payload is empty for a stretch with tracking off. Nothing due comes
// out of either; the edit answers through scheduleWireFields.
"lib/medications/update-medication/preflight.ts":
"schedule count and the primary schedule's id, derives nothing due",
"lib/medications/update-medication/write.ts":
"archives the replaced schedule; the era payload follows the tracking switch",
// Readers that hand the rows to a builder whose input TYPE requires
// `trackIntake` and which gates on it: the per-medication compliance
// payload (`buildCompliancePayload`, INTAKE_NOT_TRACKED) and the doctor
@@ -141,12 +151,6 @@ function sourceFiles(): string[] {
}
/** Drop line and block comments so a mention in prose never counts. */
function stripComments(source: string): string {
return source
.replace(/\/\*[\s\S]*?\*\//g, "")
.replace(/(^|[^:])\/\/.*$/gm, "$1");
}
function code(rel: string): string {
return stripComments(readFileSync(join(SRC, rel), "utf8"));
}
@@ -37,10 +37,13 @@ describe("native OIDC error reasons are documented", () => {
// The login route answers both legs through `loginError`; the callback's
// native-aware helper is `failRedirect`. `errorRedirect` in the callback is
// the browser-only branch taken before the state (and so the native flag)
// could be read, and never reaches the app.
// could be read, and never reaches the app. The account resolution the
// callback calls names its refusals through `refuse`, and the callback
// hands each one to `failRedirect`.
const sent = new Set([
...reasons(read("app/api/auth/oidc/login/route.ts"), ["loginError"]),
...reasons(read("app/api/auth/oidc/callback/route.ts"), ["failRedirect"]),
...reasons(read("lib/auth/oidc-callback/resolve-account.ts"), ["refuse"]),
]);
// The login route's 302 description is one string literal on one line.
@@ -70,7 +70,9 @@ const SQL_MEAN =
const TS_MEAN =
/\.reduce\(\s*\(\s*\w+\s*,\s*\w+\s*\)\s*=>\s*\w+\s*\+\s*[\w.]+\s*,\s*0\s*\)\s*\/\s*[\w.]+\.length|\bavgInWindow\s*\(|\bsummarize\s*\(|\bbucketWeekly\s*\(|\bbuildDailyValueRows\s*\(|\bapplyPayloadBudget\s*\(/g;
const NAMES_PULSE = /\bPULSE\b/;
// The stored type, or the series route's `kind === "pulse"` (its readers name
// the wire kind, not the type).
const NAMES_PULSE = /\bPULSE\b|===\s*"pulse"/;
/**
* A day folded from its hours' means with every hour weighing one: SQL
@@ -113,7 +115,7 @@ const SQL_READERS: Record<string, Entry> = {
/** Files that name pulse and hold an in-memory mean or a mean-making fold. */
const TS_READERS: Record<string, Entry> = {
"app/api/measurements/series/route.ts": HELPER,
"lib/measurements/series/read-raw.ts": HELPER,
"lib/doctor-report/collect.ts": HELPER,
"lib/doctor-report-pdf/clinical-summary.ts": HELPER,
"lib/insights/comprehensive-generate.ts": HELPER,
@@ -146,7 +148,7 @@ const TS_READERS: Record<string, Entry> = {
"lib/analytics/correlations-fast-path.ts": {
exempt: "mood mean; pulse enters as the resting series, never a day mean",
},
"app/api/dashboard/summary/route.ts": {
"lib/dashboard/summary/cards.ts": {
exempt:
"places a card's seven-day sparkline mean against its band for the trend verdict; each sparkline point is already one rollup day value, so the mean weighs every day once",
},
@@ -175,7 +177,7 @@ const TS_READERS: Record<string, Entry> = {
"app/api/insights/cards/route.ts": {
exempt: "pulse is summarised from day means (readDayMeanSeries)",
},
"app/api/insights/comprehensive/route.ts": {
"lib/insights/comprehensive-overview/build.ts": {
exempt: "summarises the mood series only",
},
};
@@ -362,7 +362,7 @@ const V143_FIELDS: ResolvedFieldEntry[] = [
sameResolver: {
pattern: VERDICT_RESOLVER,
files: [
"src/app/api/dashboard/summary/route.ts",
"src/lib/dashboard/summary/cards.ts",
"src/lib/dashboard/snapshot.ts",
],
},
@@ -410,7 +410,7 @@ const V143_FIELDS: ResolvedFieldEntry[] = [
sameResolver: {
pattern: VERDICT_RESOLVER,
files: [
"src/app/api/measurements/series/route.ts",
"src/lib/measurements/series/read-series.ts",
"src/lib/dashboard/snapshot.ts",
],
},
+34 -8
View File
@@ -76,7 +76,7 @@ import type { ShareScope } from "@/lib/sharing/scope";
import { ADMITTED_MUTATING_HANDLERS } from "../../tests/fixtures/v137/sharing-matrix";
import { API_HANDLER, guardModuleOf } from "./helpers/auth-guards";
import { readSourceText } from "./helpers/source-files";
import { readSourceText, walkSourceFiles } from "./helpers/source-files";
const SRC = join(process.cwd(), "src");
@@ -435,6 +435,17 @@ function callsSymbol(rel: string, symbol: string): boolean {
*/
const HANDLER_BODY_MODULES: Record<string, readonly string[]> = {
"app/api/medications/route.ts": ["lib/medications/create-medication.ts"],
"app/api/medications/[id]/route.ts": [
"lib/medications/update-medication/update-medication.ts",
"lib/medications/delete-medication.ts",
],
"app/api/medications/[id]/intake/route.ts": [
"lib/medications/record-intake/record-intake.ts",
],
"app/api/medications/intake/route.ts": [
"lib/medications/update-intake-status/admission.ts",
"lib/medications/update-intake-status/update-intake-status.ts",
],
"app/api/medications/[id]/intake/[eventId]/route.ts": [
"lib/medications/update-intake-event.ts",
"lib/medications/delete-intake-event.ts",
@@ -3305,15 +3316,30 @@ describe("(g) the MANAGE route set is frozen", () => {
// and refreshes no token. Credential policy belongs inside every resolver
// and presence helper so a delegate or managed system job cannot select a
// personal BYOK key or custom base URL first.
// The route hands its body to the overview modules, so the leg reads the
// route and every one of them: the probe is called among them, and no
// resolver is called by any.
const comprehensiveModules = [
"app/api/insights/comprehensive/route.ts",
...walkSourceFiles(join(SRC, "lib/insights/comprehensive-overview"), {
floor: 5,
}).map((f) => `lib/insights/comprehensive-overview/${f}`),
];
expect(read(comprehensiveModules[0])).toContain(
'"@/lib/insights/comprehensive-overview/overview"',
);
expect(
callsSymbol(
"app/api/insights/comprehensive/route.ts",
"probeProviderPresence",
),
comprehensiveModules.some((m) => callsSymbol(m, "probeProviderPresence")),
).toBe(true);
expect(
callsSymbol("app/api/insights/comprehensive/route.ts", "resolveProvider"),
).toBe(false);
for (const m of comprehensiveModules) {
for (const name of [
"resolveProvider",
"resolveProviderChain",
"probeProviderChain",
]) {
expect(callsSymbol(m, name), `${m} calls ${name}`).toBe(false);
}
}
for (const name of [
"resolveProvider",
"resolveProviderChain",
@@ -90,10 +90,7 @@ describe("one standard deviation", () => {
it("the series API and the AI and MCP payload report the same spread", () => {
expect(
stripComments(
readSource(
"src/app/api/measurements/series/route.ts",
"READING_SPREAD",
),
readSource("src/lib/measurements/series/kinds.ts", "READING_SPREAD"),
),
).toMatch(/standardDeviation\(\s*values,\s*READING_SPREAD\s*\)/);
const features = stripComments(
@@ -53,6 +53,8 @@ const ALLOWED: Record<string, string> = {
"Withholds medication texts from the recall trail; a deleted fact still withholds, which errs toward saying less.",
"coachFact@lib/ai/coach/memory/remember.ts":
"Answer-once check on the message that proposed the fact, inside its lock.",
"moodEntry@lib/mood/bulk-ingest.ts":
"Write path, not analysis: resolves the row that won a raced external-id upsert, which owns the key whether or not it is deleted.",
};
function stripComments(text: string): string {
@@ -253,6 +253,8 @@ const WIDE_SWEEP_ROOTS = [
"lib/jobs/",
"lib/targets/",
"lib/daily/",
// The series route's readers, moved out of `app/` with their unit tokens.
"lib/measurements/series/",
];
const UNIT_LITERAL_PATTERNS: readonly RegExp[] = [
@@ -359,7 +361,7 @@ const UNIT_LITERAL_ALLOWLIST: Record<
lines: 1,
reason: "the legacy export endpoint's canonical storage-unit contract",
},
"app/api/measurements/series/route.ts": {
"lib/measurements/series/kinds.ts": {
lines: 4,
reason:
"canonical wire units; glucose is overridden to the reader's unit per request",
@@ -512,7 +514,7 @@ const READER_UNIT_PRODUCERS = [
"lib/ai/prompts/weight.ts",
"lib/insights/features-units.ts",
"lib/insights/comprehensive-generate.ts",
"app/api/insights/generate/route.ts",
"lib/insights/briefing-request/features.ts",
"lib/insights/weight-status.ts",
"lib/insights/metric-status.ts",
"lib/insights/narrative/period-narrative.ts",
@@ -48,7 +48,8 @@ const PICKER_CALLERS = ["lib/workouts/canonical-read.ts"];
* acknowledgement. The value is the file that owns the read's `select`.
*/
const IDENTITY_OWNER: Record<string, string> = {
"app/api/workouts/[id]/route.ts": "app/api/workouts/[id]/route.ts",
// The workout detail read behind `GET /api/workouts/{id}`.
"lib/workouts/detail.ts": "lib/workouts/detail.ts",
"lib/jobs/workout-insight-generate.ts":
"lib/jobs/workout-insight-generate.ts",
"lib/workouts/list-read.ts": "lib/workouts/list-read.ts",