Ollama serves thinking models such as Gemma 4 on /v1/chat/completions with
the thought in a separate `reasoning` field. A long briefing can come back
with empty `content`: the thought used the whole token budget, or the
answer itself was parsed into `reasoning`. The background briefing always
asks to reason, so every briefing on such a model ended in the empty-reply
sentinel, which the chain logged as status 0 / cause "network" in the same
second the server logged 200, and the read path showed as a timeout.
The Local client and the OpenAI-compatible gateway now treat a reply with
reasoning and no answer as a lesson: the endpoint and model are remembered
in the reasoning dialect cache as answering only unreasoned, the call is
asked once more with reasoning_effort "none", and later calls ask that way
until the lesson expires. A test drives the real client, safeFetch and the
pinned dispatcher against a loopback server that answers the way Ollama
serves Gemma 4, and reproduces the reported log line without the fix.
Failed hops now carry what the call ran into: `failure` (timeout, aborted,
refused, reset, socket, parse, empty_response, reasoning_only, ...) and a
code-shaped `code` on ai.chain.link_failed, closed vocabulary only. The
cause only says "timeout" for a deadline, and the briefing failure marker
records the kind so the empty state suggests a longer timeout only when
time ran out.
Refs #1267
The pinned dispatchers kept undici's own 300 s header and body timers. A
local model with the response timeout set above five minutes answers a
non-streamed completion only once it is done, so its headers could take
longer than 300 s and undici dropped a call the caller still allowed; the
failure read as a bare network error. Every safeFetch call carries its own
AbortSignal.timeout, so that signal is now the one deadline.
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 sheet compared useSearchParams with the last ?doc= it had seen.
Next 16.4 applies its copy of a pushState after the write, and a Back
pressed in between leaves useSearchParams reading no document on both
sides, so the sheet saw no change and stayed open. The sheet now reads
the query from window.location through useSyncExternalStore, re-read on
popstate and on every render, and the selection and close paths build
their URLs from the same live value.
A step writes ?day= with replaceState, past Next's router, which adopts
the write a render later. Since 16.4 that render can land after a second
quick step and write the first step's URL back, so [ then ] pressed in a
row ended a day short. A step that finds the layer still showing another
day than the URL now waits, and publishOpenDay makes it in one write as
soon as the layer catches up. Never past today still holds for the sum.
The batch route counted arrivals inline and grew past its size baseline
with the new-sample rule. tallyHealthKitArrivals now owns the fold, the
route hands it each landed entry and hour with whether it brought a new
value, and the size baselines move down to what the route is now.
Refs #1259
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
Each of these asked the same question several times or did the expensive
part before the cheap one: the threshold guard parsed every client file
once per rule and twice per run, the i18n reverse check rebuilt its scan
three times and compared every leaf with every literal key, the step-up
caller guard stripped comments and searched every route path in every
file per case, the plausibility guard ran its writer sweep three times,
and the cycle verdict guard parsed every client file to find out whether
it mentions a cycle. Each now works a result out once, and a file is
parsed or searched only when a substring says it can match. A planted
violation still fails the threshold, plausibility, cycle verdict and
backup plan guards.
walkSourceFiles now lists each indexed folder (src, e2e, prisma) once
per worker and filters it by prefix, readSource and readSourceFolder read
through the same memoised file cache, and readSourceText is the cached
read for guards that read files themselves. The guards project shares a
module graph per worker, so a file is read once however many guards ask
for it. sourcesContaining adds the substring pre-filter for sweeps that
look for a few markers. Every guard over 1.5 s now reads through it;
anything outside the indexed folders is read from disk as before.
The oxygen saturation page drew a fixed clinical band, so a person with
a lower target of their own saw their normal range shaded as a warning.
The page now reads the resolved range from /api/user/thresholds and
draws it; without a target the clinical bands stay as they were.
Refs #1261
The dashboard bands took only the weight target into account. Blood
pressure, resting pulse and body fat were resolved from age and sex
alone, so a target set on /targets left the chart zones and the tile
ranges on the standard band.
buildDashboardBands now reads the stored targets blob and routes every
override through getEffectiveRange, the same resolver the targets page
and the doctor report use. A metric without an override keeps exactly
the band it drew before. The snapshot's targetBands carry the resolved
values, so a native client reading them needs no change; the field
descriptions now say the own target wins.
Refs #1261
A webkit-iphone project runs one spec: drag, spring back, flick, scroll before drag, a slider sideways, the three closes, focus return, the page's scroll position and pull-to-refresh. CI installs WebKit beside Chromium.
The listeners sit on window, so a drag inside an open sheet on the dashboard or the insights page armed the refresh behind it. They stand down while the scroll lock marks the body.
One bottom sheet on top of the Radix dialog, so focus, Escape, the
backdrop, aria and the page scroll lock stay where they were. The sheet
follows a touch with a transform, the backdrop lightens with it, and a
release past a quarter of the height or a flick down closes it; anything
less springs back. Grip and header always drag; content only from its
very top, and sideways gestures never count.
Every `side="bottom"` sheet and ResponsiveSheet on a phone render through
it: the More sheet, the capture and form sheets, the Coach drawer on a
phone and the day. The day opens on the new preview step and pulls up to
90 dvh, its footer held on the bottom edge. Focus now returns to whatever
opened a sheet, not only to a Radix trigger. The command palette fills
the window and keeps no grip or drag.
Each of the guard's scans started its own grep over the whole of src,
the generated client included, five times per run, and the floor case
timed out at five seconds under a loaded unit suite. The tree is read
once now, without the generated client, and a file is kept only when a
plain substring says a pattern could match; each scan's result is
reused by the cases that ask about it. The file runs in 1.9 s instead of
6.5 s alone, and the floor case in 2 ms instead of 2.3 s.
The grant expiry case gave the grant 400 ms and slept 500: on a loaded
runner accepting, signing in and switching took longer than the grant
lived, and the grant expired before it was accepted. The grant now runs
30 seconds and the case moves the clock the resolver reads to the
instant the grant names, so the row still does not change and nothing
sleeps.
The key check's start-up probe is bounded at ten seconds and two per
query. Under load a probe query ran past two seconds and the check
answered inconclusive where the data says mismatch. The verdict tests
now run the check with time to finish; the cases that test the bounds
pass their own budget or sampler and keep them.
/api/auth/me 18 to 13, dashboard snapshot 103 to 99, summary 86 to 84,
the 365- and 3650-day pulse series 6 to 5, the day view 48 to 47,
insights health status 60 to 59, correlations 44 to 43 and a 500-row
batch ingest 31 to 28.
The profile section in docs/contributing/benchmarks.md says how to run
scripts/bench/boot-profile.ts, what the profile of the v1.44 runtime
found (the worker graph as one 753 ms block, a live heap of about
165 MB of which the query compiler holds 50 and the catalogs 33) and what
changed. scripts/bench/results/v1.45.0-*.md hold the before and after
numbers per area, from back-to-back runs on the same machine. The size
baselines take the lowered numbers.
Readers that tag a cell as a closed block no longer import the
invalidation module, which several tests replace wholesale. The cache
route test counts the slice's pre-fold cell apart from the route's two
cells, and the provenance test reads the shared pick's ORDER BY over its
grouped rows.
Re-importing an Apple Health export the account already holds sent one
UPDATE per row the insert skipped, about two million statements for a
large export, nearly all writing back what was stored. One read per chunk
now finds the rows whose stored values equal what the update would write;
they count as updated as before, without the statement. A key the chunk
carries twice is written in order as before. The natural-key rescue moves
into the same module.
A long-window read of a dense series sent two statements over the same
canonical rows, the day or hour buckets and the strip's figures, so a
ten-year pulse read picked the canonical source per day and scanned the
readings twice. Both aggregates now run in one statement over the window
materialised once, with the same SQL each had (dense-series-read.ts).
An integration test keeps the two old statements as the reference and
requires the same buckets and figures for pulse (two ranked sources),
glucose and oxygen saturation, day and hour grains, in UTC,
Europe/Berlin, Asia/Kolkata and America/New_York, and the same empty
answer for a type without readings.
The two-ended checks ask every declared file about every model and each
of its relations, and read the schema and the files again for each
question. With the backup split into more files that took two seconds a
case and timed out on a loaded runner; the reads are memoised now.
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.
The whole-payload tests meet a slice's refinements only by accident. Each
pattern, bound and two-ended free-text rule now has the value just inside
and just outside it, with the issue it raises: the day keys, a long day's
time away, the Coach's table and trail caps, a life event's title and a
symptom's label, a profile fact's readable value and validity. The backup
validation mutation score goes from 25.5 to 41.6 %; the floor follows.
The element schemas move out of validations/backup.ts into one
<domain>-backup-schema.ts per domain, beside its export and restore, with
the shared primitives in backup-schema-kit.ts. validations/backup.ts now
composes the slices into backupPayloadSchema in the same key order, with
the same defaults and the checks that span sections, so the parsed
payload, every validation message and the OpenAPI contract are unchanged.
The lazy-schema guard now covers the slices too: a slice is reached only
through the payload schema or another slice, never from a domain's export
or restore. The external-id guard carries the payload's exemption to its
slices, and mutation testing scores the slices with the payload schema.
buildFullBackupPayload now asks every domain for its slice at once and
lays the slices out in the file's key order (backup-export-sections.ts),
merging the manifest where it first appears. The measurement, medication,
mood, instance-settings and nutrient readers and serialisers move out of
the payload builder into their domain modules; the records section keeps
its composition and manifest, while labs, illness, allergies, family
history, workouts and documents each export from their own module. The
measurement restore half moves to measurements-restore.ts so the export
graph does not pull in the restore's dependencies.
The file, its counts and their order are unchanged; the golden copies
still match. The measurement completeness guard now reads the domain
module and also checks that every carried column is written back.
A table read without an order comes back in whatever order its last
updates left on disk, so the column fill could pick a different row of a
two-row table from run to run. The audit rows of a restore are now found
by the copy's id instead of by time, since the database clock and the
test's clock do not agree to the millisecond. The golden copies are
written again from the code before the restore and export moved.
Up to 12.37 pg-boss retried a job whose handler outlived its expiry in
the same worker beside the run it had given up on, and the lane test
pinned that as an executable statement. 12.38 fails the job and fires
the signal as before, but the worker fetches nothing more until the
handler returns, and the retry starts after it. The test now pins that:
one run at a time, the retry starting after the overrun ends, and the
lane's handler importing once per delivery with never two at once. The
lane's lock stays, as the guard for a second worker or instance.
next/font/google downloads Inter from fonts.googleapis.com and
fonts.gstatic.com while the app builds, and when that request fails the
build fails with it, which is what broke the arm64 image build and
several CI jobs. The files it downloaded now live in src/app/fonts/inter
under the SIL Open Font License, and next/font/local declares them.
They are the same bytes: Inter 4.001, one variable file per script
subset (Cyrillic and its extension, Greek and its extension,
Vietnamese, Latin Extended, Latin), each used for weights 400 to 700.
The declarations rebuild the stylesheet Google answered, the twenty-eight
faces with Google's unicode ranges in Google's subset order, swap
display, and only the Latin file preloaded. The local loader emits one
unicode range per call, so each subset is its own call under the
family Inter.
The Arial fallback face and the font-sans stack move into globals.css
with the metric overrides next/font/google shipped for Inter; the local
loader would have computed slightly different ones from the file.
A production build with every outbound request sent to a dead proxy
completes, where the same build with next/font/google fails on the
fonts.googleapis.com request. The content security policy already
allowed fonts from self only. A guard refuses a next/font/google import
anywhere under src.
Strava's token endpoint does not answer RFC 6749 errors. A refresh
token it no longer honours, after the athlete revoked the app or the
token was rotated away, is a 400 with the API's generic Fault:
{"message":"Bad Request","errors":[{"resource":"RefreshToken",
"field":"refresh_token","code":"invalid"}]}. The classifier looked for
invalid_grant, which never arrives, so the failure was booked
persistent and the connection never asked for a reconnect.
The token error now carries the fault reduced to its resource, field
and code (or an RFC error code, should one arrive), and the classifier
lifts a 400 naming RefreshToken to reauth_required, from the error and
from its message after a retry loses the prototype. Every other refusal
is classified by its status as before, including the faults that name
the Application.
Strava documents the Fault and Error model but not these values; the
body is the one several unrelated client libraries captured from live
traffic between 2023 and 2026.
An app boot's /api/auth/me read the AppSettings singleton six times, each
reader with its own few columns: the MFA policy, the Assistant switches,
the module availability, the provider presence, the AI usage bounds and
the reasoning controls. They now take their columns from one read,
memoised for the request and read afresh inside a background job like the
readers themselves. No answer changes.
The day view started about twenty-five section reads at once beside the
readings, scores and movement, more than the pool holds, so a
neighbouring request waited for a connection. The sections now run six at
a time and come back in the same order.
Every sync marked all of an account's analytics cells stale, so the slice
re-read the pre-fold remainder (every reading older than five years,
folded per source and day, the slice's largest statement on a long
history) and the day view re-read its past history blocks, although a
sync of today's readings cannot change either.
A cache key can now name the instant its value's readings end before
(closedBlockKeyPart). invalidateUserMeasurements takes touchedFrom, the
earliest measuredAt a write created, changed or removed, and leaves such
blocks in place when it is not earlier; without it every block goes as
before. The batch route passes it from the identities it wrote. The
pre-fold remainder moves into its own module and is cached as a closed
block; the day view's past history blocks carry their end, with a day of
margin for a night across midnight.
The batch route's two up-front reads move into batch-stored-rows.ts with
the once-per-batch key rule they share.