Skip to content

Honest read-failure states and MCP scope-note correction - #753

Merged
MBombeck merged 19 commits into
mainfrom
fix/honest-errors-and-security-copy
Aug 9, 2026
Merged

Honest read-failure states and MCP scope-note correction#753
MBombeck merged 19 commits into
mainfrom
fix/honest-errors-and-security-copy

Conversation

@MBombeck

@MBombeck MBombeck commented Aug 9, 2026

Copy link
Copy Markdown
Owner

The first charge from the app-wide UI and copy audit: honest read-failure states and two security-copy corrections.

Two things that read as false before:

The MCP settings note claimed tokens are read-only in every case, printed directly above the toggle that mints a write token. It now describes the real model: read by default, write opt-in per token, and never admin. Six locales, and the pronoun that read as a formal address is resolved.

The share-link list rendered "no active share links" when the read failed, so on the clinic-sharing surface a failure was indistinguishable from having shared nothing. It shows an honest error with retry now.

The same read-fails-as-empty pattern is fixed across the app: the API and MCP token lists, the AI settings screen (which had been swallowing three reads and painting a default form), the Vorsorge dashboard tile, the ECG detail and list, the mood insights, the cycle view, the destructive-action settings cards, the document and share pickers, and the eight admin error boxes. Each now shows a recoverable error instead of an empty frame, and each carries a component test that fails if the empty state ever comes back.

Full detail in the CHANGELOG.

MBombeck added 19 commits August 9, 2026 03:54
…ggle

The note above the write toggle claimed tokens are read-only in every
case, which the toggle directly below it contradicts by minting a
read_write scope. Rewrite it to state the real model: read-only by
default, write opt-in per token, never admin. Resolve the pronoun that
read as a formal address, and promote both scope notes to foreground so
this security copy no longer renders as muted meta.
The central-codex and auto-read consent notes are safety copy the user
has to read before enabling a data-sharing path, but both rendered as
muted extra-small meta. Promote them to foreground text-sm and keep only
the decorative icon muted.
The respiratory-rate tile hard-coded the English unit while the metric
sub-page already reads the localized string. Point the tile at the same
key so every locale shows its own unit.
…or classes

Three small copy corrections that share the locale bundles:
- Resolve the formal-address outliers on the owner sharing and report
  scopes to the informal register the rest of those surfaces use.
- Add the direct-address comma to the personalized dashboard greeting.
- Split the managed-record form error: a client-side validation failure
  no longer surfaces as a network error, and a failed save gets its own
  line.
…ty state

The share-link query had no error or loading handling, so a failed read
collapsed to an empty list and rendered the "no active share links"
copy — on a clinical sharing surface a load failure was indistinguishable
from "you have shared nothing". Gate the list on the query state:
QueryErrorCard with retry on failure, a skeleton while loading, the lists
only once the data is in. The added test was watched fail first against
the old fall-through before this fix made it pass.
…y state

Same fall-through as the share-link list on another security surface: the
token query had no error or loading branch, so a failed read rendered
"no active tokens". Gate the list on the query state with QueryErrorCard
and retry, a skeleton while loading. Test watched fail first against the
old empty-state fall-through.
…ty states

The connected-assistants and connector-token queries had no error or
loading branch, so a failed read rendered "no connected assistants" or
"no active tokens" on this security surface. Gate both lists with
QueryErrorCard and retry, a skeleton while loading. Test watched fail
first against the old empty-state fall-through.
…y state

The tile already read the query's error flag but never branched on it, so
a failed reminder read fell through to "no upcoming checkup reminders" —
a missed preventive-care nudge hiding behind an honest-looking empty
state. Add a QueryErrorRow with retry before the empty check. Test
watched fail first against the fall-through.
… form

The three AI configuration reads each returned null on a non-OK response,
so a failed read painted the default provider form as if the account were
configured that way. Throw on a non-OK response so the query reports its
error, and render a QueryErrorCard with retry when any read fails. Test
watched the misleading form render first, then pass on the honest error.
The ECG detail rendered a read failure as a muted, non-recoverable line;
the routed list page had no error branch at all, leaving the shell
heading over an empty body that read the same as loading. The detail now
paints a QueryErrorCard with retry (an alert is content, not muted meta),
and the page shows the same instead of an empty shell. The overview teaser
still unmounts silently, which is right for the overview. Tests watched
each fail first.
…degradation

The mood-insights regions returned nothing on a failed read by documented
intent, degrading to the line chart. Enforce the honest-error standard
here too: on error the main region paints a QueryErrorRow with retry, once,
mirroring how the loading skeleton is scoped to that one region so the
three regions do not stack identical rows. Test watched the silent empty
first.
The cycle tabs rendered a bespoke error row in muted text, wrapped in a
bare card. Replace it with the shared primitives: QueryErrorCard on the
standalone prediction/insights/settings tabs, and a borderless
QueryErrorRow inside the calendar card so the failure reads as foreground
content with retry rather than muted meta. Test watched the muted row
first.
A family of settings surfaces rendered a failed read as a bare
text-destructive line with no way to recover: the security sessions,
trusted-devices and activity cards, the coach memory and reminders
sections, the about-me section, and the document link/share pickers. Swap
each to the shared QueryErrorRow primitive with a retry control. The suite
covering the statically renderable members was watched fail first against
the bare lines; the two portaled pickers take the same swap.
The section carried a bespoke muted error row with its own retry button —
the exact drift QueryErrorRow was made to absorb. Swap it for the shared
primitive so the failure reads as foreground content. Test watched the
bespoke row first.
…itive

Eight admin surfaces rendered a failed read as their own destructive-
tinted box, and most offered no way to recover. Sweep them onto the shared
QueryErrorRow with retry so the console uses one error form (§13). The
statically renderable sections were watched fail first against the
hand-rolled boxes.
Adding recoverable read-failure handling to thirteen surfaces and the MCP and
managed-record copy rewrites across six locales lifts the whole-build client
total to 3404 KB gz. Every per-route ceiling is still met; the aggregate cap
moves 3352 to 3428 with the same margin.
@MBombeck
MBombeck merged commit 18e9a80 into main Aug 9, 2026
23 checks passed
@MBombeck
MBombeck deleted the fix/honest-errors-and-security-copy branch August 9, 2026 04:30
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant