chore(release): fold in the coach discriminant, the dependency bumps, and the notes the audit found wrong

This commit is contained in:
Marc-André Bombeck committed 2026-07-26 18:57:21 +02:00
1 parent 5a71f376d4
commit 4be01a67f0
22 files changed
+252 -489

No files matched your search

+1 -1
View File
@@ -35,7 +35,7 @@ jobs:
COACH_EVAL_API_KEY: ${{ secrets.COACH_EVAL_API_KEY }}
steps:
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- uses: pnpm/action-setup@0ebf47130e4866e96fce0953f49152a61190b271 # v6.0.9
+1 -1
View File
@@ -12,7 +12,7 @@ jobs:
if: github.actor == 'dependabot[bot]'
steps:
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- uses: pnpm/action-setup@0ebf47130e4866e96fce0953f49152a61190b271 # v6.0.9
+4 -4
View File
@@ -46,7 +46,7 @@ jobs:
contents: read
steps:
- name: Checkout full history
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
fetch-depth: 0
@@ -129,7 +129,7 @@ jobs:
steps:
- name: Checkout
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@bb05f3f5519dd87d3ba754cc423b652a5edd6d2c # v4.2.0
@@ -150,7 +150,7 @@ jobs:
# Image is built but not pushed in that case.
- name: Log in to GitHub Container Registry
if: github.event_name != 'pull_request'
uses: docker/login-action@af1e73f918a031802d376d3c8bbc3fe56130a9b0 # v4.4.0
uses: docker/login-action@abd2ef45e78c5afb21d64d4ca52ee8550d9572c7 # v4.5.1
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
@@ -350,7 +350,7 @@ jobs:
echo "IMAGE_REF=${REGISTRY}/${IMAGE_NAME,,}" >> "$GITHUB_ENV"
- name: Log in to GitHub Container Registry
uses: docker/login-action@af1e73f918a031802d376d3c8bbc3fe56130a9b0 # v4.4.0
uses: docker/login-action@abd2ef45e78c5afb21d64d4ca52ee8550d9572c7 # v4.5.1
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
+1 -1
View File
@@ -45,7 +45,7 @@ jobs:
NODE_ENV: production
steps:
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- uses: pnpm/action-setup@0ebf47130e4866e96fce0953f49152a61190b271 # v6.0.9
+1 -1
View File
@@ -25,7 +25,7 @@ jobs:
timeout-minutes: 5
steps:
- name: Checkout
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- name: Install pnpm
uses: pnpm/action-setup@0ebf47130e4866e96fce0953f49152a61190b271 # v6.0.9
+1 -1
View File
@@ -14,7 +14,7 @@ jobs:
runs-on: ubuntu-latest
timeout-minutes: 15
steps:
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- uses: pnpm/action-setup@0ebf47130e4866e96fce0953f49152a61190b271 # v6.0.9
+1 -1
View File
@@ -16,7 +16,7 @@ jobs:
timeout-minutes: 10
steps:
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- uses: pnpm/action-setup@0ebf47130e4866e96fce0953f49152a61190b271 # v6.0.9
+1 -1
View File
@@ -19,7 +19,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- name: Scan src/ for TODO/FIXME/XXX/HACK markers
run: |
+1 -1
View File
@@ -71,7 +71,7 @@ jobs:
steps:
- name: Log in to GHCR
uses: docker/login-action@af1e73f918a031802d376d3c8bbc3fe56130a9b0 # v4.4.0
uses: docker/login-action@abd2ef45e78c5afb21d64d4ca52ee8550d9572c7 # v4.5.1
with:
registry: ghcr.io
username: ${{ github.actor }}
+4 -4
View File
@@ -15,7 +15,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- uses: pnpm/action-setup@0ebf47130e4866e96fce0953f49152a61190b271 # v6.0.9
@@ -66,7 +66,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- uses: pnpm/action-setup@0ebf47130e4866e96fce0953f49152a61190b271 # v6.0.9
@@ -91,7 +91,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
fetch-depth: 0
@@ -106,7 +106,7 @@ jobs:
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
steps:
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- name: Build Docker image
run: docker build -t healthlog:scan .
+19 -8
View File
@@ -25,6 +25,11 @@ including a connection that had already been parked for a dead credential. A
failing connection now shows how long it has been failing, escalates after a
day, and stops retrying after two with a reconnect button.
One limit worth naming rather than leaving to be discovered: the ledger
remembers a single failing part per provider. If two parts fail at overlapping
times, the recovery of the later one still clears the error of the earlier. That
is narrower than the case this fixes, and it is not closed.
**The Environment module had never once saved a row, for anyone.** One
declaration in 49 was missing the line that maps it to the database, so every
write referred to a type that does not exist. The job failed every night and
@@ -38,8 +43,7 @@ backfill button covers the rest.
left two overlapping in-bed periods, and both were added. One night read ten
hours in the headline and twenty in the legend. The same fault inflated the
time-asleep figure itself. Every stage total is now the measure of its own
period rather than the sum of overlapping ones. Naps are also now told apart
from the main sleep everywhere a person reads them, not just in the export.
period rather than the sum of overlapping ones.
**Twenty-two controls could destroy something without asking.** Among them a
single tap that cleared the allergy list along with a text note, and a switch
@@ -77,8 +81,12 @@ see which before you import. Seven status values are ruled on individually: only
notification is counted and named rather than turned into a decision you never
made.
Behavioural patterns now cover alcohol against next-day recovery and resting
heart rate. The statistics for it were already in the app.
The Coach can tell "you never recorded this" apart from "you recorded it, but
outside the range I looked at". Someone with 1,597 imported glucose readings
from April 2024 was told there was no glucose data at all, and the Coach then
changed the subject, because one reason code covered both situations and the
instruction to move on fired on both. It now says what is actually true and
offers to look further back.
### For operators
@@ -89,10 +97,13 @@ inventory that was wrongly expired. None deletes or rewrites a measurement.
### Credit
Reported by @lutzkind (sleep double-counting, the gender contract, the
Environment enum, and a run of earlier reports), @Nazza01 (the intake import,
plus the export file and the format documentation that made reading it
possible), @DrGithubble (the unit and precision work that led here) and @doenke
(the measurement table, narrowed by the reporter into something buildable).
Environment enum, the Coach retrieval window, and a run of earlier reports),
@Nazza01 (the intake import, plus the export file and the format documentation
that made reading it possible) and @DrGithubble (the unit and precision work
that led here).
@doenke's measurement table is not in this release. An earlier draft of these
notes said it was and credited him for it, which was wrong on both counts.
Two of these defects were found because someone outside this project read the
code and said what was wrong. The Environment module had been broken for every
+5 -5
View File
@@ -77,13 +77,13 @@
"jose": "^6.2.3",
"jspdf": "^4.2.1",
"jspdf-autotable": "^5.0.8",
"lucide-react": "^1.18.0",
"lucide-react": "^1.27.0",
"mmdb-lib": "^3.0.2",
"next": "16.2.11",
"next-themes": "^0.4.6",
"nodemailer": "9.0.3",
"otpauth": "^9.5.1",
"p-limit": "^7.3.0",
"p-limit": "^7.3.1",
"pg-boss": "^12.26.0",
"prisma": "^7.8.0",
"qrcode": "^1.5.4",
@@ -92,7 +92,7 @@
"react-day-picker": "^10.0.1",
"react-dom": "19.2.7",
"react-hook-form": "7.81.0",
"recharts": "^3.8.1",
"recharts": "^3.10.1",
"rrule": "^2.8.1",
"sax": "^1.6.0",
"sonner": "^2.0.7",
@@ -107,7 +107,7 @@
},
"devDependencies": {
"@axe-core/playwright": "^4.12.1",
"@next/bundle-analyzer": "^16.2.9",
"@next/bundle-analyzer": "^16.2.12",
"@playwright/test": "^1.60.0",
"@tailwindcss/postcss": "^4",
"@testcontainers/postgresql": "^12.0.3",
@@ -118,7 +118,7 @@
"@types/react": "^19",
"@types/react-dom": "^19",
"@types/web-push": "^3.6.4",
"@vitejs/plugin-react": "^5.1.4",
"@vitejs/plugin-react": "^6.0.4",
"@vitest/coverage-v8": "^4.1.5",
"eslint": "^9",
"eslint-config-next": "16.2.6",
+195 -447
View File
File diff suppressed because it is too large. Load diff
+4
View File
@@ -21,3 +21,7 @@ allowBuilds:
ssh2: false
tesseract.js: false
unrs-resolver: false
minimumReleaseAgeExclude:
- "@next/bundle-analyzer@16.2.12"
- lucide-react@1.27.0
+6 -6
View File
@@ -1774,7 +1774,7 @@ model Measurement {
// user_id` an index-only scan that converges to empty. Same partial-predicate
// reason it is omitted here.
// `measurements_tombstone_purge_idx` is a partial index over `(deleted_at)
// WHERE deleted_at IS NOT NULL` — see migration 0277 (v1.32.40). Every
// WHERE deleted_at IS NOT NULL` — see migration 0276 (v1.33.0). Every
// other deleted_at index here is partial on IS NULL, which is the live-rows
// predicate and the opposite of what the nightly tombstone purge asks for;
// without this one the purge planned a sequential scan and could not finish
@@ -2871,7 +2871,7 @@ model MedicationIntakeEvent {
@@index([userId, scheduledFor])
@@index([userId, medicationId, takenAt])
// `medication_intake_events_tombstone_purge_idx` is a partial index over `(deleted_at)
// WHERE deleted_at IS NOT NULL` — see migration 0277 (v1.32.40). Every
// WHERE deleted_at IS NOT NULL` — see migration 0276 (v1.33.0). Every
// other deleted_at index here is partial on IS NULL, which is the live-rows
// predicate and the opposite of what the nightly tombstone purge asks for;
// without this one the purge planned a sequential scan and could not finish
@@ -3888,7 +3888,7 @@ model MoodEntry {
// (v1.28.46 H4), serving the note-encryption boot-discovery scan. Raw SQL
// only (partial predicate not expressible in Prisma).
// `mood_entries_tombstone_purge_idx` is a partial index over `(deleted_at)
// WHERE deleted_at IS NOT NULL` — see migration 0277 (v1.32.40). Every
// WHERE deleted_at IS NOT NULL` — see migration 0276 (v1.33.0). Every
// other deleted_at index here is partial on IS NULL, which is the live-rows
// predicate and the opposite of what the nightly tombstone purge asks for;
// without this one the purge planned a sequential scan and could not finish
@@ -4329,10 +4329,10 @@ model AuditLog {
// this three-column index serves both the findFirst and the take:5 as
// an index range scan over the highest-churn table. See migration 0123.
@@index([userId, action, createdAt(sort: Desc)])
// v1.32.40 — the retention purge filters on `createdAt` alone. Every index
// v1.33.0 — the retention purge filters on `createdAt` alone. Every index
// above leads with `userId` or `action`, so the purge planned a sequential
// scan and could not finish inside statement_timeout on an instance with
// enough history. See migration 0277.
// enough history. See migration 0276.
@@index([createdAt])
@@map("audit_logs")
}
@@ -4487,7 +4487,7 @@ model ImportJob {
model MedicationIntakeImportJob {
id String @id @default(cuid())
userId String @map("user_id")
/// v1.32.40 (migration 0276) — nullable. The per-medication import route
/// v1.33.0 (migration 0278) — nullable. The per-medication import route
/// scopes its job to one medication and names it here. A dose history
/// exported from another tracker covers a whole regimen in one file — the
/// reported export named sixteen medications across 3,395 rows — so that job
@@ -363,7 +363,7 @@ const REGISTRY: DestructiveEntry[] = [
{
file: "components/records/allergy-manager.tsx",
destroys: "one allergy record",
recovery: "tombstoned-no-restore",
recovery: "permanent",
confirm: ["DeleteButton"],
},
{
@@ -16,7 +16,7 @@ vi.mock("@/lib/ai/coach/snapshot", () => ({
buildCoachSnapshot(userId, scope),
}));
// v1.32.40 (#648) — an empty window read is no longer reported as absence until
// v1.33.0 (#648) — an empty window read is no longer reported as absence until
// the availability probe has confirmed the record is empty. Stub the probe's
// reads to "nothing stored", which is what these dispatch assertions mean by an
// absent section; `coach-availability-window-honesty.test.ts` owns the other
+1 -1
View File
@@ -31,7 +31,7 @@ export function getAuditLogRetentionDays(): number {
/**
* Delete audit rows past the retention horizon, in bounded batches.
*
* Until v1.32.40 this was one unbounded `deleteMany` on `created_at < cutoff`.
* Until v1.33.0 this was one unbounded `deleteMany` on `created_at < cutoff`.
* Every index on the table leads with `user_id` or `action`, so the predicate
* had none and the statement planned a sequential scan plus index maintenance
* on every removed row. Past the 60-second `statement_timeout` that aborts and
@@ -32,7 +32,7 @@ function tombstoneCutoff(now: Date): Date {
* Hard-delete soft-deleted measurement rows whose `deletedAt` is older than
* the retention horizon.
*
* Batched. Until v1.32.40 this was one unbounded `deleteMany` over a predicate
* Batched. Until v1.33.0 this was one unbounded `deleteMany` over a predicate
* that no index supported, which meant a backlog large enough to exceed the
* 60-second `statement_timeout` could never be drained: the statement aborted,
* the transaction rolled back, and the next night ran the identical statement
+1 -1
View File
@@ -13,7 +13,7 @@
* it, and the job that was supposed to make deletion real never completes.
*
* The fix has three parts and this file is one of them:
* - the predicates get indexes that match them (migration 0277);
* - the predicates get indexes that match them (migration 0276);
* - the delete runs in bounded batches, so no single statement is on the
* hook for the whole backlog;
* - a run that stops at the cap says so, so "still draining" and "nothing
@@ -1,5 +1,5 @@
/**
* v1.32.40 — the retention purges have to be able to fail out loud.
* v1.33.0 — the retention purges have to be able to fail out loud.
*
* Both handlers used to catch every error into a wide-event warning and return
* normally. pg-boss then recorded a successful job, so a purge that aborted on
+1 -1
View File
@@ -185,7 +185,7 @@ export async function handleMeasurementTombstoneCleanup(
// v1.7.0 sync — prune tombstones across all three sync domains on
// the same retention horizon.
//
// v1.32.40 — sequential rather than parallel. Each leg now walks its
// v1.33.0 — sequential rather than parallel. Each leg now walks its
// backlog in batches, and three concurrent walks against the three
// densest tables competed for the worker pool for no gain: the job has
// the whole night.