[QA] §R Discovery-pass fixes DP1–DP18: correctness, a11y/UX, TDS colours, refactor regression pass #187

Open
opened 2026-09-17 23:24:10 -04:00 by jared · 7 comments
Owner

Migrated from LOTUS_TESTING.md §R on 2026-09-17 — the file is now reference-only.

How to report: tick each item as it passes; on FAIL comment with what you saw vs expected, browser/OS, web (chat.lotusguild.org) vs desktop (Tauri), theme, and any browser-console errors. Screenshots for anything visual.

Checklist

  • Correctness
  • a11y / UX (needs a screen reader + a narrow viewport)
  • TDS colors (Lotus Terminal theme)
  • Refactor regression pass (no behavior change intended)

Agent-surveyed + TPVR-verified low/med issues, now fixed (commits 8eb961b6 db864326 6cf18c3b 165714e1 8c0e2b42 e545706c b1ee3ada 4fc3f7a3 101e4116 4fa4327a c2598d21). Behavioral items have concrete checks; the refactors just need a "still works" regression pass.

Correctness

  • DP1 — slash-command errors are visible. Run a slash command that must fail — e.g. /kick @nobody:server in a room where you lack permission, or /join a bad alias. Expected: an error toast appears (not a silent no-op); a successful command still clears the composer normally.
  • DP2 — no invite re-notify on reload. With ≥1 pending invite, hard-reload (Ctrl+F5). Expected: NO "you have N new invitation" toast/sound on load. Then have someone invite you while the app is open → you DO get one notification for the new invite. (👥 2 accounts)
  • DP3 — status clear syncs across devices. Set a status message on device A, confirm it shows on B; clear it on A. Expected: B clears too and does NOT re-publish the old status on its next presence heartbeat. Toggling Invisible must not wipe a real saved status. (👥 2 sessions)
  • DP4 — tag-toggle failure surfaced once. With the network offline, toggle a room's Favourite/Low-priority. Expected: a single error toast (not two) on failure; on success the tag updates as before.
  • DP5 — soundboard packs update on room switch. Open a soundboard in room A, then switch to room B (different pack) in the same mounted view. Expected: B's packs show without needing an unrelated event.
  • DP6 — declining a call still dismisses. Decline an incoming call. Expected: the ringing UI dismisses even if the decline send fails (best-effort). (👥 2 accounts)

a11y / UX (needs a screen reader + a narrow viewport)

  • DP7 / DP8 — call-control buttons announce correctly. In a call with a screen reader: the deafen button announces "Deafen" when sound is on (not "Undeafen"); Sound / Video / Screenshare announce a consistent pressed/unpressed state like Mic.
  • DP9 — GIF picker focus + width. Open the GIF picker, close it (Esc / click-out) → focus returns to the GIF button. On a ~320px viewport the picker doesn't overflow the page.
  • DP10 — search-filter clears by keyboard. In message search, toggle a filter chip (Has link / msg-type / pinned) off with Enter; the date-range clears via its menu's Clear. No mouse-only clear needed.
  • DP11 — voice recorder fits + announces. On a ~360px viewport, start a voice message → the recorder row doesn't overflow the composer; a screen reader can query the duration (role="timer") without being spammed.
  • DP12 — live-call count announced. With a screen reader, when someone joins/leaves an active call, the "{n} Live" change is announced (polite status region).

TDS colors (Lotus Terminal theme)

  • DP14 — send-status + receipt colors follow the theme. In TDS light mode: the message send-status "failed" icon and the read-receipt pill use the theme's darker red/blue (from --lt-* tokens), NOT bright dark-mode cyan/red. TDS dark still looks right; non-TDS themes unchanged.

Refactor regression pass (no behavior change intended)

  • DP13 — bookmarks / reminders / notes still work (they now share one store engine). Add/remove a bookmark, set/clear a reminder, write/clear a user note; each persists across reload; rapid consecutive writes don't clobber each other.
  • DP15 / DP16 — state-event + account-data writes still work. Edit room name/topic/avatar, join-rules, power levels, an emoji/soundboard pack (state events); toggle a setting stored in account data. All save + reflect correctly.
  • DP17 — link previews render. Open a TikTok / Spotify / Steam / Reddit link preview; provider icons render (folds icons, not raw glyphs) and brand colors look right.
  • DP18 — member avatars/names live-update. Read receipts + the "seen by" reader list show correct avatars/names and update live when a member changes their avatar or display name (no reload).

_Migrated from `LOTUS_TESTING.md` §R on 2026-09-17 — the file is now reference-only._ **How to report:** tick each item as it passes; on FAIL comment with what you saw vs expected, browser/OS, web (chat.lotusguild.org) vs desktop (Tauri), theme, and any browser-console errors. Screenshots for anything visual. **Checklist** - [ ] Correctness - [ ] a11y / UX (needs a screen reader + a narrow viewport) - [ ] TDS colors (Lotus Terminal theme) - [ ] Refactor regression pass (no behavior change intended) --- Agent-surveyed + TPVR-verified low/med issues, now fixed (commits `8eb961b6` `db864326` `6cf18c3b` `165714e1` `8c0e2b42` `e545706c` `b1ee3ada` `4fc3f7a3` `101e4116` `4fa4327a` `c2598d21`). Behavioral items have concrete checks; the refactors just need a "still works" regression pass. ### Correctness - [ ] **DP1 — slash-command errors are visible.** Run a slash command that must fail — e.g. `/kick @nobody:server` in a room where you lack permission, or `/join` a bad alias. **Expected:** an error toast appears (not a silent no-op); a successful command still clears the composer normally. - [ ] **DP2 — no invite re-notify on reload.** With ≥1 pending invite, hard-reload (Ctrl+F5). **Expected:** NO "you have N new invitation" toast/sound on load. Then have someone invite you while the app is open → you DO get one notification for the new invite. (👥 2 accounts) - [x] **DP3 — status clear syncs across devices.** Set a status message on device A, confirm it shows on B; clear it on A. **Expected:** B clears too and does NOT re-publish the old status on its next presence heartbeat. Toggling Invisible must not wipe a real saved status. (👥 2 sessions) - [ ] **DP4 — tag-toggle failure surfaced once.** With the network offline, toggle a room's Favourite/Low-priority. **Expected:** a single error toast (not two) on failure; on success the tag updates as before. - [ ] **DP5 — soundboard packs update on room switch.** Open a soundboard in room A, then switch to room B (different pack) in the same mounted view. **Expected:** B's packs show without needing an unrelated event. - [x] **DP6 — declining a call still dismisses.** Decline an incoming call. **Expected:** the ringing UI dismisses even if the decline send fails (best-effort). (👥 2 accounts) ### a11y / UX (needs a screen reader + a narrow viewport) - [x] **DP7 / DP8 — call-control buttons announce correctly.** In a call with a screen reader: the deafen button announces "Deafen" when sound is on (not "Undeafen"); Sound / Video / Screenshare announce a consistent pressed/unpressed state like Mic. - [x] **DP9 — GIF picker focus + width.** Open the GIF picker, close it (Esc / click-out) → focus returns to the GIF button. On a ~320px viewport the picker doesn't overflow the page. - [x] **DP10 — search-filter clears by keyboard.** In message search, toggle a filter chip (Has link / msg-type / pinned) off with Enter; the date-range clears via its menu's Clear. No mouse-only clear needed. - [x] **DP11 — voice recorder fits + announces.** On a ~360px viewport, start a voice message → the recorder row doesn't overflow the composer; a screen reader can query the duration (role="timer") without being spammed. - [x] **DP12 — live-call count announced.** With a screen reader, when someone joins/leaves an active call, the "{n} Live" change is announced (polite status region). ### TDS colors (Lotus Terminal theme) - [x] **DP14 — send-status + receipt colors follow the theme.** In **TDS light** mode: the message send-status "failed" icon and the read-receipt pill use the theme's darker red/blue (from `--lt-*` tokens), NOT bright dark-mode cyan/red. TDS dark still looks right; non-TDS themes unchanged. ### Refactor regression pass (no behavior change intended) - [x] **DP13 — bookmarks / reminders / notes still work** (they now share one store engine). Add/remove a bookmark, set/clear a reminder, write/clear a user note; each persists across reload; rapid consecutive writes don't clobber each other. - [x] **DP15 / DP16 — state-event + account-data writes still work.** Edit room name/topic/avatar, join-rules, power levels, an emoji/soundboard pack (state events); toggle a setting stored in account data. All save + reflect correctly. - [x] **DP17 — link previews render.** Open a TikTok / Spotify / Steam / Reddit link preview; provider icons render (folds icons, not raw glyphs) and brand colors look right. - [x] **DP18 — member avatars/names live-update.** Read receipts + the "seen by" reader list show correct avatars/names and update live when a member changes their avatar or display name (no reload). ---
jared added this to the Manual QA backlog milestone 2026-09-17 23:24:10 -04:00
jared added the uxqa labels 2026-09-17 23:24:10 -04:00
Author
Owner

Behavioral DP items verified on the local dev homeserver with Playwright:

item result
DP1 slash-command errors visible /join bad alias → "Command failed: The /join command failed. Please try again." ✓. /kick without permission → silent (documented in code; filed #216). Successful commands clear the composer ✓
DP2 no invite re-notify on reload pending invite → login: 0 toasts / 0 sounds; hard reload: 0 / 0; a new invite while open → notified (sound) ✓
DP4 tag-toggle failure surfaced once Favourite toggle while offline → exactly one toast "Failed: Could not update this room. Please try again." ✓
DP13 bookmarks store Save message → io.lotus.bookmarks account data written ✓ (reminders verified under #180, notes not exercised)
DP12 live-call count announcement bug found + fixed (RoomViewTyping.tsx) — not the call count itself, but the neighbouring typing live region announced "undefined, undefined, undefined and -3 others are typing" whenever nobody was typing (every room load). Fixed in the next commit.
DP3 status sync, DP5 soundboard packs, DP6 decline, DP7/8/11/12 screen-reader wording, DP9 GIF focus, DP10 keyboard chip clear, DP14 TDS colours, DP15-18 not exercised here (need a second device, a screen reader, calls, or visual judgment)

Leaving open for the remaining rows.

Behavioral DP items verified on the local dev homeserver with Playwright: | item | result | |---|---| | DP1 slash-command errors visible | `/join` bad alias → "Command failed: The /join command failed. Please try again." ✓. `/kick` without permission → **silent** (documented in code; filed #216). Successful commands clear the composer ✓ | | DP2 no invite re-notify on reload | pending invite → login: 0 toasts / 0 sounds; hard reload: 0 / 0; a **new** invite while open → notified (sound) ✓ | | DP4 tag-toggle failure surfaced once | Favourite toggle while offline → exactly **one** toast "Failed: Could not update this room. Please try again." ✓ | | DP13 bookmarks store | Save message → `io.lotus.bookmarks` account data written ✓ (reminders verified under #180, notes not exercised) | | DP12 live-call count announcement | **bug found + fixed (`RoomViewTyping.tsx`)** — not the call count itself, but the neighbouring typing live region announced **"undefined, undefined, undefined and -3 others are typing"** whenever nobody was typing (every room load). Fixed in the next commit. | | DP3 status sync, DP5 soundboard packs, DP6 decline, DP7/8/11/12 screen-reader wording, DP9 GIF focus, DP10 keyboard chip clear, DP14 TDS colours, DP15-18 | not exercised here (need a second device, a screen reader, calls, or visual judgment) | Leaving open for the remaining rows.
Author
Owner

More rows verified headlessly (2026-09-24, local Synapse + Playwright):

item result
DP9 GIF picker focus + width Bug found and fixed (e06600af). Esc closed the picker, but focus landed in the composer, not on the GIF button. The picker's focus trap did return focus correctly; then RoomView's "start typing → focus composer" handler treated Escape as a typing key and moved it. Escape (plus CapsLock, Insert, ContextMenu, PrintScreen, Pause) is now excluded. After the fix, Esc → focus on "Insert GIF" at 1300 px and at 320 px, and the 320 px picker fits with 0 px page overflow.
DP10 search filters by keyboard ✅ Keyboard only: "Has link" and "Pinned" toggle aria-pressed false → true → false with Enter; the date range is set via Enter on "Last week" and cleared with Enter on the menu's Clear (chip back to "Date range").
DP11 voice recorder fits + announces ✅ At 1300 px and 320 px (via More actions): recorder row causes 0 px overflow; the duration is role="timer" with no aria-live, so it can be queried without spamming.
DP14 TDS colours ✅ Lotus Terminal light: failed-send ✕ = rgb(181,0,31) (--lt-accent-red #b5001f); read-receipt pill border/bg = #0062b8 at 30 % / 7 %. Dark: ✕ = rgb(255,45,85) (#FF2D55), pill = #00D4FF. So both follow the theme tokens, not hard-coded dark-mode colours.

Note for anyone re-testing DP14: receipt pills are hidden while Settings → Privacy → hide activity is on (hideReadReceipts={hideActivity}), which is expected, but it looks like a failure if the test account has it on.

Still open: DP3, DP5, DP6 (two sessions or calls), DP7/8/12 (screen-reader wording), DP15-18.

More rows verified headlessly (2026-09-24, local Synapse + Playwright): | item | result | |---|---| | **DP9** GIF picker focus + width | **Bug found and fixed (`e06600af`).** Esc closed the picker, but focus landed in the **composer**, not on the GIF button. The picker's focus trap did return focus correctly; then RoomView's "start typing → focus composer" handler treated **Escape** as a typing key and moved it. Escape (plus CapsLock, Insert, ContextMenu, PrintScreen, Pause) is now excluded. After the fix, Esc → focus on "Insert GIF" at 1300 px and at 320 px, and the 320 px picker fits with 0 px page overflow. | | **DP10** search filters by keyboard | ✅ Keyboard only: "Has link" and "Pinned" toggle `aria-pressed` false → true → false with Enter; the date range is set via Enter on "Last week" and cleared with Enter on the menu's Clear (chip back to "Date range"). | | **DP11** voice recorder fits + announces | ✅ At 1300 px and 320 px (via More actions): recorder row causes 0 px overflow; the duration is `role="timer"` with no `aria-live`, so it can be queried without spamming. | | **DP14** TDS colours | ✅ Lotus Terminal light: failed-send ✕ = `rgb(181,0,31)` (`--lt-accent-red` #b5001f); read-receipt pill border/bg = `#0062b8` at 30 % / 7 %. Dark: ✕ = `rgb(255,45,85)` (#FF2D55), pill = `#00D4FF`. So both follow the theme tokens, not hard-coded dark-mode colours. | Note for anyone re-testing DP14: receipt pills are hidden while **Settings → Privacy → hide activity** is on (`hideReadReceipts={hideActivity}`), which is expected, but it looks like a failure if the test account has it on. Still open: DP3, DP5, DP6 (two sessions or calls), DP7/8/12 (screen-reader wording), DP15-18.
Author
Owner

More rows (2026-09-24):

item result
DP13 notes (the part not covered before) ✅ A note typed on bob's profile saves to io.lotus.user_notes, survives a reload (field shows it), and clearing it removes it from account data.
DP15 state-event writes ✅ Room Settings → Edit → topic → Save: m.room.topic on the server matches, and the settings view and room header show it.
DP17 link previews ✅ Provider badges render with brand colours (SoundCloud, Spotify, Steam, Reddit, TikTok), no raw glyphs. Bug found and fixed (fix(embeds) commit): the Steam card showed The "Perpetual Testing Initiative", because Steam double-encodes its meta tags. Preview text is now entity-decoded once where it's fetched, and it renders The "Perpetual Testing Initiative".

Still open: DP3, DP5, DP6 (two sessions or calls), DP7/8/12 (screen reader), DP16 (account-data settings toggle, largely exercised by settings sync), DP18.

More rows (2026-09-24): | item | result | |---|---| | **DP13** notes (the part not covered before) | ✅ A note typed on bob's profile saves to `io.lotus.user_notes`, survives a reload (field shows it), and clearing it removes it from account data. | | **DP15** state-event writes | ✅ Room Settings → Edit → topic → Save: `m.room.topic` on the server matches, and the settings view and room header show it. | | **DP17** link previews | ✅ Provider badges render with brand colours (SoundCloud, Spotify, Steam, Reddit, TikTok), no raw glyphs. **Bug found and fixed (`fix(embeds)` commit):** the Steam card showed `The "Perpetual Testing Initiative"`, because Steam double-encodes its meta tags. Preview text is now entity-decoded once where it's fetched, and it renders `The "Perpetual Testing Initiative"`. | Still open: DP3, DP5, DP6 (two sessions or calls), DP7/8/12 (screen reader), DP16 (account-data settings toggle, largely exercised by settings sync), DP18.
Author
Owner

DP3: was still broken; now fixed (fix(status) commit). Two sessions of the same user on local Synapse:

step before after
B saves "dp3 old status", then leaves Settings server "dp3 old status" same
A → Clear Status server "" server ""
B goes hidden → visible (heartbeat) server back to "dp3 old status" server stays "", and B's local copy is removed
A sets "dp3 new from A", B heartbeats — server keeps "dp3 new from A"; B adopts it

Cause: a device never receives its own user's presence changes made on other devices (B's presence store logged only its startup values). The earlier fix mirrored remote changes from inside the Profile page, so it could never fire. Heartbeats now GET our own presence and send the server's current status, falling back to the local copy on error, when invisible, or within 15 s of a local save.

**DP3: was still broken; now fixed (`fix(status)` commit).** Two sessions of the same user on local Synapse: | step | before | after | |---|---|---| | B saves "dp3 old status", then leaves Settings | server "dp3 old status" | same | | A → Clear Status | server "" | server "" | | B goes hidden → visible (heartbeat) | **server back to "dp3 old status"** | server stays "", and B's local copy is removed | | A sets "dp3 new from A", B heartbeats | — | server keeps "dp3 new from A"; B adopts it | Cause: a device **never receives its own user's presence changes made on other devices** (B's presence store logged only its startup values). The earlier fix mirrored remote changes from inside the Profile page, so it could never fire. Heartbeats now GET our own presence and send the server's current status, falling back to the local copy on error, when invisible, or within 15 s of a local save.
Author
Owner

DP6: ✅, plus an a11y bug found and fixed.

  • bob calls alice in their DM, and alice's decline send (org.matrix.msc4310.rtc.decline) is forced to fail (aborted). Pressing Reject still dismisses the ringing overlay, and the ring sound stops (no new oscillators over the next 2.5 s).
  • Fixed (fix(a11y) commit): the full-screen incoming-call overlay, shown when you aren't already in a call, had no role or accessible name on any ancestor of its buttons. A screen reader got a bare button and no "call ringing" cue. It is now role="alertdialog", aria-modal="true", labelled "Incoming voice call from bob". The in-call banner variant already had role="alert".
**DP6: ✅**, plus an a11y bug found and fixed. - bob calls alice in their DM, and alice's decline send (`org.matrix.msc4310.rtc.decline`) is forced to fail (aborted). Pressing **Reject** still dismisses the ringing overlay, and the ring sound stops (no new oscillators over the next 2.5 s). - **Fixed (`fix(a11y)` commit):** the full-screen incoming-call overlay, shown when you aren't already in a call, had **no role or accessible name** on any ancestor of its buttons. A screen reader got a bare button and no "call ringing" cue. It is now `role="alertdialog"`, `aria-modal="true"`, labelled "Incoming voice call from bob". The in-call banner variant already had `role="alert"`.
Author
Owner

DP7/8 — fixed; DP12 — present. Checked in a live call by reading what assistive tech is given (the exact speech still needs a real screen reader):

  • DP7 wording ✅ — the deafen button is "Deafen" while sound is on and "Undeafen" when deafened; mic "Turn off/on microphone"; camera/screenshare "Start/Stop …".
  • DP8 — bug fixed (fix(a11y): call toggles…). Those same buttons also carried aria-pressed, which contradicted the label: "Deafen" had pressed=true while you were not deafened (read as "Deafen, pressed"), and mic/screenshare had a pressed state in one bar but not the other. Since the labels already name the action, aria-pressed is removed from all nine toggles — now consistent in both bars and both states.
  • DP12 ✅ (structure) — the "N Live" chip carries a visually-hidden role="status" aria-live="polite" aria-atomic region reading "N in call", updated with the count; call-ended announcements have their own region outside the embed (#168).
**DP7/8 — fixed; DP12 — present.** Checked in a live call by reading what assistive tech is given (the exact speech still needs a real screen reader): - **DP7 wording ✅** — the deafen button is "Deafen" while sound is on and "Undeafen" when deafened; mic "Turn off/on microphone"; camera/screenshare "Start/Stop …". - **DP8 — bug fixed (`fix(a11y): call toggles…`).** Those same buttons *also* carried `aria-pressed`, which contradicted the label: "Deafen" had `pressed=true` while you were **not** deafened (read as "Deafen, pressed"), and mic/screenshare had a pressed state in one bar but not the other. Since the labels already name the action, `aria-pressed` is removed from all nine toggles — now consistent in both bars and both states. - **DP12 ✅ (structure)** — the "N Live" chip carries a visually-hidden `role="status" aria-live="polite" aria-atomic` region reading "N in call", updated with the count; call-ended announcements have their own region outside the embed (#168).
Author
Owner

Last batch (2026-09-24):

  • DP15/16: ✅ State events: the topic edit (above). Account data: toggling Monochrome Mode in Settings writes io.lotus.settings on the server (false → true), and toggling back restores false.
  • DP18: ✅ With the page left loaded (no reload): bob renames himself to "Bobby DP18", and the member list, the typing/"following the conversation" line, and the read-receipt pill on the next message he reads all show "Bobby DP18". Note on test design: a rename is a new m.room.member event from bob, so bob's receipt moves onto it (a user's own event counts as read). A pill that sat on an older message therefore disappears rather than "updating in place". That's receipt semantics, not a bug.

Remaining unticked: DP5 (soundboard packs on room switch; needs packs set up in two rooms) and the parts that need a real screen reader or device (the audio of DP7/8/12). Everything else in §R is verified.

Last batch (2026-09-24): - **DP15/16: ✅** State events: the topic edit (above). Account data: toggling **Monochrome Mode** in Settings writes `io.lotus.settings` on the server (`false → true`), and toggling back restores `false`. - **DP18: ✅** With the page left loaded (no reload): bob renames himself to "Bobby DP18", and the member list, the typing/"following the conversation" line, and the read-receipt pill on the next message he reads all show "Bobby DP18". Note on test design: a rename is a new `m.room.member` event *from* bob, so bob's receipt moves onto it (a user's own event counts as read). A pill that sat on an older message therefore disappears rather than "updating in place". That's receipt semantics, not a bug. Remaining unticked: **DP5** (soundboard packs on room switch; needs packs set up in two rooms) and the parts that need a real screen reader or device (the audio of DP7/8/12). Everything else in §R is verified.
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: LotusGuild/cinny#187