Commit Graph
9450 Commits
Author SHA1 Message Date
Marc-André Bombeck 6c15a66cde feat(mental-health): show Brazil's crisis line to pt-BR readers
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.
2026-10-22 15:15:48 +02:00
Marc-André Bombeck 36a1485b91 style: format the database helper test 2026-10-22 15:08:14 +02:00
Marc-André Bombeck 2d16183b58 feat(i18n): let translators edit the catalogues in the browser with Fink
Add an inlang project so Fink opens the repository directly:
English as the source, the nine shipped locales, and the
message-format plugin pinned to 4.5.5 reading messages/{locale}.json.
That plugin keeps the nested keys and {placeholder} tokens as they
are; the i18next and next-intl plugins Fink also supports either
rewrite numeric-keyed objects as arrays or misread quotes around a
placeholder as ICU escapes.

Checked against these files with the inlang CLI and SDK: all nine
locales load with no errors and no findings, a load and save without
edits leaves every file byte-identical, and an edit changes exactly
the edited lines. inlang's working files beside settings.json ignore
themselves in git and are kept out of the format check.

CONTRIBUTING gains the browser workflow (fork, push, pull request),
what a reviewer checks, and that machine translation is a draft a
reader of the language goes through before the pull request; the
new-locale steps now name the real locale list. A test keeps the
project's locales equal to the shipped ones and the plugin pinned.
2026-10-22 15:03:16 +02:00
Marc-André Bombeck dc9beaefb7 fix(i18n): spell the Korean singular forms the way English does
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.
2026-10-22 15:02:15 +02:00
Marc-André Bombeck 1bc5df17bc test(guards): write back the lower source-read counts
Since the guards read the source tree through the shared index, 35 of
them no longer read a source file by path, and the realism ratchet
failed until the lower numbers were recorded.
2026-10-22 14:57:59 +02:00
Marc-André Bombeck 10bd2e5d94 test(guards): raise the size baselines for the pt-BR tables
The outbound screen, the prose-grounding check and the insights and
Coach prompt files keep one table per locale on purpose: the dual-bank
rule (the reader's bank plus English) reads in one place, and every
other locale lives there. A ninth locale adds its rows, mostly to the
dose, risk and causal banks of outbound-screen.ts and its
buildDoseChangeClass table (+134 and +40 lines). The managed-profile
settings section and the Telegram handler grow by an import and the
Portuguese bare words.
2026-10-22 14:57:33 +02:00
Marc-André Bombeck 51f7d38b3c test(i18n): give the per-locale copy guards their pt-BR vocabulary
The delete-confirmation, sleep-debt, mood-prognosis, MCP-token and
AI-consent guards match each locale against its own phrases, and the
sharing-boundary guard against the word for account; pt-BR now has
them. The locale-count floors read nine, and the managed-profile picker
test counts the locale list instead of a literal.
2026-10-22 14:57:32 +02:00
Marc-André Bombeck 71123e5fae test(i18n): hold every catalogue to the English placeholders
Key parity let 38 pt-BR strings through that renamed or dropped a
{placeholder}: a renamed one renders as a raw token, a dropped one
loses what the sentence was for. Every non-English bundle now has to
use exactly the placeholders of the English string, with one
allowance: a singular plural form may spell out or add {count}.
2026-10-22 14:57:09 +02:00
Marc-André Bombeck 5c2f91463c fix(i18n): state the glucose band edges in the five locales that left them out
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.
2026-10-22 14:57:00 +02:00
Marc-André Bombeck fed49f9b76 fix(i18n): translate the last English leftovers and a stray backslash in pt-BR
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.
2026-10-22 14:57:00 +02:00
Marc-André Bombeck 34ee0ea6e8 fix(i18n): separate the intake from the amount in the pt-BR medication wording
"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.
2026-10-22 14:50:52 +02:00
Marc-André Bombeck 4df28c5f80 feat(i18n): fill the pt-BR keys added since the translation was drafted
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ê.
2026-10-22 14:50:52 +02:00
Marc-André Bombeck 4e47c52aed fix(i18n): match the pt-BR wording and placeholders to the English source
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.
2026-10-22 14:50:28 +02:00
Marc-André Bombeck 3577da6966 fix(coach): narrow the pt-BR population-norm patterns
A sentence the grounding check reads as population guidance has its
numbers exempted from the evidence check. Two of the pt-BR patterns
matched sentences about the reader's own readings: "(entre|de) ...
geralmente" fired on "Sua pressão de 158/97 geralmente fica...", and a
singular "médico ... recomenda" with a 30-character gap fired on "Seu
médico recomenda manter a pressão em 158/97". Either let an invented
figure through unchecked.

Every pt-BR entry now needs a population subject or a reference noun:
plural guideline, doctor or specialist subjects next to their verb,
plural adults needing something, and "a/o <metric> normal" without a
possessive. Portuguese month names join the written-date pass so "21 de
julho" is not graded as a figure, and quilos, por cento and passos
join the unit words.

Negative cases prove the reader's-own sentences are checked again;
positive cases keep the reference sentences exempt.
2026-10-22 14:50:17 +02:00
Marc-André Bombeck 68b428e3f5 feat(ai): screen Brazilian Portuguese model output for dose, risk and causal claims
The outbound screen runs the reader's bank plus English. For a pt-BR
reader that meant English only, so "Pare de tomar a metformina",
"Dobre a dose de insulina" or "Seu risco é de cerca de 12%" passed every
surface unchanged.

Add the pt-BR banks the other locales carry: the dose-change class
(change, take, skip, stop, halve, double and one-more imperatives in
the você form, with the medication nouns, drug classes and stop words a
Brazilian reply uses), the target-dose patterns, the risk-figure and
risk-engine patterns, the causal phrases, and the continuation and
change-stem pair that keeps "continue tomando conforme prescrito"
exempt. UI joins the insulin units, and the count words and dosage
forms gain the Portuguese spellings.

Tests pin each class blocking in pt-BR and the restatements, negated
warnings, referrals, past changes and dietary advice passing.
2026-10-22 14:50:10 +02:00
Marc-André Bombeck 929d83b3b6 test(e2e): record the whole drag instead of one fixed-time sample 2026-10-22 14:50:01 +02:00
Marc-André Bombeck 764794496c feat(i18n): register Brazilian Portuguese as a locale
Add pt-BR to the locale list and everything that hangs off it: the
client loader, Intl and date-fns mapping, the reply-language footers of
the Coach and insights prompts (English body, pt-BR footer, the same
path Korean and Dutch take), the citation-coverage normative words, the
no-key fallback copy, the AUDIT-C standard-drink line, country labels,
period search, CSV yes/no cells and the Telegram bare-word aliases.

The locale enums in the extract, managed-profile and record-settings
schemas now derive from the locale list instead of repeating it, and
the five notification and login-alert routes share one isLocale guard
instead of hand-rolled chains, so a later locale is one edit there.
A language tag is matched exactly and case-insensitively before its
primary subtag, so pt-BR and pt-PT browsers land on the Portuguese
bundle rather than English, and AUDIT-C no longer cuts a region tag to
two letters.

PHQ-9, GAD-7 and WHO-5 are not marked validated for pt-BR: the wording
has not been read against the published Brazilian forms, so readers get
the English items plus the existing note.
2026-10-22 14:50:00 +02:00
Marc-André Bombeck 6cf69bbf1c test(insights): pin the clock in the two-service workout collapse case
The case built its sessions from the real clock: one copy a day before
now, the other 30 s later. The cross-source workout picker groups sessions
into fixed five-minute slots of the epoch, so whenever the suite ran in
the last 30 s of a slot the two copies landed in different slots and
counted twice. It had nothing to do with day boundaries or time zones: the
outcome followed the minute of the wall clock alone.

The case now pins Date to an instant well inside a slot. With the pin at
12:04:45Z or 23:59:45Z the case failed under UTC, Europe/Berlin and
Pacific/Kiritimati alike; at the committed 12:02:00Z it passes under all
three.

The production code reads no clock here (the block takes `now` from its
caller). What the flake exposed is the fixed slot grid itself: two copies
of one session that straddle a slot edge are not collapsed. That is a
change to the picker every workout surface shares, so it is left for a
change of its own.
2026-10-22 14:49:55 +02:00
Marc-André Bombeck 1619b2406a fix(i18n): reshape the Brazilian Portuguese catalogue onto the English key structure
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.
2026-10-22 14:41:17 +02:00
Marc-André Bombeck 402daa2753 Merge pull request #1251 from dareoon/feat/i18n-pt-br 2026-10-22 14:19:17 +02:00
Marc-André Bombeck 7363bcd5d3 ci(e2e): trust the checkout in the WebKit container; measure the day button once it settles 2026-10-22 14:16:08 +02:00
Marc-André Bombeck e18cd086fd ci(e2e): run the WebKit spec in the Playwright image, keep the shards on Chromium
Installing WebKit's system packages in every shard stalled one shard for
29 minutes on apt and left another without time for its tests. The
bottom-sheet spec now runs in its own job inside Microsoft's Playwright
image, whose tag follows the playwright-core version the lockfile
resolves; the shards install Chromium only and skip the WebKit project.
The e2e gate answers for the shards and the WebKit job.
2026-10-22 13:44:10 +02:00
Marc-André Bombeck 98a083c86e test(guards): scan once in the threshold and timezone guards
Both guards timed out at five seconds under a loaded unit suite. The
timezone formatter guard grepped the whole of src, the generated client
included, once per scan; it now reads the tree once without the generated
client and keeps a file only when a plain substring says a pattern could
match. The threshold literal guard parsed every client file once per rule
and twice per run; each file is parsed once, each rule's hits are found
once, and a file is parsed for a rule only when it carries one of the
rule's markers. A sample that the markers would skip fails the matcher
case, and a planted literal still fails the allowlist case.

Measured alone: the timezone guard 5.5 s to 0.45 s (its floor case 1.9 s
to 2 ms), the threshold guard 4.6 s to 0.54 s (its non-empty case 1.1 s to
0 ms, reusing the hits it already found).
2026-10-22 13:02:59 +02:00
Marc-André Bombeck 8fc4941200 docs(changelog): local thinking models and the regenerate timeout
Refs #1267
2026-10-22 13:02:03 +02:00
Marc-André Bombeck 9e2a8229ec feat(settings): say that the daily briefing reasons at its own depth
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
2026-10-22 13:01:20 +02:00
Marc-André Bombeck 6d250d092d fix(insights): wait as long as the response timeout allows in the browser
The regenerate button aborted its inline POST after a fixed 45 s, so on a
slow local model every regenerate was cut while the server still had
minutes left on the person's setting. It now uses clientAbortMs over the
route's sequential model calls, never less per call than the briefing's
own 180 s default, because the published value cannot say whether the
person set it.

A save of the about-me self-context derives the clarifying questions
inline and ran under the 15 s request default, which reported a failed
save while the server went on to commit it. All six save sites now take
their abort from the same setting. Every other browser request that waits
on a model either has no client timeout or only queues the work.

Refs #1267
2026-10-22 13:01:20 +02:00
Marc-André Bombeck 221960af88 fix(ai): ask a thinking model again when it answered with reasoning alone
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
2026-10-22 13:01:10 +02:00
Marc-André Bombeck bb3ee6b855 fix(safe-fetch): leave the deadline to the caller's signal
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
2026-10-22 13:01:10 +02:00
Janne Asmala 8ea0ba5297 feat(vaccinations): Add dengue and tuberculosis to the catalogue
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.
2026-10-22 18:58:15 +08:00
Marc-André Bombeck f08277e595 Merge pull request #1265 from MBombeck/fix/v1441-next-security
Release v1.44.1
v1.44.1
2026-10-22 12:26:44 +02:00
Marc-André Bombeck ed04103eb6 chore(release): v1.44.2 2026-10-22 12:05:28 +02:00
Marc-André Bombeck 803d90c6c4 Merge branch 'fix/1261-own-targets' into release/v1.44.2 2026-10-22 12:04:29 +02:00
Marc-André Bombeck ac9693fac9 Merge branch 'feat/bottom-sheet' into release/v1.44.2 2026-10-22 12:04:28 +02:00
Marc-André Bombeck 03b3f6a3ba docs: record the history fixes and what 16.4.2 measured 2026-10-22 11:32:57 +02:00
Marc-André Bombeck aae7bce078 test(security): write the next/image import matchers as literals 2026-10-22 11:32:57 +02:00
Marc-André Bombeck 6cd8ffa526 fix(documents): follow the address bar for the open document
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.
2026-10-22 11:32:57 +02:00
Marc-André Bombeck c496e390be fix(day): hold a step until the layer shows the previous one
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.
2026-10-22 11:32:56 +02:00
Marc-André Bombeck 08675a4f13 Merge branch 'release/v1.45.0' into feat/v145-issues 2026-10-22 11:00:45 +02:00
Marc-André Bombeck 7bbe64ad1a refactor(healthkit): fold the per-type arrival tally into the ledger module
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
2026-10-22 11:00:06 +02:00
Marc-André Bombeck 190a83c513 feat(coach): read lab results over the whole record
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
2026-10-22 10:50:56 +02:00
Marc-André Bombeck 6a2247e422 fix(healthkit): count a type as arrived only when the batch brought something new
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
2026-10-22 10:34:45 +02:00
Marc-André Bombeck 743a1e742f test(guards): stop the slowest guards repeating their own work
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.
2026-10-22 10:30:59 +02:00
Marc-André Bombeck 4dc3bd46bf test(guards): read the source tree once per worker through a shared index
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.
2026-10-22 10:30:50 +02:00
Marc-André Bombeck ff49bbb5fc fix(insights): shade the SpO2 chart from the own target when one is set
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
2026-10-22 10:23:15 +02:00
Marc-André Bombeck 90106d88c8 fix(dashboard): shade blood pressure, pulse and body fat from the own target
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
2026-10-22 10:23:14 +02:00
Marc-André Bombeck 72e6fd6620 test(e2e): drive the bottom sheet on WebKit with an iPhone profile
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.
2026-10-22 10:20:30 +02:00
Marc-André Bombeck 55211c0e69 fix(pwa): never arm pull-to-refresh while a sheet holds the page
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.
2026-10-22 10:20:30 +02:00
Marc-André Bombeck 1cc1cda7aa feat(ui): make every bottom sheet draggable
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.
2026-10-22 10:20:28 +02:00
Marc-André Bombeck 601d5ea447 test(guards): walk the tree once in the timezone formatter guard
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.
2026-10-22 10:19:11 +02:00
Marc-André Bombeck 703c92c776 test(integration): take the clock and the probe budget out of two verdict tests
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.
2026-10-22 10:14:03 +02:00