From 81e564a724b085aa05c1ee01750928f9bb5fa50b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Bombeck?= Date: Sun, 19 Jul 2026 02:44:42 +0200 Subject: [PATCH] =?UTF-8?q?chore(release):=20v1.30.21=20=E2=80=94=20dose?= =?UTF-8?q?=20reminders=20land=20on=20the=20right=20hour=20across=20a=20cl?= =?UTF-8?q?ock=20change?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGELOG.md | 11 +++++++++++ docs/api/openapi.yaml | 2 +- package.json | 2 +- public/sw.js | 2 +- 4 files changed, 14 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0b88eef28..ef32706f0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,17 @@ ## [Unreleased] +## [1.30.21] — 2026-07-19 + +Dose reminders land on the right hour across a clock change. + +- **A reminder on a clock-change day now fires at the time you set.** The conversion from your local time to a real instant read the timezone offset at the moment the scheduler happened to run, not at the time the dose was actually due. On the autumn change in a timezone that observes one, a 20:00 dose could resolve to 19:00 when the scheduler ticked before the change. Two days a year, and only in timezones that change their clocks — but a dose reminder should never be an hour off. Nothing stored changed; the same schedule now produces the correct instant. +- **A duplicate pending dose was possible on those same days.** The reminder projector, the worker and the intake write derived the instant separately and could disagree on the change day, which broke the matching that keeps them on one row. +- **The next-dose day label could show the wrong day** when your device timezone differs from the one in your profile, because the offset was applied twice. The two copies of that label — in the card and in the table — are now one. +- The tests could not have caught any of this: they used times with no timezone attached, so the day boundary could not be distinguished from a UTC one, and the suite ran only in one host timezone. They now state their timezone explicitly, cover both clock changes, and the suite is pinned to match the build. + +No breaking changes. + ## [1.30.20] — 2026-07-19 - **A restore now refuses when the backup file names a different account than the backup record.** The restore target was read from inside the encrypted file rather than from the record the operator selected, so a file claiming a different account would have been written into that account instead — while the audit entry recorded the one the operator picked. Both values were already available at that point; they are now compared, and a mismatch is refused and recorded with both. diff --git a/docs/api/openapi.yaml b/docs/api/openapi.yaml index 475928533..c7a4d8f5d 100644 --- a/docs/api/openapi.yaml +++ b/docs/api/openapi.yaml @@ -1,7 +1,7 @@ openapi: 3.1.0 info: title: HealthLog API - version: 1.30.20 + version: 1.30.21 description: >- Self-hosted personal-health-tracking PWA — public API surface for the iOS native client and external ingest. diff --git a/package.json b/package.json index e14f27017..c2d3b1d32 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "healthlog", - "version": "1.30.20", + "version": "1.30.21", "description": "Self-hosted personal-health-tracking PWA with Withings integration, AI insights, and doctor-report PDF export.", "license": "PolyForm-Noncommercial-1.0.0", "homepage": "https://healthlog.dev", diff --git a/public/sw.js b/public/sw.js index 6cd992933..bdb572686 100644 --- a/public/sw.js +++ b/public/sw.js @@ -36,7 +36,7 @@ try { // v1.4.38.4 → v1.4.42. Do not hand-edit; bump `package.json` and rebuild. const CACHE_VERSION = (typeof self !== "undefined" && self.__APP_VERSION__) || - /* @sw-version-fallback */ "v1.30.20"; + /* @sw-version-fallback */ "v1.30.21"; const STATIC_CACHE = `healthlog-static-${CACHE_VERSION}`; const PAGE_CACHE = `healthlog-pages-${CACHE_VERSION}`; // v1.18.6 — read-only data cache for a curated allowlist of safe GET `/api/*`