mirror of
https://github.com/MBombeck/HealthLog.git
synced 2026-11-08 20:42:43 +00:00
chore(release): v1.39.0 — AI becomes optional, and a switched-off module leaves the whole app
This commit is contained in:
1 parent
53bd7098da
commit
ecfa837dea
4 files changed
+284
-3
No files matched your search
+281
@@ -1,5 +1,286 @@
|
||||
# Changelog
|
||||
|
||||
## [1.39.0] — 2026-09-25
|
||||
|
||||
AI is optional everywhere now: your data loads whatever the AI settings
|
||||
say, and each AI switch stops the work it names instead of hiding it. A
|
||||
module you switch off leaves the whole app, and there are fixes for
|
||||
heart-rate streams, charts, the cycle calendar and labs.
|
||||
|
||||
### Added
|
||||
|
||||
- **The weight tile judges a change against your own target.** Below your
|
||||
target band a gain counts as progress, above it a loss does, and inside
|
||||
the band staying steady is progress while a small move either way is
|
||||
shown neutrally. The weight note, the daily briefing, the overview
|
||||
analysis and the Coach know the target too, and changing the target
|
||||
refreshes the weight note without a new weigh-in. Without a target the
|
||||
tile works as before. Thanks to @COBO5671 for #1006 and the screenshots.
|
||||
- **A document can be linked to every visit and vaccination it covers.**
|
||||
The document's own view in the vault lists the visits and vaccination
|
||||
doses it belongs to and lets you add or remove them, so a childhood
|
||||
vaccination record can be filed against every dose it lists in a few
|
||||
taps. Links made from either side are the same links. Thanks to @Cnote43
|
||||
for #1024 and @CritLoren for #1005.
|
||||
- **The vaccination page shows the booster you planned.** Next to each
|
||||
vaccine's heading it says when the next booster is due, marked once it
|
||||
is due within a month and again once it is overdue. The app shows the
|
||||
boosters you planned and does not work out dates of its own (#1005).
|
||||
- **A new "Reading documents" switch for people who run a server.** It
|
||||
sits under Admin, Coach and covers AI reading of stored documents,
|
||||
lab report scans and turning a typed medication description into a
|
||||
schedule. It is on by default.
|
||||
- **Reading documents has its own consent.** Sending a document, a lab
|
||||
scan or a medication description to an AI service outside your server
|
||||
now needs consent for reading documents, including with your own OpenAI
|
||||
or Anthropic key or your own ChatGPT account. A self-hosted model needs
|
||||
none. The app asks at the place you start the read and grants exactly
|
||||
that; the consent has its own withdraw button in Settings, AI. It does
|
||||
not open the Coach or AI analysis, and consent for AI analysis alone
|
||||
does not cover documents. A full AI consent given before this release
|
||||
still covers both.
|
||||
- **What the Coach stored stays yours with the Coach off.** Your
|
||||
conversations, the facts it remembered, your plans and the reminders you
|
||||
asked it to keep can be read and deleted in Settings whether the Coach
|
||||
is switched off on the server, hidden by you, or has no provider.
|
||||
Confirming, finishing or moving a plan or reminder waits until the Coach
|
||||
is back.
|
||||
- **One short hint instead of a message on every card.** While no AI
|
||||
provider is set up and you could set one up, Insights and Settings, AI
|
||||
show a single note that AI is optional, with a way to set it up and a
|
||||
"Not now" that hides it on both pages. With AI switched off on the
|
||||
server, setup and the getting-started list do not bring AI up.
|
||||
|
||||
### Changed
|
||||
|
||||
- **Your data never depends on AI.** Readings, charts, scores,
|
||||
correlations, ECG recordings, heart rhythm events, the breathing and
|
||||
lab-change cards, intraday pulse and the baseline strip on each metric
|
||||
page load the same with AI on or off, with or without a provider, and
|
||||
with or without your consent. Apple Watch ECG uploads are
|
||||
stored in every case. Before, several of these reads sat behind AI
|
||||
switches, and the Insights overview could fail with "Failed to load
|
||||
insights". Thanks to @CritLoren for the log in #975.
|
||||
- **AI parts are left out when AI is off for you.** The daily briefing,
|
||||
the sentence under your greeting and under the trend charts, the notes
|
||||
on metric pages, lab markers and workouts, the line after a new reading,
|
||||
the Coach button and menu entry, and the "describe it in words" button
|
||||
in the medication wizard only appear while they can work. Text a model
|
||||
wrote earlier is hidden from the next page load and returns when AI is
|
||||
back; a switch or a missing provider deletes nothing. A summary the app
|
||||
composed from your numbers alone is not AI text and stays.
|
||||
- **Nothing is written by a model at night unless AI is on for you.** The
|
||||
nightly briefing, status notes, period summaries, arrival lines, workout
|
||||
notes and Coach memory upkeep now check the server's switches, your AI
|
||||
analysis switch, your provider and your consent for each person as the
|
||||
run reaches them. Switching AI off during a nightly run stops the rest
|
||||
of that run, and a reply that arrives after you withdrew consent is
|
||||
thrown away. Week and month summaries still appear, written from your
|
||||
numbers, and Coach nudges arrive in their plain form when only consent
|
||||
is missing.
|
||||
- **The assistant switches stop AI work instead of hiding it.** When a
|
||||
switch in Admin, Coach is off, nothing it covers is sent to a model,
|
||||
and that now includes document reading, lab scans and medication text,
|
||||
which the switches used to leave running. A read queued before the
|
||||
switch was turned off stops when it runs. "Status cards" is renamed
|
||||
"Status notes". If the server cannot read the switches for a moment,
|
||||
every AI feature stays off for that request.
|
||||
- **The Coach has one switch for people who run a server.** It is the
|
||||
Coach switch under Admin, Coach. The Coach row under module
|
||||
availability now follows it and links to it; an operator who had turned
|
||||
the Coach module off there has the Coach switch turned off.
|
||||
- **The "Insights" module is now "AI analysis".** It decides whether a
|
||||
model writes the briefing, status notes and workout notes for you. With
|
||||
it off, the Insights tab stays in the menu and the bottom bar, and the
|
||||
Today summary and the readiness, recovery and sleep score rings stay on
|
||||
the dashboard. Breathing screening now follows the Sleep module and
|
||||
"What changed since your last panel" follows the Labs module.
|
||||
- **Hiding the Coach hides only the Coach.** It used to stop the nightly
|
||||
briefing and status notes as well, which the setting never said. If you
|
||||
had the Coach hidden, AI analysis is switched off for you in this
|
||||
release so nothing new is written; switch it back on under Settings,
|
||||
Modules if you want the notes.
|
||||
- **The morning briefing notification keeps coming with AI analysis
|
||||
off.** It carries your health score or the day's reminders without the
|
||||
first sentence a model would have written.
|
||||
- **Someone managing your record sees the stored AI text you would see.**
|
||||
Your briefing, notes and summaries show for them whenever they show for
|
||||
you, but opening your record never starts AI work on it.
|
||||
- **Coach reminders wait while the Coach is unavailable.** They were
|
||||
surfaced into a conversation nobody could open and dismissed after a few
|
||||
unanswered rounds. They now wait and appear once the Coach is back.
|
||||
- **Withdrawing AI consent deletes the notes written under it.** When no
|
||||
consent for AI analysis is left, the status notes, the daily briefing,
|
||||
the model-written period summaries, the arrival lines and the workout
|
||||
notes are deleted in the same step. Your Coach conversations, the facts
|
||||
it remembered, your plans and reminders, and your document summaries are
|
||||
your records and stay. The confirmation says which of these applies to
|
||||
you. When the consent card cannot read your consent, it says so with a
|
||||
retry instead of showing it as withdrawn.
|
||||
- **Switching a module off removes it everywhere.** Mood, Sleep, Labs and
|
||||
the other modules now leave the Insights tabs, the trends row on the
|
||||
overview, the add menu (including the measurement types they own, such
|
||||
as sleep and glucose), the dashboard tiles, the overview layout settings
|
||||
and the score rings. The trends row moves on to the next chart so it
|
||||
still shows three.
|
||||
- **Correlations only use what you track.** The pattern finder, and the
|
||||
patterns the Coach, the status notes and the weekly and monthly review
|
||||
look at, leave out mood, sleep, glucose, medication adherence, symptoms,
|
||||
weather or lab results once that module is off. Turning it back on
|
||||
brings them back, and patterns you had dismissed stay dismissed. Because
|
||||
fewer pairs are checked, a weak pattern between two things you still
|
||||
track can appear or disappear when you switch a module.
|
||||
- **A link to a switched-off page says why.** A bookmark to a page whose
|
||||
module is off shows a short notice with a button to Settings, Modules
|
||||
when the switch is yours. When the page is outside what someone shared
|
||||
with you or the server turned the module off for everyone, it says so
|
||||
and leaves the button out. The Nutrients page uses the same notice and
|
||||
its own "turn on" button is gone.
|
||||
- **Clearer messages when AI is refused.** The Coach, document reading,
|
||||
lab scans and the medication reader tell a missing consent, AI switched
|
||||
off on the server, a record someone shared with you and a missing
|
||||
provider apart. A spent daily budget in the medication reader no longer
|
||||
shows "too many requests". Settings, AI names what the server has
|
||||
switched off, and "Test connection" says AI is off on this server
|
||||
instead of calling the model or showing an error code.
|
||||
- **Status notes live in their own encrypted storage.** They used to be
|
||||
kept as plain text in the audit log. They are now encrypted like the
|
||||
rest of your health data, covered by key rotation, left out of backups
|
||||
because they are rebuilt each night, and removed by "Delete All Data".
|
||||
- **A year of per-minute heart rate reads in about half the time** when a
|
||||
chart asks for it.
|
||||
- **If you write against the API**, `GET /api/auth/me` gains
|
||||
`ai: { capabilities, provider }`, which says per feature and for the
|
||||
record in use whether AI is available and why not. Routes that serve
|
||||
data no longer answer `403` for an AI reason; routes that mix data with
|
||||
model text answer `200` with the model text as `null` and an `ai` object
|
||||
giving the reason. This covers `GET /api/insights/comprehensive`,
|
||||
`/api/insights/derived`, `/api/insights/narrative`, the status note
|
||||
routes, `/api/workouts/{id}`, `/api/daily/digest` and
|
||||
`/api/dashboard/snapshot`, among others. AI refusals carry
|
||||
`meta.errorCode` with `meta.capability`, `meta.reason` and, where it
|
||||
applies, `meta.module`; the new codes are `ai.record.notPermitted`,
|
||||
`ai.provider.none` and `ai.unavailable`. Document reading, lab scans and
|
||||
medication text refuse with `assistant.disabled.documentAi`, and
|
||||
`/api/insights/generate` with `assistant.disabled.briefing` instead of
|
||||
`assistant.disabled.coach`. The consent routes accept a new kind,
|
||||
`ai_extraction`. `aiAvailable` on `GET /api/user/ai-provider` is false
|
||||
while the master switch is off, and every card from
|
||||
`GET /api/insights/cards` says `provider: "rules"`.
|
||||
- **More for API clients.** New additive fields are
|
||||
`tiles.weightTrend` on `GET /api/dashboard/snapshot` (`direction` is
|
||||
`up-good`, `up-bad` or the new `hold`), `renewals` on
|
||||
`GET /api/vaccinations`, `vaccinationLinks` on
|
||||
`GET /api/documents/inbound/{id}` and `vaccinationIds` on its `PATCH`,
|
||||
and `cycleDay` and `periodEndable` on each day of
|
||||
`GET /api/cycle/calendar`. `GET /api/medications/{id}/dose-history`
|
||||
reports `from` as the requested start rather than the medication's
|
||||
creation time. `GET /api/auth/me` reports the server's default time
|
||||
zone when the stored one cannot be used.
|
||||
|
||||
### Removed
|
||||
|
||||
- **The "Correlations" assistant switch.** It only ever turned off
|
||||
statistics, which no model writes, so correlations now always load.
|
||||
|
||||
### Fixed
|
||||
|
||||
- **The worker no longer runs out of memory on a watch that streams heart
|
||||
rate.** On an account with heart rate every minute or faster, the worker
|
||||
grew until it crashed with "JavaScript heap out of memory" within 15 to
|
||||
40 minutes, because the heart-rate status card read three months of
|
||||
readings one by one. The card and the other background summaries,
|
||||
including the Coach's cycle summary, now read one total per day. If you
|
||||
raised `NODE_OPTIONS=--max-old-space-size` to keep the worker up, you
|
||||
can leave it or remove it. Thanks to @ckaotik for the report, the logs
|
||||
and the patient testing in #1023.
|
||||
- **Daily totals stay on the same day across chart ranges.** Steps,
|
||||
active energy, flights climbed and walking distance could move to the
|
||||
neighbouring day between the 7-day and 30-day ranges, because the longer
|
||||
ranges cut days at midnight UTC. Every range of single days, up to a
|
||||
year, now cuts them at your own midnight; longer ranges still group
|
||||
weeks, months and years by UTC days. Thanks to @mills1975 for #1026 and
|
||||
the screenshots.
|
||||
- **The 7-day chart shows the whole week on a streaming source.** It read
|
||||
individual readings up to a limit that per-minute heart rate reaches
|
||||
after about three and a half days. Every range now reads one value per
|
||||
day, and the 7-day and 30-day ranges agree (#1026).
|
||||
- **Charts on the medication page, in the Coach and in recovery use your
|
||||
time zone.** They cut days in Berlin for everyone. When a stored time
|
||||
zone cannot be used, the server and the app both fall back to the
|
||||
server's default. A bare offset such as `+05:30` is no longer accepted
|
||||
as a time zone, because the database would cut days on the wrong side of
|
||||
UTC; pick a named zone such as Asia/Kolkata (#1026).
|
||||
- **Recent doses appear under "Last 90 days" in a medication's history.**
|
||||
A dose logged for a time before the medication was added, a dose taken
|
||||
shortly before its scheduled time, and a dose added while the tab was
|
||||
open were missing until later or until a reload. Thanks to
|
||||
@sreeramachandramurthy for #1028 and for spotting the time pattern.
|
||||
- **Past dates in the cycle calendar show their own cycle day.** The log
|
||||
sheet labelled any date with today's cycle day, and "My period ended
|
||||
this day" only appeared while today was a period day. It now shows the
|
||||
day of the cycle the date belongs to and offers the period end on the
|
||||
first days of any logged cycle. Thanks to @sreeramachandramurthy for
|
||||
#1004 and the step-by-step notes.
|
||||
- **Save in the cycle log needs something to save.** An empty Save stored
|
||||
an empty entry the calendar could not show, which looked like a failed
|
||||
save. It now asks you to pick a flow, a symptom or another sign (#1004).
|
||||
- **Cycle history entered out of order lands on the same cycles.**
|
||||
Logging the second day of a period before the first no longer opens a
|
||||
separate one-day cycle; the earlier day becomes the start, and days
|
||||
logged before a back-filled start move to the right cycle. If you
|
||||
already have such a one-day cycle, open the real first day and tap "My
|
||||
period started this day" again. A start tapped by mistake a few days
|
||||
early can be removed again, and the start it replaced comes back
|
||||
(#1004).
|
||||
- **Selecting a cycle symptom no longer moves the list.** Symptoms are one
|
||||
per line with the optional 1 to 4 intensity beside them. Thanks to
|
||||
@sreeramachandramurthy for #1001.
|
||||
- **Labs "Save and add another" keeps your biomarker.** The second save
|
||||
said "Pick a biomarker first" although one was shown. The form now keeps
|
||||
the biomarker, the date and the visit and clears only the value and its
|
||||
note. Thanks to @sreeramachandramurthy for #1029.
|
||||
- **Manual entry has the rest of the scale's readings.** Visceral fat, fat
|
||||
mass, fat-free mass, lean body mass and muscle mass can be entered by
|
||||
hand, in kilograms or pounds as you set. French, Italian and Polish
|
||||
labels that gave two of these one name are distinct. Thanks to @ocurero
|
||||
for #1013.
|
||||
- **The "Link a document" picker offers your whole vault.** It said "No
|
||||
documents yet." on vaccinations and visits even with a full vault,
|
||||
because it asked for more documents per page than the server accepts.
|
||||
Documents dated within a week come first, the rest are listed by month
|
||||
and searchable, and a failed load shows a retry. The condition picker on
|
||||
visits had the same problem (#1024, #1005).
|
||||
- **The Insights overview no longer fails as a whole.** Each section loads
|
||||
on its own and a failed one offers a retry. "Today's signal", the heart
|
||||
rhythm events and the mood patterns card say when they could not load
|
||||
instead of hiding or spinning, a score page no longer says "not enough
|
||||
data" when it could not read the score, and with the cycle module on but
|
||||
no cycle in progress the scores row no longer leaves a gap (#975).
|
||||
- **Restoring instance settings from a backup made before this release
|
||||
keeps the Coach off** when the backup had the Coach module switched off.
|
||||
|
||||
### Upgrade notes
|
||||
|
||||
- **Take a database backup before upgrading.** Three migrations run.
|
||||
`0343` adds the "Reading documents" switch, moves the old Coach module
|
||||
setting into the Coach switch, switches AI analysis off for everyone who
|
||||
had the Coach hidden and removes the Correlations switch. It cannot be
|
||||
undone automatically; going back to an earlier version means restoring
|
||||
that backup. `0344` creates the encrypted status note storage and
|
||||
deletes the old status note rows from the audit log without copying
|
||||
them, so the next night writes every note again, about one normal night
|
||||
of extra model use. `0345` adds one column to cycle starts and changes
|
||||
nothing else.
|
||||
- **The Correlations switch is gone** from Admin, Coach. Correlations
|
||||
always load now.
|
||||
- **`GET /api/feature-flags` is deprecated.** It still answers, with a
|
||||
`Deprecation` header pointing to `GET /api/auth/me`, and the web app no
|
||||
longer reads it. The iPhone app and other clients should read `ai` on
|
||||
`GET /api/auth/me` instead, expect `200` with `null` model text on the
|
||||
mixed reads listed under Changed, and handle the three new error codes.
|
||||
The route is removed in the first release after the next iPhone app.
|
||||
|
||||
## [1.38.25] — 2026-09-20
|
||||
|
||||
Three readings that never arrived, and one import that turned away a
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
openapi: 3.1.0
|
||||
info:
|
||||
title: HealthLog API
|
||||
version: 1.38.25
|
||||
version: 1.39.0
|
||||
description: >-
|
||||
Self-hosted personal-health-tracking PWA — public API surface for the iOS native client and external ingest.
|
||||
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "healthlog",
|
||||
"version": "1.38.25",
|
||||
"version": "1.39.0",
|
||||
"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",
|
||||
|
||||
+1
-1
@@ -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.38.25";
|
||||
/* @sw-version-fallback */ "v1.39.0";
|
||||
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/*`
|
||||
|
||||
Reference in new issue
Block a user