Accessibility and testing

Troubleshooting

Fix missing, repeated, late, delayed, or noisy announcements by checking each step from the framework event to the browser update.

Nothing is announced

First check that the runtime receives a started event, new text only, and one completed, failed, or interrupted event with the same response ID. Then check runtime diagnostics and the browser result separately.

  • Confirm the announcement listener or DOM binding is attached before dispatch.
  • Complete a sentence or dispatch response.completed so buffered text can flush.
  • Check for policy-silent, empty-text, unknown-response, or runtime-disposed diagnostics.
  • Check DOMDeliveryResult for unavailable or disposed delivery.
  • A successful page update does not confirm what a screen reader spoke. Test that separately.

Output repeats or arrives too often

response.text.delta must contain only the text that just arrived. If you send the full response every time, earlier text may be announced again.

  • Dispatch append-only deltas rather than accumulated message text.
  • Keep responseId and responseInstanceId stable for one active attempt.
  • Increase text.minimumCharacters or minimumGapMs when valid updates are too granular.
  • Inspect duplicate and coalesced diagnostics before changing policy.

Old output appears after retry

A retry must replace the active response attempt. Core ignores late updates from older attempts and reports stale-response diagnostics.

  • Send response.retrying with the replaced and next response instance IDs.
  • Attach the new responseInstanceId to each later text event and final event.
  • Do not reuse a completed or interrupted response instance.
  • If the framework does not provide retry IDs, report retry events directly from your app instead of guessing.

Tool progress is too noisy

Keep each tool ID stable and use short, translated labels. To reduce noise, adjust the start delay and progress settings instead of filtering announcements after they are created.

  • Delay tool starts with tools.announceStartAfterMs so fast operations can finish quietly.
  • Raise tools.progressEveryPercent or disable progress announcements.
  • Never copy raw arguments, results, or backend errors into user-facing labels.

Use diagnostics to find the first problem

Each diagnostic says what the runtime did and why. Start with the first unexpected result instead of looking only at the final browser update.

ReasonMeaningFirst check
policy-silentActive policy suppresses this eventPreset and explicit policy overrides
unknown-response or unknown-toolNo active matching identity existsStarted event order and IDs
stale-response or stale-toolEvent belongs to a replaced executionInstance identity propagation
progress-thresholdProgress did not cross the configured bucketprogressEveryPercent
queue-capacityBounded scheduler rejected additional workProducer rate and maxQueueSize
delivery-errorEvery announcement listener failedListener exceptions and onDeliveryError
deliveredListeners accepted the prepared announcementCheck the DOM result, then test with a screen reader

Inspect a redacted trace during development

Use @generative-a11y/devtools when a single diagnostic is not enough to explain the event sequence. Its bounded store connects source events, runtime decisions, snapshots, and optional DOM delivery results without retaining response text, labels, tool data, or page content.

  • Attach the store to an existing runtime and give that runtime a stable development ID.
  • Forward DOMDeliveryResult values to recordDelivery when you need browser correlation.
  • Pause or clear capture without changing runtime scheduling or browser delivery.
  • Treat the trace as debugging evidence, not proof of screen-reader speech.