mirror of
https://github.com/MBombeck/HealthLog.git
synced 2026-11-13 22:32:04 +00:00
Merge branch 'release/v1.46.0' into feat/v146-ui
This commit is contained in:
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",
|
||||
],
|
||||
},
|
||||
|
||||
@@ -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",
|
||||
|
||||
Reference in new issue
Block a user