fix(calls): remove misleading Retry button from call load error overlay (N96)

Both Retry and Leave called the same dismiss function; Retry implied a
reconnect attempt that never happened. Collapsed to a single Back button
that honestly describes returning to the prescreen.

docs: correct Gemini audit entries — sanitize-html not DOMPurify (Claim A),
retract inaccurate LiveKit replaceTrack soundboard approach (Claim B,
contradicts confirmed cross-origin iframe constraint), expand N95 fix note
to clarify track-stop vs AudioContext-suspend distinction.

docs(testing): add L1 N95 reproduction guide; update A7 to reflect single Back button.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-06-27 16:24:33 -04:00
parent 31cf353463
commit 91c6f2f091
4 changed files with 51 additions and 10 deletions
+20
View File
@@ -488,3 +488,23 @@ This document tracks identified bugs, edge cases, and architectural discrepancie
| N92 | Location "Open Location" Button | `MsgTypeRenderers.tsx` | 534547 | "Open Location" action link uses `<Chip as="a">` — compact badge-sized element — **FIXED**: replaced with `<Button as="a" variant="Secondary" fill="Solid" radii="300" size="400">` matching FileContent pattern | `FileContent.tsx` uses `<Button variant="Secondary" fill="Solid" radii="300" size="400">` for "Open File"/"Open PDF" |
| N93 | Location Coordinates Text | `MsgTypeRenderers.tsx` | 532 | `<Text size="T300" style={{ opacity: 0.65 }}>` — hardcoded non-standard opacity — **FIXED**: replaced with `<Text size="T300" priority="300">` | Secondary text uses folds `priority` prop; `0.65` is outside the token scale |
| N94 | Mention Highlight Border Invisible | `App.tsx` | 41 | `--mention-highlight-border` is set to the same value as `--mention-highlight-bg` — the border is invisible — **FIXED**: border is now `rgba(r,g,b,0.5)` — same hue as the background at 50% opacity, always visible | In folds, `color.*.ContainerLine` is always a lighter/muted sibling of `color.*.Container`, providing the 1px outline that gives mention chips visual definition |
---
#### 🔴 Additional Major Findings (Gemini)
**N95 — AFK Auto-Mute Keeps Hardware Mic Active While Muted**
- **File:** `src/app/hooks/useAfkAutoMute.ts`
- **Status:** **OPEN** [Gemini_Found]
- **Issue:** The `useAfkAutoMute` hook holds a persistent `MediaStream` from `getUserMedia` for the duration of the call. This causes the OS-level microphone recording indicator (e.g., green dot on macOS/iOS or camera/mic icon on Windows) to stay on even when the user mutes their microphone within the Lotus Chat UI.
- **Root Cause:** A separate parallel `MediaStream` is spawned instead of tapping into LiveKit/Element Call's managed local stream.
- **Fix:** Stop the `MediaStream` tracks (`.getTracks().forEach(t => t.stop())`) when `callEmbed.control.microphone` is false, and re-request `getUserMedia` when it turns back on. Suspending the `AudioContext` alone is **not sufficient** — it stops processing but does not clear the OS recording indicator; only stopping the tracks does. Optionally suspend the `AudioContext` alongside the track stop for CPU savings. Note: re-requesting `getUserMedia` on unmute adds a small latency and may trigger browser permission prompts on some configurations. Tapping into Element Call's local audio stream directly is architecturally cleaner but is not possible from Lotus — EC runs in a cross-origin iframe and its LiveKit `LocalAudioTrack` is inaccessible from our realm.
**N96 — Call Recovery "Retry" and "Leave" Buttons Perform Identical Actions**
- **File:** `src/app/features/call/CallView.tsx` (`CallLoadErrorMessage`)
- **Status:** **FIXED ⚠️ UNTESTED** [Gemini_Found] — needs verification: force a call load failure (offline the network right as you click join, or block the EC origin), confirm the error overlay shows a single **"Back"** button that returns to the prescreen cleanly.
- **Issue:** The `Retry` and `Leave` buttons in the call error overlay both executed the exact same `dismiss` function (`setCallEmbed(undefined)`), returning the user to the prescreen. "Retry" falsely implied it would automatically re-attempt joining the call. A true retry would require threading the previous `CallPreferences` into this component (via props or a Jotai atom) — a non-trivial change.
- **Root Cause:** Two identically-wired buttons with misleading labels; the simpler recovery path is a single honest label.
- **Fix Applied:** Removed the "Retry" button. Renamed "Leave" → "Back". One button, one clear action: returns to the prescreen where the user can manually click Join again to retry. Updated the code comment to match.