/topics shows a tile per topic the record holds data for, and names the
empty topics and the module-hidden ones once each. /topics/<topic>
shows the topic today, its signals side by side over 7, 30, 90 days or
a year against their usual range, how they move together, their trends,
its blocks, the single-metric pages behind it and what it is missing.
Every topic links into the metric pages, which stay as they are, and
each page ends on a neutral note that this is a preview.
Settings > System > Preview features is listed again and switches the
area on for the person reading. While it is on, the sidebar carries a
Topics entry with a Beta badge directly below Insights and the phone's
More sheet leads with a Topics tile; the bottom bar does not change.
The pages leave for Insights when the switch is off.
The charts load through the shared chart runtime. The sidebar rows move
into their own module and the More sheet tile into its own component,
so neither shell file grows; the lab trend wording is shared between the
marker page and the metabolism topic. Copy in all nine locales.
The report data counts, per screener score type, how many of the
window's results were answered in a translation that has not been
validated (`screenerUnvalidatedTranslations`, read only when a screener
total is in the report). The PDF marks such a row with an asterisk and
says under the vitals table how many of how many read as orientation;
the clinician share view says the same under the row.
To keep the aggregator and the PDF section from growing, the wellness
summary and the per-context glucose rows move into helpers; the size
ratchets only fall.
The PHQ-9, GAD-7, WHO-5 and SCI now have text in every app language
instead of falling back to the English original. Each instrument and
language is one file under src/lib/mental-health/wording/ that declares
what it is: a published validated translation reproduced word for word,
with its source and terms in `source`, or a translation written for
HealthLog, faithful to the English and on the same scale.
Validated versions added: the Pfizer PHQ-9 for France, the Netherlands,
Korea and Brazil, the Pfizer GAD-7 for the Netherlands, Korea and
Brazil, the PRU Dutch WHO-5, the Korean WHO-5 validation (J Korean Geriatr Psychiatry 2010) and
the Polish SCI validation (Sci Rep 2026). The SCI in the other
languages and the WHO-5 in Brazilian Portuguese carry HealthLog's own
translation; each file names any validated version found and why it is
not used.
Where the text is unvalidated, the check-in shows a note that the result
is orientation and a one-tap switch to the English original. Each
language loads as its own chunk when a questionnaire surface needs it.
The item text, answers, stems and the PHQ-9 follow-up leave every message
bundle, so a translator never sees them; the i18n guard now requires that
no bundle carries them, and the registry test requires every instrument
in every language with the item count and anchor scores the scoring
expects. CONTRIBUTING explains where the wording lives and how to propose
a validated version.
axe 4.14 checks WCAG 2.5.3 (label in name), and the app frame failed it
on every page: the account link, the user menu and the day strip carried
an aria-label that left out their visible text. The same class sat in
the coverage meter, the score ring, medication links, instrument cards,
filter pills with a value set, cycle calendar days (named by an ISO
key), admin user and login rows, a few sort and action buttons, and the
French, Spanish, Italian and Polish weekday chips, whose abbreviations
were not part of the day names.
Controls with visible text are now named by it, with any extra purpose
added as screen-reader text; the select pill and calendar days spell
out a name that contains what they show. The day and conversation
strips keep their action as the tooltip.
Every instrument now runs the same wizard: the form's own question stem
above each item (the PHQ-9 and GAD-7 stems were missing), the item's
exact answer options as one radio group in source order, progress, Back,
number-key answers, and a review step that lists every answer, lets any
of them be changed and is the only step that submits. The result leads
with the crisis card when it applies, then shows the score on the
instrument's scale, the band, what the band means, the change since the
last check-in against the meaningful-change threshold, and the next
step. Scoring is untouched.
The wording was read against the published versions. German follows the
PHQ-D and Löwe's GAD-7 verbatim, including the follow-up question in its
published formal address. Spanish, Italian and Polish carry the official
PHQ-9 and GAD-7 translations, French the official GAD-7, and the GAD-7
gets its own answer set because the Italian forms word it differently.
Where a version could not be matched to a published form (the French
PHQ-9, every Korean form) the language now shows the English original.
Each locale list names its sources, and spot checks pin the corrected
wording.
The no-limit option promised every lab result, and the German detail
sentence ended on a dangling clause. The Coach keeps the latest value
of the most recently measured markers and, for a marker asked about,
its five previous results with older ones summarised per year for ten
years; years before that are only counted. Every language now says
that in complete sentences, with the two numbers pinned to the lab
history constants.
The app ships one Portuguese bundle, and pt-PT, pt-AO and bare pt all
fold into pt-BR, so a stored pt-BR does not mean Brazil. A positive
PHQ-9 item 9 still answered it with SAMU 192 as the emergency number
and CVV 188 as the only line, neither of which connects from Portugal,
under a comment claiming pt-PT kept the international set.
With no region signal, Portuguese now gets the DE_AT_CH treatment: 112
first, the worldwide directory, then CVV and SAMU labelled Brazil and
SNS 24 (808 24 24 24, option 4) and SOS Voz Amiga labelled Portugal.
An explicit pt-PT tag gets the Portugal set and br the Brazil set.
The PHQ-9, GAD-7 and WHO-5 are not validated in Dutch or Brazilian
Portuguese, and the SCI is validated in English only, yet the check-in
wizard and the answer breakdown read the item text, answer options and
stems through t() in the reader's language. Dutch and Brazilian
Portuguese readers saw unvalidated translations of every item,
including PHQ-9 item 9, under a note saying the questions were in
English.
Every surface now resolves instrument wording through instrumentText,
which returns the English source for a language outside the
instrument's validated set. The unvalidated wording is removed from
the bundles; the locale-parity check accepts exactly those keys as
absent and fails when a bundle carries one, and a structural test
keeps item text out of bare t() calls. The PHQ-9 follow-up question
regains its original wording. CONTRIBUTING states the rule for
translators.
next stays on main's 16.4.2 (the RCE and Server Actions advisories) with its two companions; release's newer dev tools and its own additions are kept. The lockfile is release's, re-resolved. pt-BR, which main does not have, takes the one key main added.
A Brazilian Portuguese reader who answered PHQ-9 item 9 saw the
international set: 112 and two directories. They now see CVV (Centro de
Valorização da Vida), 188 by phone and the chat at cvv.org.br, free and
answering around the clock, with SAMU's 192 as the emergency number.
Both were checked against cvv.org.br and the Ministry of Health's SAMU
page. A bare "pt" or "pt-PT" keeps the international set, because 188
does not connect from Portugal.
The CVV label is translated in every bundle, and a test pins that every
resource of every locale's set resolves its label in that locale.
Korean has no singular plural category, so the two ...One strings are
never chosen at run time, but they carried {count} where English writes
the number. They now read "1일 후" and "검사 수치 1개", which leaves no
placeholder that English lacks.
Since the explainer started naming the fasting bands in the reader's
glucose unit, the English, Dutch and Korean text states where normal,
prediabetes and diabetes begin and that one high reading is not a
diagnosis. The German, French, Spanish, Italian and Polish text kept
the older sentence without the bands or the caveat. They now carry
both, with the same placeholders as English.
Two badge and plan strings still carried the English text, and the
Coach plans description escaped its quotes twice, so the reader saw
\"se… então…\" with literal backslashes.
"Dose" stood for both the amount of a medication and the act of taking
it, so "Editar dose" could mean either, and the mechanical toma-to-dose
pass had turned two questions into "Com que frequência você dose?".
Where English says intake, the Brazilian strings now say "tomada"
(tomadas registradas, histórico de tomadas, editar tomada); "dose"
stays for the amount and where English itself says dose.
411 English keys had no Brazilian Portuguese string yet: the 135 that
were already missing when the translation was opened, and everything
v1.44 and v1.45 added since (the activity calendar, source provenance,
the lab and medication CSV import, the doctor-report workout and
medication-effect sections, the segmented medication-effect view, lab
trends and OCR outcomes, the mental-health trend lines, and the new
settings, integration and error strings). The bundle now has exactly
the English key set.
Terminology follows the existing catalogue: medicamento, exame,
treino, faixa de referência, chave de acesso, você.
38 strings used other placeholders than English: {when} for {date},
{provider} for {name}, a {unit} English dropped since, and the
integration-card, document-archive and Apple Health freshness lines lost
{since}, {list}, {relative} or {time} altogether, so the reader saw a
label where the sentence belonged. Most of those lines had been
translated from the key name ("Plano limitado", "Erros do provedor")
rather than from the English text; the whole of those sections is
translated from the source now, along with the Dawarich, glucose
reference, setup, re-confirmation and connector-token lines that had
the same problem, and the 19 strings whose English changed after the
translation was drafted.
The Telegram help documented "tomado <nome>", but the bot only accepts
"taken <name>"; it now shows the command the bot understands.
The pt-BR bundle carried 420 top-level sections that duplicated the
nested settings and onboarding keys (1,835 strings, of which 538 differed
from the nested copy), wrapped thresholds, gettingStarted and trendHints
in one-element arrays, and kept 48 keys English no longer has.
Rebuild it in en.json's order and shape: unwrap the arrays, drop the
stray top-level duplicates in favour of the nested copies (which match
the terminology of the rest of the catalogue), and drop keys English
does not have. No wording changes.
The provider's reasoning select reaches neither the Coach nor the
background jobs: the daily briefing thinks at Medium at most, lower under
the operator's cap, and not at all on the Frugal usage level. A line under
the select now says so, in every locale. Behaviour is unchanged.
Refs #1267
Dengue: Two doses three months apart and no booster. It's listed with the
travel vaccines.
Tuberculosis: One dose at birth and no booster. It's listed under childhood,
since that's where it appears on most vaccination cards.
Both cite the relevant WHO position paper. The names are translated in
all eight languages, and the OpenAPI spec is regenerated to include the
two new vaccines.
The Coach read lab results from the last twelve months only, even with
the lookback set to its widest option, so a slow change in LDL or PSA
across years stayed out of reach. Labs are sparse, so they are no
longer held to the one-year window that bounds the dense readings: they
reach back over the whole record, and a lookback limit the person set
still applies.
The snapshot block keeps the latest value per marker, now over that
wider window, at its old size: it shares the prompt's size cap and is
never shed. get_labs with an analyte adds each matching marker's
history, summarised so it stays bounded: the newest five earlier
readings in full and older ones as one mean / min / max / count per
year, ten years at most, older years counted. With a heavy fixture
(30 markers, quarterly for 20 years) the overview stays at 4.3k
characters and a named LDL read grows from 0.2k to 1.2k characters for
80 readings. The MCP get_labs read and the lab resource follow, since
they run the same tool.
The widest lookback option no longer reads "All": it names what it
reads, twelve months in detail and every lab result, in every locale.
Refs #1263
A batch that carried a type with duplicates only moved its
lastReceivedAt, lastTrigger and lastBackgroundAt, so a type whose live
delivery had stalled kept reading as freshly arrived for as long as a
replay, a retry or an older client re-sent its old samples.
The arrival ledger now moves those stamps only for a type the batch
brought at least one new or changed row for. An unchanged stats:
re-post and an hour posted again with its stored value count as
duplicates here; the wire keeps answering updated for them. A
duplicates-only type stamps the new last_seen_duplicate_at column on
its existing row and nothing else. The intake bulk route's dose entry
follows the same rule through the shared recorder. lastSyncedAt and
healthKitLastSyncedAt are unchanged.
GET /api/integrations/healthkit serves the stamp additively as
metricFreshness[].lastSeenDuplicateAt, and the Apple Health card names a
re-send that came after the last arrival.
Refs #1259
The beyond-horizon line said the range held "for more than {years}
years, the span your readings cover", but the horizon is capped at three
years, so a ten-year history was told its readings spanned three. The
trend now says whether the cap or the span set the horizon
(`horizonCapped`), and the card words each case on its own in every
locale.
The strain run writes no impulse row on a day without a scorable workout
or active energy, so a rest day for someone without daily active energy
was never rated: fitness and fatigue held for months instead of
decaying, and the figures named the last stored day while the coverage
count ended there too.
A day without a stored impulse is now classified from the underlying
data: a workout on the day leaves it unrated, steps, heart rate or
active energy without a workout make it rest, and no data at all leaves
it unrated. The series runs to the day the strain run scores, so a
stretch without data after the last rated day shows in the coverage
count, and the card names the last rated day when it lies further back
than the day before.
The switch was stored and shown, but nothing reads the topics flag
yet, so the page promised a change it could not make. The section,
its nav entry, its loader and its copy are gone, so its palette
entry goes with them; /settings/preview is no longer a route. The
stored flag, /api/settings/preview-features and its backup round-trip
stay, and the column's pending-consumer note says why.
The effect is fitted on up to 90 days before a start and 180 after
it, which can lie outside the report period. The PDF notes and the
clinician view now state the fitted window for every effect shown.
The effect block names every medication it describes and its
confounders, so a report or share link that withheld the medication
list still carried the names. The aggregator now loads the block only
when both leaves are admitted, the clinician view checks the list leaf
as well, and the leaf label says it needs the list.
The automatic Newey-West rule gives a lag of 3 on 30 to 270 daily
values, which leaves most of a physiological series' carry-over out of
the intervals. The lag is now at least 7. Reference values are
recomputed with statsmodels at the new default, and the lag-3 values
stay pinned with an explicit lag. A fit whose residual autocorrelation
exceeds 0.5 is flagged, and the card, the clinician view and the PDF
say the ranges may still be too narrow.
A day without a stored training impulse was read as a rest day, so a
watch left off or a nightly run that had not happened yet pulled
fitness and fatigue toward zero. Such a day is now not rated: the
averages hold through it, the series marks it, and the card says how
many of the last 42 days were rated. A scored day of 0 stays rest. The
figures describe the last stored day rather than always yesterday.
Today is shown as in_progress instead of being placed against whole
days, and a running period is compared over its completed days only:
the total through yesterday against the usual rate times the days
completed. The period total and goal progress still count today. The
comparison gains completedDays and completedValue.
A marker whose newest reading is more than a year old is now reported
as of that reading (projection "stale"), with no exit date and no
already-outside verdict. The projection horizon is capped at the span
the readings cover, so a line is never carried further ahead than the
data reaches back. The detail read keeps the newest 2000 readings
rather than the oldest.
The health-status read scanned five vitals over 90 days for a dated,
sustained level shift. It now scans every vital with a stable daily level
(adding RMSSD, diastolic pressure, pulse, body fat, respiratory rate,
oxygen saturation, walking heart rate and VO2 max) over 180 days, reads one
value per day per metric, leaves a metric unread when its module is off,
and reports how many days stand on each side of the break. The Coach keeps
its five-metric, 90-day scan unchanged.
Settings > Export & Import gains a card that reads the head of the file,
suggests the column for each field from its header in eight languages,
suggests the separator, decimal mark and date order, and lets every
choice be corrected. The check lists each refused row by line and the
markers the names land on; the import button names how many rows it
will write. Templates for both kinds download from the sheet.
The first page of the workout list now carries the fitness-fatigue model
over the day-total heart-rate impulse the nightly strain run already
stores: fitness as the 42-day and fatigue as the 7-day exponentially
weighted average, form as their difference. A day without a stored impulse
counts as rest. It needs 28 days and three training days, flags the first
six weeks as warming up, and reads in the person's own units only. The
workouts page shows the three figures above the list.
The Topics preview describes what it will add, the workout-route detail
says off for new accounts, and German reads 'Zurück zu den Modulen',
'Unter Module ändern', 'Unter Anordnung öffnen' and 'Erfassung' for
the Tracking group. Strings that name the Insights area call it
Insights; generic uses of Auswertung stay.
The assessments list now carries, per PHQ-9, GAD-7 and WHO-5, the latest
total against the previous and the first administration, classified
against the change studies treat as meaningful: 5 points on the PHQ-9,
4 on the GAD-7, 10 on the WHO-5 percentage scale. A smaller change reads
as within the threshold rather than better or worse. The instrument
detail states each change and whether it reaches that size, in neutral
words. The read takes totals and dates only, never an answer.
The Coach overlay had become a read-only line with a link to Settings >
AI, which took away switching the model mid-conversation. The provider
and model selects are back; they write through the same routes and the
same stored preference as Settings > AI, so there is still one setting,
and the link to Settings > AI stays below them.
A read-only view per metric and UTC day: every source with readings, its
day value, its place in the person's source priority, and which source
the charts use with the reason. A second card lines two sources up over
30, 90 or 365 days. The pick is explained from the rank the canonical
SQL returns, so the page cannot disagree with the charts. Linked from
the metric pages and from Settings > Source priority.
The standard report template now carries sleep duration, heart-rate
variability as two labelled rows (SDNN and RMSSD), daily steps, a
per-sport workout summary and the change around each medication start.
Each still rides its module, and the template is still only applied by
the button that names it; saved selections and share links are
untouched.
Two structured leaves join the catalogue: WORKOUTS (activity group,
workouts module) and MEDICATION_EFFECT (medications group). The workout
block reads narrow rows through the canonical-workout picker and sums
them per sport. The effect block reuses the efficacy loader with the
report's end as its horizon, carries a target only when that target's
own measurement leaf is admitted, and is capped at eight medications.
In the PDF the wearable series chart at half width, two to a row, in
the units the table prints; the workout and effect blocks are compact
tables with short notes. The clinician view renders both blocks from
the same payload. RMSSD joins the dense day-bucket path so long windows
stay aggregated.
The biomarker detail read now carries a trend: the least-squares line
through every numeric reading of the marker (all stored in its unit), with
the slope's 95 % interval and p-value. It needs three readings over at
least a year. The line is placed against the marker's band, and an exit
date is given only when the interval excludes zero, the line is inside the
band today and reaches a bound within three years. The detail page words
it as a straight-line projection, not a forecast.
The efficacy tab keeps its before/after comparison and gains, per metric
target, the level change and the change in weekly trend at the start,
each with a 95 % interval. The fit covers up to 90 days before and 180
after the start and ends before the first dose change. After the start,
days are left out when fewer than 80 % of the doses of the preceding 14
days were taken (cadence-aware, from the dose ledger) or when the
medication was paused or between courses. Other medications that
started, stopped, changed dose or paused inside the window are listed.
Below 14 days with readings across 21 days on either side the view says
what is missing instead of showing numbers.
The efficacy response gains a nullable segmented block per target.
The checkups page links to the checkup reminders under Notifications
and the screening hints under the health profile, the two cards that
left its settings in this release. Data & privacy gets a row pointing
at sessions and devices under Security.
The discovery matrix gains the families people log but could not test:
water, caffeine and up to four varying micronutrients from the nutrient
log, alcohol days from the mood tag, workout minutes (one per session) and
the day's training impulse, exercise, stand and mindful minutes, State of
Mind as an outcome, and the overnight room climate against that night's
sleep only. Every channel runs through the same seasonal adjustment,
effective-n p-value, Benjamini-Hochberg control and effect-size floor, is
read only while its module is on, and drops out below the paired-day floor.
State of Mind, mindful minutes and alcohol days are statistics for the
person: the Coach, the period narrative and the assessment cards drop every
pair that touches them, after the shared scan so the remaining pairs keep
the statistics the correlations page shows. A guard walks the import
closure of the analysis modules and refuses any path to a provider.