Commit Graph
8171 Commits
Author SHA1 Message Date
Marc-André Bombeck 74fa4e10b6 Merge branch 'v143/labs' into release/v1.43.0 2026-10-15 23:06:51 +02:00
Marc-André Bombeck e112e05a58 fix(labs): name a merge in the owner's activity feed and toast it through the outcome module
A merge by a record manager now reads as its own sentence in the owner's
activity feed, the merged toast goes through the written-outcome toast,
and the export test doubles carry the alias and merge tables.
2026-10-15 23:03:45 +02:00
Marc-André Bombeck 5dab12472f Merge branch 'v143/support' into release/v1.43.0 2026-10-15 23:01:52 +02:00
Marc-André Bombeck e65ada2961 feat(labs): merge markers, edit their aliases and pick a marker on review
The marker list offers a merge with the server's preview: what moves, what
is converted, which names become aliases, and a refusal when a unit cannot
be converted; it says a merge cannot be undone. The marker page shows and
edits the other spellings and follows a merged marker to its target. Scan
and document review name the matched marker or offer its suggestions and a
new marker; the choice is remembered. The biomarkerMerge feature flag is
on.
2026-10-15 22:55:08 +02:00
Marc-André Bombeck 9c01e179ca test(integration): compare the oidc refusals without their request ids 2026-10-15 22:55:03 +02:00
Marc-André Bombeck 24c74bd3eb test(integration): keep the requestId out of the mcp refusal it does not carry 2026-10-15 22:54:17 +02:00
Marc-André Bombeck 0ec7b80a9e style(api): format the request id envelope test 2026-10-15 22:42:05 +02:00
Marc-André Bombeck 703689069f docs(support): document error ids, the support info and the support report, and ask for them in bug reports 2026-10-15 22:37:18 +02:00
Marc-André Bombeck 6979928d73 chore(web): drop toast imports the error toast helper made unused 2026-10-15 22:36:34 +02:00
Marc-André Bombeck f7386742b4 feat(web): show the error id on server failures and add the support info and report surfaces 2026-10-15 22:31:51 +02:00
Marc-André Bombeck e5544913f6 test(labs): prove merges, aliases and their backup against real SQL
The merge moves every reading and every reader shows one series, a dry run
answers the same and writes nothing, conversions keep the printed value,
an unconvertible source refuses the whole merge, a chosen spelling resolves
on the next scan and on manual entry, and aliases and the merge ledger
survive both kinds of backup. The merge route joins the record-scoped
manage inventory with its driver.
2026-10-15 22:28:32 +02:00
Marc-André Bombeck 81be73fca8 feat(labs): merge markers, keep aliases and read lab series per marker
POST /api/biomarkers/{id}/merge folds markers into one in a transaction,
converting readings where the registry knows the units and refusing the
whole merge where it does not; a dry run answers the same result and
writes nothing. Aliases appear on the marker and are edited through the
marker's PUT. Scan and document review rows name the matched marker or
offer up to three, and a chosen marker is remembered as an alias. The
doctor report, FHIR and MCP group readings by marker. Aliases and the
merge ledger travel through backup and restore.
2026-10-15 22:22:40 +02:00
Marc-André Bombeck a3ce6af9a3 feat(labs): resolve marker names through aliases and catalog shorthand
A printed name now resolves to one of the account's markers by its own
name, then by an alias of the account, then by a catalog name for the same
analyte when the reading's unit fits. The catalog gains seeds for alkaline
phosphatase and total bilirubin and a checked list of common lab shorthand
in seven languages; names that mean two analytes stay out.
2026-10-15 22:22:29 +02:00
Marc-André Bombeck 800bebd45c chore(support): drop an unused lint directive 2026-10-15 22:18:29 +02:00
Marc-André Bombeck b873ce8bc8 feat(admin): fill the redacted support report with its redaction guard 2026-10-15 22:15:50 +02:00
Marc-André Bombeck 20a1ac4f7d test(links): prove a period search returns exactly that period
Parser cases for every accepted form in de, en, es, fr, it, pl and ko and
the near misses that stay text; builder cases for every family; and an
integration walk over three years of lab results, conditions, visits and
documents, with records either side of each boundary in the person's
zone, across every page.
2026-10-15 22:11:50 +02:00
Marc-André Bombeck e16c9fb717 feat(links): search a year or a month in the link pickers by its date window
A picker term that names a period ("2019", "03.2019", "2019-03",
"März 2019", "2019년 3월") is sent as the list route's from/to window
instead of q, newest first, on every family including the visit list,
which has no text search. Month names come from Intl for the UI locale,
folded for case, accents and umlaut spellings. Instant routes get the
period's bounds in the person's timezone; the document route gets the
period's calendar days. The sheet names the period it shows.
2026-10-15 22:11:49 +02:00
Marc-André Bombeck 1af0de5e87 feat(logging): keep warnings and errors in their own ring and find them by error id 2026-10-15 22:06:39 +02:00
Marc-André Bombeck 2fd62cc115 feat(api): carry the request id in meta.requestId on every error envelope 2026-10-15 22:05:06 +02:00
Marc-André Bombeck f75a2fe343 Merge branch 'v143/w0' into release/v1.43.0 2026-10-15 21:54:07 +02:00
Marc-André Bombeck 3786deb503 feat(api): publish the v1.43 contract with routes that answer 501 until filled
Every new endpoint of the contract exists, wrapped in apiHandler, with its
authentication, module gate and request validation, and answers
501 not_implemented until its behaviour lands. The OpenAPI document carries
the new operations and schemas and the additive response fields on the
changed routes. The four server feature flags are published as false.

