diff --git a/.planning/STATE.md b/.planning/STATE.md index d4379c0..702b7e3 100644 --- a/.planning/STATE.md +++ b/.planning/STATE.md @@ -66,8 +66,11 @@ settled. The gate earned its place; the hold was correct. `1a32f08`. Accepted deliberately: the collapse removed a class of seam rather than adding another guard. - No human screen-reader pass on the person picker. axe is clean across empty and - populated states, which is not the same thing. -- 21-05 Task 5 (human browser verification) was never performed. + populated states, which is not the same thing. **Consolidated 2026-08-10 into + `todos/pending/2026-08-10-person-picker-screen-reader-pass.md`** — see the + reassessment below. +- ~~21-05 Task 5 (human browser verification) was never performed.~~ **STRUCK + 2026-08-10 as superseded** — see below. ### The two carried gaps — one closed, one only narrowed (2026-08-09) @@ -94,6 +97,34 @@ whether the live-region timing is usable, or whether the four similarly-named groups are actually distinguishable in practice. A human with NVDA or VoiceOver remains worthwhile, and no automated result should be read as having replaced it. +### Reassessed 2026-08-10 — the two remaining items are ONE task + +Both were carried as prose here rather than as a todo, which is how they survived +two releases without moving. Reviewing them together: + +**21-05 Task 5 — STRUCK as superseded.** Phase 25 performed a genuine human pass +in a live editor (`25-VERIFICATION.md`, 2026-08-09), and recorded itself as such +precisely because this project had one checkpoint recorded the other way. It +covered the toolbar and the locked-checkbox row. It did NOT cover the person +picker or the four-group popover — so the residue is real, but it is the same +residue as the screen-reader item, not a separate one. + +**The screen-reader item slightly WIDENED, and now owns the residue.** Phase 25's +M2 change altered this same popover AFTER the v1.5.0 axe scan: the derived-locked +checkbox went from natively `disabled` to `aria-disabled`, so a control that +focus mode used to skip is now reachable and refuses its own toggle. That was the +right fix — the lock reason was written for assistive technology and could never +be heard while the row was skipped — but it changes tab order and announcement +sequence in exactly the component that has never had a human pass, and a +focusable-but-refusing control is not something automated tooling can evaluate +for comprehensibility. axe passes over it either way. + +Both now live in `todos/pending/2026-08-10-person-picker-screen-reader-pass.md` +as one task: one person, one sitting, VoiceOver or NVDA actually running. + +The original record of 21-05 Task 5 follows, kept because the distinction it +draws is the reason both were written down. + **21-05 Task 5 (human verification) — NOT PERFORMED AS SPECIFIED.** The plan marked it `autonomous: false` and called for a person driving the real editor in a browser before the phase closed. That did not happen. The phase was accepted @@ -166,10 +197,17 @@ not automatic and required a manual `workflow_dispatch`. Plan the step in. **Open, carried deliberately:** - ROLE-02's cloned-role "profiles" half is still deferred (`todos/pending/2026-08-02-cloned-role-hiding-profiles.md`) -- Phase 22 (Playground demo) and Phase 25 (toolbar polish) remain open -- The #128 fixes shipped unreviewed (the ultrareview ran against the prior commit) -- No human screen-reader pass on the person picker -- 21-05 Task 5 (human browser verification) was never performed +- Phase 22 (Playground demo) remains open. ~~Phase 25 (toolbar polish)~~ — + ✅ COMPLETE 2026-08-09, SHIPPED in v1.5.1 +- The #128 fixes shipped unreviewed (the ultrareview ran against the prior commit). + **Still true as of v1.5.1** — the mechanism is intact in `main`, touched since + only by #138's 20-line entity-collision fix. Closing it needs `/code-review ultra` + over `1a32f08..707d9b6`, which is user-triggered. +- No human screen-reader pass on the person picker → consolidated into + `todos/pending/2026-08-10-person-picker-screen-reader-pass.md` +- ~~21-05 Task 5 (human browser verification) was never performed~~ — **STRUCK + 2026-08-10 as superseded** by Phase 25's human pass; the residue merged into the + todo above ### Release Checklist (v1.4.0) @@ -404,6 +442,14 @@ Recent decisions affecting current work: and arbitrary SVG upload, which is a security feature wearing a UI feature's clothes and wants its own pass. `todos/pending/2026-08-09-icon-picker-remaining-scope.md` +- **Human screen-reader pass on the person picker** — consolidates the two + surviving v1.5.0 caveats into one task (21-05 Task 5 is struck as superseded by + Phase 25's human pass). axe is clean and still passing, which is not the same + claim: it cannot judge announcement sequence, live-region timing, or whether four + similarly-named groups are distinguishable by ear. Phase 25's M2 change made a + previously-skipped control focusable in that popover *after* the axe scan, so the + gap widened slightly. One person, one sitting, VoiceOver or NVDA actually running. + `todos/pending/2026-08-10-person-picker-screen-reader-pass.md` - **The release→deploy trigger is dead by construction** — `wp-deploy.yml` declares `release: types: [published]`, a path that has fired **zero times in six releases**; all six deploys were manual `workflow_dispatch`. Cause confirmed @@ -473,10 +519,21 @@ re-opening either question:** "fold versus width conflict" flagged on 2026-08-09 was mis-framed and is **withdrawn**: `160px` is just hardcoded in three places. -**Three things carried, not resolved** (also in the v1.5.0 milestone entry): -1. The #128 fixes shipped **unreviewed** — the ultrareview ran against the prior commit. -2. **No human screen-reader pass** on the person picker; axe is clean, which is not the same claim. -3. 21-05 Task 5 (human browser verification) was never performed; the phase was accepted on automated evidence. +**Reviewed 2026-08-10 — three carried items are now TWO, and both are actionable:** +1. **The #128 fixes shipped unreviewed.** Verified still live: `707d9b6` changed + 192 lines of `class-config.php` plus the logic modules, and that mechanism is + intact in `main` (touched since only by #138's 20 lines). It is the same + sanitize path in which the ultrareview found four consecutive holes, and it is + the one round no adversarial pass has ever seen. **Close with `/code-review + ultra` over `1a32f08..707d9b6`** — user-triggered and billed, so it needs Dan. + Highest value of the three, and the cheapest. +2. **The screen-reader pass**, now a real todo rather than prose: + `todos/pending/2026-08-10-person-picker-screen-reader-pass.md`. It absorbed + item 3 and slightly widened — Phase 25's M2 change made a previously-skipped + control focusable in that same popover *after* the v1.5.0 axe scan. +3. ~~21-05 Task 5 (human browser verification)~~ — **STRUCK as superseded.** Phase + 25 did a genuine human pass (`25-VERIFICATION.md`); it covered the toolbar and + the locked-checkbox row, not the person picker. That residue is item 2. **Environment gotcha:** another project's wp-env on this machine has claimed 8888/8889 and at times 8899. Check which ports are free before `wp-env start`, diff --git a/.planning/todos/pending/2026-08-10-person-picker-screen-reader-pass.md b/.planning/todos/pending/2026-08-10-person-picker-screen-reader-pass.md new file mode 100644 index 0000000..7d69f12 --- /dev/null +++ b/.planning/todos/pending/2026-08-10-person-picker-screen-reader-pass.md @@ -0,0 +1,87 @@ +--- +created: 2026-08-10T00:00:00.000Z +title: Human screen-reader pass on the visibility popover and person picker +area: a11y +files: + - assets/maestro.js (buildRoleGroup + the person picker — four similarly-named groups in one dialog) + - tests/e2e/specs/person-picker-a11y.spec.ts (the axe coverage this does NOT replace) + - .planning/phases/25-edit-mode-toolbar-dark-surface-polish/25-VERIFICATION.md (the human pass that closed the other half) +--- + +## Problem + +**Nobody has driven the person picker in a browser with a screen reader on.** + +This merges two items that were tracked separately across v1.5.0 and v1.5.1 and +have turned out to be one task. Both were carried as prose in STATE.md rather +than as a todo, which is how they survived two releases without moving. + +## What is actually covered, and what is not + +**Covered — axe-core.** `person-picker-a11y.spec.ts` scans the popover in BOTH +empty and populated states (the chips, results list and live-region messages only +exist after interaction, so an empty-state scan would miss most of what the +feature renders). Zero violations against wcag2a/2aa/21a/21aa, scoped to the +popover so wp-admin's own pre-existing findings don't train people to ignore the +suite. This still passes. + +**Covered — a human in a live editor, for the OTHER half.** Phase 25 was a real +human pass (`25-VERIFICATION.md`, 2026-08-09) and it deliberately records itself +as such because this project has one checkpoint recorded the other way. It +covered the toolbar and the locked-checkbox row. **It did not cover the person +picker or the four-group popover**, and it names no assistive technology. + +**Not covered — anything about sequence or sense.** axe catches +machine-detectable violations. It cannot tell you whether the announcements make +sense in order, whether the live-region timing is usable, or whether four +similarly-named groups ("Hide this item from:", "Hide its sub-items from:", and +their two person equivalents) are actually distinguishable by ear. No automated +result should be read as having replaced that. + +## Why this got slightly WORSE, not just older + +Phase 25's M2 change altered this same popover **after** the v1.5.0 axe scan: the +derived-locked checkbox moved from natively `disabled` to `aria-disabled`, so a +control that screen-reader focus mode used to skip entirely is now reachable and +refuses its own toggle. + +That was the right fix — the lock reason was written for assistive technology and +could never be heard while the row was skipped. But it changes tab order and +announcement sequence in exactly the component that has never had a human pass, +and "focusable control that declines to change" is a pattern automated tooling +cannot evaluate for comprehensibility. The axe suite passes over it either way. + +## The task + +One person, one sitting, roughly twenty minutes, with VoiceOver or NVDA actually +running: + +- Open the visibility popover on an item WITH sub-items, so all four groups are + present. Can you tell the four groups apart by ear alone? +- Tab to a derived-locked checkbox. Is the lock reason announced, and does it + arrive as a description after the name rather than tangled into it? +- Try to toggle it. Is the refusal comprehensible, or does it read as broken? +- Use the person search: type, wait for results, pick someone. Is the live-region + announcement timed usefully, or does it fire before or long after the results? +- Add and remove a chip. Is what happened announced? +- Dismiss by clicking outside. Does focus land somewhere sensible (Phase 25's M3 + fix should return it to the anchor)? + +## Not automatable, and not a code change + +The deliverable is a short findings note plus any defects it turns up — not a +patch. If it finds nothing, that is worth recording too: the claim "a human +listened to this" is one this project cannot currently make about its most +complex surface, and making it once is the point. + +## Supersedes + +- **21-05 Task 5** (human browser verification) — struck as superseded 2026-08-10. + The plan marked it `autonomous: false` and it was never performed; Phase 21 was + accepted on automated evidence, two Codex rounds, and Claude's own browser-driven + round-trip during 21-04. Phase 25 has since done a genuine human pass over part + of the editor. The residue that actually remains is this todo. +- The "screen-reader pass — narrowed, not closed" caveat carried in STATE.md + since 2026-08-09. + +Source: consolidated 2026-08-10 while reviewing the three carried v1.5.0 gaps.