Nothing renders through next/image, so /_next/image only offered a route
that fetches, decodes and re-encodes whatever local path a request names.
With images.unoptimized Next answers it with 404 before reading a
parameter. A guard fails when next/image is imported while the optimizer
is off, or when the optimizer returns with SVG input allowed.
Next 16.4.2 carries the fixes for GHSA-673q-mjm6-r5xr and
GHSA-2464-fhr4-w9xw (unauthenticated remote code execution) and
GHSA-p3m5-59mp-jv5r (denial of service through Server Actions).
eslint-config-next and @next/bundle-analyzer move with it, both pinned
exactly. nodemailer 10.1.7 fixes the address-parser advisories.
The 16.4.0 ignore in the Dependabot config is gone: the history journeys
it was guarding pass on 16.4.2 with the day-step fix, and the note says
what was measured.
A step read the day the layer had last published, which reaches the
shortcut and the header arrows through useSearchParams, a render and an
effect. Next 16.4 lets that chain trail a replaceState by more than a key
repeat, so two quick presses of ] both stepped from the same day and one
was lost. stepDay now reads ?day= from window.location, which the step
itself writes, and refuses a step past today on that value too.
Three spelled-out range labels beside the card title pushed /insights/sources
past the viewport. Use the charts' short day labels and keep the long form as
the segment title. The route sweep resolves the new module pages and drops
mood from the arrangement pages, whose old address now redirects to them.
A MANAGE grant on a managed profile now connects its OAuth providers: each
of the six cards offers one connect and says whose record it is for, while
Fitbit and Nightscout stay status-only. A view or view-and-add grant still
gets no integration surface and a 403 from the connect route.
The connect cards read the display name alone, so a profile created without
one rendered "Connect for" with nobody after it. Use the account label the
switcher and the banner use.
The standard template carries SDNN and RMSSD since the wearable leaves
landed, and the cardio group has fifteen leaves. Assert the untouched
mobility group at zero instead.
A dynamic import() of app code skips the runner's @/ path mapping for that
module's own imports, so sealing the seeded briefing failed with
"Cannot find module '@/lib/crypto'".
The release branch measured 3875 KB gz without the lazy catalogs
against the 3755 cap (main 3737). About 15 KB is new client code; the
rest is the aggregate's per-chunk-group double count of the shared
confirmation dialog and of the two new routes' own chunks. The summed
first load of the 108 pages fell from 39998 to 35895 KB gz with the
metric pages off Zod; the watched routes keep their baselines.
The arrangement page imported its link to the module's own page from the
module pages file, which also holds the labs, mood and injection-site
settings, so every arrangement page shipped all three. The card lives in
its own module.
The value domain read the plausibility band out of the measurement
validation module, so every metric sub-page that asks whether a metric
can be negative or is integer-valued loaded the measurement schemas and
Zod with them. The band and its check live in a Zod-free module now,
re-exported by the validation module for the server writers, and the
values list checks its segment against the exhaustive type label map
instead of the Zod enum. About fifty metric routes drop roughly 88 KB
gzip from their first load. The client-route guard walks a metric page
and the values list too.
The free-text backfill no longer has an insights cache step since the
readable cached-text column was dropped, so its summary carries no
insightsCachesMigrated count. The expected summaries follow.
GPS tracks are kept only after the account turns storeWorkoutRoutes on.
The two route-storing cases opt in first, and a new case proves that an
account which has not opted in keeps the workout, answers it as
inserted, and stores no track.
The two provenance reads take required query parameters and had no
entry, so the run could not call them. Give them a day and a range on
the steps, seed a second steps source for the last week so the pick and
the comparison have two sources to explain, and save a labs list order
so the module list layout read answers with a row.
The restore admits activity goals key by key against the goals schema,
so the generic { roundTrip } JSON fill was refused as an unknown goal
rather than carried. Fill the column with real goals and pin the
per-goal admission (valid goals kept, unknown keys and out-of-bounds
goals named) in the unit suite.
detect_changepoints no longer averages bucket means itself; it hands
them to the shared level-shift detector, so the file has no in-memory
mean left for the guard to list.
A wall-clock time read in another zone on a retry is a different
instant, so neither an exact-instant match nor the zone's day catches
it near midnight, and widening the match would drop a genuine reading
of the same value on the neighbouring day. The earlier import's zone is
not stored, so the comment states the rule that never loses a reading.
The medication CSV import created the medication and then set its
category in a second write. A crash between the two left a medication
without a category, and a retry skipped it as a duplicate, so it never
got one. Both writes now share one transaction.
The lab CSV import builds its rows into an array and writes each chunk
with one createMany({ data: toWrite }). The ciphertext-writer scan only
read payload literals at the call site, so it never saw the encrypted
note that write carries; the column stayed covered only by the name
scan. The scan now follows an identifier payload into the literals the
same file pushes onto it, and asserts it sees the chunked note write.
The CSV import wrote its audit row in a finally block, so an audit write
that threw discarded whatever the import had settled on: the result of
a finished import, the 413 of a file over the cap, or the error of one
cut off part way. The failure is now noted on the wide event and the
import answers as it would have.
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 tool kept its own CUSUM with a plain standard-deviation bar, so the
per-metric floors and the drift rejection the health-status scan gained
never reached it, nor the medication-effect note that reads it: a 0.6 kg
weight step or a steady climb still came back as a dated shift. The tool
now segments the series with the shared detector, recursing on each side
of a shift with the same bar and the metric's floors. The output shape
is unchanged.
The 100000 ceiling refused offsets a correctly paging client reaches on
its own: an Observation series with a heart-rate history runs well past
a hundred thousand rows, and the next link the server handed out led
straight into a 400. The 500 the ceiling was added for came from an
offset such as 1e20 that no longer floors to an exact integer and that
the database cannot read as an OFFSET. The refusal now sits at the
largest exact integer, and a next link never carries an offset the
server would refuse.
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 note named the activity goals among the three new readable routes.
They are the calendar read and the two source provenance reads; the
goals route stays owner-only.
An offset beyond what the database can skip reached Prisma unchecked
and answered 500. Every search route now refuses an _offset above
100000 with an invalid OperationOutcome.
The lab, medication and measurement CSV routes ignored parameters they
did not know, so a misspelt dryrun=1 fell back to a real import and
wrote the file the caller meant only to check. Their query schemas are
strict now: an unknown parameter answers 422 before anything is read
or a rate bucket is spent.
Every accepted row was its own insert, so a 20 000-row file meant
20 000 round trips and an import cut off part way left an arbitrary
prefix behind. Each 200-row chunk is now one createMany: it lands whole
or not at all, and uploading the same file again skips the written
chunks as duplicates. The importers report each committed write, and
the audit row is written in a finally block, marked partial with the
rows written when the import did not finish.
The rows were parsed in the query's timezone while the duplicate keys
used the account's, so two draws on separate days of the file's zone
could collapse into one, or one day split in two.
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.
Two rows of one workout slot from sources off the ladder were both
kept by the picker and their impulses added. Only one source's rows
now count per slot, a source off the ladder ranking below every
listed one. The day's active energy, the strain fallback signal,
summed every source; it now goes through the activeEnergy source pick
and keeps one source's total.
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.
Each scanned vital gets a minimum level change and a spread floor at
about its clinical and device resolution, so a VO2 max estimate that
steps by 0.3 or a clean 2 bpm change no longer reads as a shift. A
series a straight line explains at least as well as a step is a drift,
not a dated shift. The magnitude is capped at 10 so the flattest series
cannot win the ranking.
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.