contract-stub-inventory.test.ts registers the stubbed routes; each one
leaves the register with the change that fills it. The route, sharing,
session, security, module-gate and outcome inventories name the new routes
deliberately, and the error-code catalogue lists the codes the routes emit
today.
2026-10-15 21:49:02 +02:00
Marc-André Bombeck 6e72de1c35 feat(db): add the v1.43 schema and drop the readable location columns
Migrations 0402 to 0410: AI usage levels, biomarker aliases and merges,
medication ingredients (with the supplement label run kind), life
circumstance fact kinds, AI sections and AUDIT-C, Dawarich context, the
pulse day-mean method, intraday hour buckets, the readable location drop
and five relation link tables. Every new column carries its reader or a
pending-consumer marker.

0409 refuses to run while any home, location period or stored day still
holds a readable location, and names the counts. Locations are read from
the sealed copy only; the encryption backfill no longer handles them, and
the demo seed writes sealed locations only.

The new tables are backed up and wiped, the new sealed columns are in the
rotation registry with labels of their own, the AI usage level and the
life-circumstance confirmations travel with the backup, and the wellbeing
score reads the mental-health screeners only.
2026-10-15 21:48:57 +02:00
Marc-André Bombeck 0b64b80343 test(sharing): count the admitted biomarker delete in the fixture inventory 2026-10-15 21:31:50 +02:00
Marc-André Bombeck 97871f7b90 fix(http): mint the fresh request id through randomId
The proxy no longer calls crypto.randomUUID itself, so it leaves the
client-random-id exemption list; the request-id helper uses the shared
randomId, which also works without a secure context.
2026-10-15 21:31:50 +02:00
Marc-André Bombeck 9ee89f2455 fix(http): adopt an incoming x-request-id only when it is a plain token
The header is echoed on the response and written into every log line. Both
readers (the proxy and apiHandler) now accept it only when it matches
^[A-Za-z0-9-]{8,64}$ and otherwise use a fresh id.
2026-10-15 20:24:01 +02:00
Marc-André Bombeck f72ec02484 fix(labs): charge the shared record-write bucket on OCR commit
POST /api/labs/ocr/commit can write a whole report and mint markers, yet it
was the one lab write without a ceiling. It now charges the same per-account
record-write bucket as POST /api/labs and POST /api/biomarkers and answers
429 record_write.rate_limited once exhausted.
2026-10-15 20:24:01 +02:00
Marc-André Bombeck 5d6216a59f fix(labs): resolve biomarker delete through the record-scoped labs authority
DELETE /api/biomarkers/{id} used a bare requireAuth() while the PUT beside
it requires requireRecordAuth("manage", "labs"). The delete now uses the
same authority and, as a manage-level hard delete, files what it destroyed
(name, unit, reading count) through destroyedDetails.
2026-10-15 20:24:00 +02:00
Marc-André Bombeck b4dc0d5927 Merge branch 'chore/demo-seed-v1424' into release/v1.43.0 2026-10-15 20:18:02 +02:00
Marc-André Bombeck c57abfbd68 Merge pull request #1226 from MBombeck/docs/update-dump-advice
docs(self-hosting): take the dump before pulling
2026-10-15 20:15:46 +02:00
Marc-André Bombeck 0d6bbb942d docs(self-hosting): take the dump before pulling, not after the pending-migrations line 2026-10-15 19:08:17 +02:00
Marc-André Bombeck 89ccb71a12 chore(demo): show one row of six tiles with the weight chart below it 2026-10-15 18:49:51 +02:00
Marc-André Bombeck 9839bde4f6 chore(demo): let the dental check-up fall due on the seed day 2026-10-15 18:46:19 +02:00
Marc-André Bombeck 1fe995245b Merge pull request #1225 from MBombeck/release/v1.42.4
Release v1.42.4
v1.42.4
2026-10-15 18:14:30 +02:00
Marc-André Bombeck 140fe7277a test(e2e): wait for the lab overview read and drop an unused picker type 2026-10-15 17:31:31 +02:00
Marc-André Bombeck b1c59b908c chore(release): v1.42.4 2026-10-15 16:43:39 +02:00
Marc-André Bombeck d0b9cd8b5d Merge branch 'v1424/review' into release/v1.42.4 2026-10-15 16:42:53 +02:00
Marc-André Bombeck 346825149d fix(integrations): send no recovery for an incident the first run recorded silently
The watchdog's first pass after a deploy records standing incidents as
announced without paging. Their end then sent a recovery note for
something the operator was never told about. Such incidents now carry
the epoch as their announcement time, which no real announcement can
have, and close without a note.
2026-10-15 16:42:41 +02:00
Marc-André Bombeck 6dd71f0103 fix(medications): keep scoped credentials out of the dose arrival record
The dose arrival record describes the phone's Apple Health sync. The
measurement batch already leaves it alone for a narrow, single-purpose
credential; the intake batch now does the same, so the record stays
honest should the route ever accept such a credential.
2026-10-15 16:38:12 +02:00
Marc-André Bombeck f665a42789 fix(medications): converge a same-day Apple dose onto the slot's take
The extra-dose rule split a dose that HealthLog already recorded: a tap
at 08:00 and the same dose arriving from Health at 08:20 became two
doses and consumed stock twice, and a dose edited in Health (a new
record, a new time) became a second dose next to the first. The rule
now follows the calendar and the record: a take on another local day
is another dose; on the same day, a take logged in HealthLog converges
with the incoming record, a new record that names the slot as its
scheduled time is the slot's dose recorded again, and only an
unscheduled record more than a minute from the held one is an extra
dose.
2026-10-15 16:38:12 +02:00
Marc-André Bombeck 1e07ecaaaa fix(google-health): keep the hourly sync inside its job's expiry
An account whose backfill slice held it made the hourly job wait up to
eight minutes, and the sync after the wait ran as long as it needed:
past the fifteen-minute expiry pg-boss failed the job and retried it
beside the run still going. The pass now spends the job's budget: the
lock wait is capped at what is left, the sync's walks stop when the
budget is spent and leave the rest of the window to the next hour (the
cycle is not stamped), and an account reached after that is skipped.
A stop on the budget is not counted as a failure to retry.
2026-10-15 16:38:12 +02:00
Marc-André Bombeck 66be8c7c2c feat(integrations): one watchdog message for a provider-wide incident
The watchdog sent one page per account, so a provider outage or an
expired app credential paged once for every connected account. A pass
now collects its messages and sends them per provider at its end: more
than three accounts of one provider opening (or closing) an incident in
the same pass become one message naming the count, the reasons with
their earliest start and the accounts, and one recovery note. Every
incident in it counts as announced.
2026-10-15 16:38:12 +02:00
Marc-André Bombeck 0e5afe76a4 fix(integrations): skip the ledger page when the watchdog announced it
A failure streak reaching the alert threshold paged the operator even
when the watchdog had already announced an open incident for the same
connection. The ledger now checks for that announced incident first,
stamps the streak as announced and sends nothing; the watchdog's
recovery note still ends it.
2026-10-15 16:38:12 +02:00
Marc-André Bombeck 3e95755c3b fix(integrations): page only for trouble an operator can act on
The watchdog opened an incident for any degraded state that lasted a
day, so an Apple Health account whose phone app stopped running read as
no_new_data for good and paged. Incidents now open for action_required,
for provider errors and for the watchdog's own unexpected silence; stale
or stalled data alone never pages. The first pass after a deploy, with
no watch row yet, records what stands as already announced instead of
paging every long-broken connection at once.
2026-10-15 16:38:12 +02:00
Marc-André Bombeck 1c05813b82 fix(google-health): keep the skip's place across backfill slices
A walk that reads without the edge bound passed over everything earlier
slices wrote on every slice, and once it crossed the edge the skipped
pages were counted against the walk's page ceiling. The skip now stays
counted for the whole walk, runs on the slice's clock and its own
three-minute limit, and saves the page token it stopped at (on a limit,
a rate limit or the slice budget) so the next slice re-reads that one
page and goes on. A saved place counts as progress only when it moves
forward; a token Google refuses, or one that no longer reaches the edge,
sends the walk back to the newest page as before.
2026-10-15 16:38:12 +02:00
Marc-André Bombeck 73b9870338 Merge branch 'v1424/w2' into release/v1.42.4 2026-10-15 15:42:46 +02:00
Marc-André Bombeck 17478b08aa test(healthkit): type the card fixture's arrival fields 2026-10-15 15:38:42 +02:00
Marc-André Bombeck 09072c9f62 test(healthkit): pin dose arrivals, the background date and migration 0401 over enum rows 2026-10-15 15:36:20 +02:00
Marc-André Bombeck 03b24461ad feat(healthkit): record Apple Health dose arrivals and the last background arrival per type
Migration 0401 turns healthkit_type_syncs.type into text so the ledger can
hold MEDICATION_DOSE, and adds last_background_at (seeded from rows whose
latest arrival was a background one). POST /api/medications/intake/bulk
takes syncTrigger and records APPLE_HEALTH dose arrivals; the Apple Health
status read serves a MEDICATION_DOSE freshness entry and lastBackgroundAt
on every entry with arrival facts.
2026-10-15 15:33:30 +02:00
Marc-André Bombeck 6313c0174a Merge branch 'v1424/readiness' into release/v1.42.4 2026-10-15 15:24:29 +02:00
Marc-André Bombeck f95c2bfd41 Merge branch 'v1424/cards' into release/v1.42.4 2026-10-15 15:22:12 +02:00