Repository navigation
Description
Implementation: FlyBot (ours) — PR follows within 24h. Do not pick up without a pickup-ok comment on this issue.
Written-by: FlyBot Lead
Claimed-by: FlyBot Lead
Claim-Id: c72b3131ad0140a8b3dfd681f98e9d00
Branch: dev/1-single-refusal-alert
Base: 77a6b4d
At: 2026-11-02T16:26:46Z
Owner: Dev-1
Tier: T2
What happens today
A refused Rename / Delete / Create now keeps its dialog and shows the host's sentence inside it (#2193, fixed in the PR that this issue follows). But the page keeps its own copy of the same sentence in a page-level role="alert", so one refusal produces two live-region announcements of the same words.
Measured by FlyBot Test on 3f8e951312ecf1bb9a3c28b30a3358d6df14861d: RENAME_ALL=2, BEFORE_REOPEN_ALL=2, with one of each pair living in the sidebar's .wf-err. role="alert" is a live region — a visual mask does not hide it from the accessibility tree, so a screen-reader user hears the same refusal twice.
This is not the same as "the old node is still drawn but covered": the covered copy is still in the DOM and still announced. The write target of #2193 was "readable inside the dialog"; this issue is "exactly once, in the accessibility tree".
Expected behaviour
One refusal is announced once. Either the page-level copy stops rendering for a refusal the dialog is showing, or it stays in the DOM with aria-hidden="true" — decided by whichever keeps the page's own error reporting intact for refusals that have no dialog. Visual masking is not an answer.
Scope
plugins/workflow/client.js— the page-levelwf-err(the one around:2205-2206at the tip) and the dialog's copies (:1394,:1408,:1516,:1659) must not both announce the same refusal. The existing refusal and success paths are otherwise unchanged, and a refusal that has no dialog still reports as it does today.plugins/workflow/test/client.test.js— the red-first test below.docs/subsystems/workflow.mdandchangelog.d/<this issue>-single-refusal-alert.fixed.md.
Reproduction (red first)
Count role="alert" over the whole rendered tree, not inside the dialog. At the tip, opening Delete and letting the host refuse yields two nodes carrying the same sentence; the test asserts exactly one.
The shape matters and is part of the acceptance: the existing assertions introduced by #2193 all search inside role="dialog", which is precisely why the duplicate was not caught. This test must use the whole-tree helper (alertsOf(settings)-style) and assert:
- the whole tree carries exactly one
role="alert"for the refusal; - its text is the host's sentence verbatim;
- it is inside the open dialog (the dialog is where the action happened).
A second test covers the case that must not regress: a refusal with no dialog open still produces exactly one announcement, as it does today.
Three criteria (binding)
- In the whole tree — not only inside the dialog — a refusal may carry only one
role="alert". - A node that is under a mask must be
aria-hidden="true"or not rendered at all; visual occlusion alone is not acceptable. - The red-first assertion counts alerts over the whole tree shape, never
findAll(dialog, …).
Prior art / duplicates
Searched before opening (announced twice, duplicate role=alert, wf-err alert screen reader):
#2193— the refusal being invisible inside the dialog; this issue is the opposite face of the same refusal (announced twice), filed while the fix was in review, per the rule that a known gap lives in the issue thread rather than in a pull-request body edited after CI started.#1521/#1522— a stage control reporting silently; different surface, closed.#2187— the read-only edit surface; unrelated.
No open or closed issue counts role="alert" over the whole tree for a refused Workflow edit.
Acceptance
- One refusal, one
role="alert"in the whole tree, carrying the host's sentence verbatim. - The covered page-level node is either absent or
aria-hidden="true"; the test proves it through the accessibility-relevant attribute, not through geometry. - A refusal without a dialog still announces exactly once.
- The new test fails before the fix and passes after;
plugins/workflowsuite green,npm run verifygreen,arch-docs: OK.
Activity
workflow: announce a refused dialog edit once, not twice (ThinkFlowLa…
workflow: a refused dialog edit is announced once, not twice (ThinkFl…
HugoXK commentedon Nov 2, 2026
Release
Written-by: FlyBot Lead
Released: c72b3131ad0140a8b3dfd681f98e9d00
Reason: merged via PR #2212 (2a0bbb2)
At: 2026-11-02T19:46:24Z
workflow: a refused dialog edit is announced once, not twice (ThinkFl…