[P3] role="alert" warnings include the live ceiling value, so screen readers re-announce them every time the 0.1-unit value changes #114
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Priority: P3
Type: bug
Source: full codebase review requested 2026-10-31 (independently reproduced against
2cac7cf)Location:
src/App.tsx:1499-1504,src/App.tsx:1581-1611Problem and evidence
Two
role="alert"regions containdepthText(highCeiling, 1), the live ceiling rounded to 0.1 ft/m.role="alert"is implicitlyaria-live="assertive"andaria-atomic="true":.manual-ascent-warning: "...shallower than the gf-high ceiling of X ft...".critical-alerts: the ceiling line "...of X ft" and the surfaced line "...ceiling remains X ft". It also contains the "Sound becomes available..." paragraph.highCeilingis recomputed from the tissue state on every simulation tick. Each time the rounded value changes, the alert's text node changes. Assistive tech then interrupts and reads the whole alert again, for as long as the condition lasts. The two cited regions are the only alerts that contain the live number. The VPM-B metric and the stops panel are not alerts.I ran Playwright against the HEAD production build in /tmp/divesim-review-dist-SqbiNx, served on a private port.
Results for
.manual-ascent-warning(role=alert):In my runs the
.critical-alertspanel did not appear during the observation window. Its ceiling and surfaced paragraphs use the samedepthText(highCeiling, 1)interpolation inside the same kind of atomic alert, so the mechanism is identical by code trace. The original reviewer also observed it churning (17 mutations in 5 s).Suggested correction
Keep the text inside role="alert" static while the condition holds, for example "Ascent target is above the current ceiling" or "Above the decompression ceiling". Render the live ceiling number in a sibling element outside the alert: a plain paragraph, or at most a polite/off live region updated only on coarse changes. Alternatively, mark the number span
aria-hiddenand put a fixed-precision snapshot taken when the alert starts into the announced text. Also move the "Sound becomes available..." paragraph out of the critical alert so it is not re-read whenever the alert updates.Acceptance criteria
A Playwright regression test (131 ft at 128x with override until deco is required, then 8x and Surface) uses a MutationObserver on [role=alert] for 10 s or more. It should record at most one text per alert condition: the alert text must not change while only the ceiling value changes. The visible ceiling number must still update in a non-alert element. The same check should cover
.critical-alertsin both the ceiling-violation and surfaced-with-ceiling states. pnpm verify passes.Scope: maintenance of the educational simulator. Preserve historical R1 acceptance and operational-validation limits.