Files
cinny/LOTUS_BUGS.md
T
jared 6ec0ab78d9
CI / Build & Quality Checks (push) Successful in 10m30s
Trigger Desktop Build / trigger (push) Successful in 6s
fix: LIGHT variant bg animations, decoration grid spacing, bug doc updates
- chatBackground.ts: remove animRainGlowKeyframe and animGridBrightnessKeyframe
  from LIGHT anim-rain and anim-pulse definitions (these were removed from the
  import and from DARK variants in the previous session but the LIGHT variants
  were missed, leaving stale references that would cause a build error)
- ProfileDecoration.tsx: increase decoration grid gap 20→36 (visual gap was
  only 4px due to 8px image overflow beyond each 52×52 button), fix paddingBottom
  4→8 and add paddingRight:8 to prevent edge clipping
- LOTUS_BUGS.md: correct bug #8 root cause (CSP, not lazy-loading), add
  bugs #9 (grid spacing) and #10 (Windows taskbar badge)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-14 13:19:11 -04:00

12 KiB
Raw Blame History

Lotus Chat — Bug Report & Technical Audit

Date: June 2026

This document tracks identified bugs, edge cases, and architectural discrepancies found during the audit of the Lotus Chat codebase. Recommended fixes are provided for each item.


🛡️ Critical Security & Privacy Regressions

File: src/app/features/room/MediaGallery.tsx (Line 855) Status: CRITICAL

  • Issue: The "Download" button in the Files tab uses mxcUrlToHttp directly and clicks an <a> link.
  • Impact: In encrypted rooms, this downloads the encrypted ciphertext rather than the decrypted file. Users cannot open the downloaded files.
  • Recommended Fix:
    1. Check if the event is encrypted.
    2. If encrypted, use the decryptAttachment logic (similar to useDecryptedMediaUrl) to decrypt the file in memory.
    3. Use file-saver or a Blob URL to trigger the download of the decrypted plaintext.

2. Privacy Leak in URL Previews

File: src/app/components/url-preview/UrlPreviewCard.tsx (Line 1655) Status: PRIVACY RISK

  • Issue: Generic URL preview cards fetch favicons directly from https://www.google.com/s2/favicons?domain=....
  • Impact: This leaks the user's browsing/chat activity (domains of links they see) to Google. It bypasses the "proxied through Matrix" privacy standard.
  • Recommended Fix: Use the proxy URL returned by the Matrix /_matrix/media/v3/preview_url endpoint instead of contacting Google directly.

🚩 Functional & Logic Bugs

1. Presence Updater Reverts Status Updates

File: src/app/hooks/usePresenceUpdater.ts (Line 20) Status: RESOLVED (June 2026)

  • Issue: The storedStatus variable was captured once when the useEffect started.
  • Impact: If a user updated their status message in Profile Settings, the hook would continue broadcasting the old message on every activity event, silently reverting the change.
  • Fix Applied: Replaced the single localStorage.getItem read with a readStatus() function called inside every setOnline and setUnavailable invocation, ensuring the current value is always used.

2. Audio Playback Rate Reset

File: src/app/components/message/content/AudioContent.tsx (Line 97) Status: UX Bug

  • Issue: The playbackRate is set in a useEffect that only depends on [playbackSpeed].
  • Impact: If a user selects a playback speed before the audio blob has finished loading, the <audio> element may reset its rate to 1.0 once the <source> is added.
  • Recommended Fix: Add srcState.data to the useEffect dependencies or set the playbackRate in an onCanPlay handler on the audio element.

3. Room Insights are Static (No Live Updates)

File: src/app/features/room-settings/RoomInsights.tsx (Line 60) Status: Medium Priority

  • Issue: Stats are calculated in a useMemo that only depends on [room].
  • Impact: If new messages arrive while the Insights page is open, the statistics (message counts, top participants, etc.) do not update.
  • Recommended Fix: Add a listener for RoomEvent.Timeline inside the component to trigger a recalculation when new events are added to the room.

4. Incorrect Ringing in Voice Rooms

File: src/app/components/CallEmbedProvider.tsx Status: RESOLVED (June 2026)

  • Issue: Joining a static voice room (Public Space channel) triggered the "Incoming Call" ringing animation and sound.
  • Root Cause: getStateEvent(room, StateEvent.SpaceParent) always returned undefined because m.space.parent events use the parent space's room ID as the state key, not an empty string. The ringing suppression check silently failed.
  • Fix Applied: Replaced getStateEvent with getStateEvents (plural), which returns all events of a given type regardless of state key. A room with any m.space.parent event is correctly identified as a space channel and suppresses ringing.

🎨 UI/UX & Visual Consistency

1. Hardcoded Primary Color in Polls

File: src/app/components/message/content/PollContent.tsx (Line 245) Status: TDS Violation

  • Issue: Uses rgba(var(--mx-primary-rgb, 0,132,255), ...) for selected options and borders.
  • Impact: Polls look like standard Cinny and ignore the Lotus Terminal Design System (TDS) colors.
  • Recommended Fix: Use var(--lt-accent-cyan) or the primary theme accent color.

2. Inaccessible Room Menu on Mobile

File: src/app/features/room-nav/RoomNavItem.tsx (Line 643) Status: MOBILE BUG

  • Issue: The room menu icon (VerticalDots) is hidden on mobile because hover is never active.
  • Impact: Mobile users cannot access room settings, mark as read, or leave rooms from the sidebar.
  • Recommended Fix: Ensure the menu button is visible on mobile for the active room or provide an alternative trigger.

3. Inconsistent Settings Dropdown Styling

File: src/app/features/settings/general/General.tsx Status: RESOLVED (June 2026)

  • Issue: The dropdowns for "Join & Leave Sounds", "UI Font", and "Seasonal Theme" used raw HTML <select> elements, which render differently from the custom-styled Menu+PopOut used for "Message Layout" and other settings.
  • Fix Applied: All three raw <select> elements replaced with a reusable SettingsSelect component using the Menu+PopOut+FocusTrap pattern consistent with the rest of the settings UI.

4. No Camera Focus During Screenshare

File: src/app/features/call/CallControls.tsx Status: UX Bug — blocked by Element Call internals

  • Issue: When someone is screensharing and another participant turns on their camera, there is no way to switch the primary display to the camera or go fullscreen on it.
  • Root Cause: Element Call's spotlight/layout is controlled internally by EC. Lotus Chat injects the call iframe and cannot easily override EC's participant tile behavior without forking the EC widget.
  • Recommended Fix: Implement a "Pin/Focus" toggle on participant tiles that overrides the automatic screenshare spotlight — requires EC upstream changes or a custom message bridge.

5. Ringing Modal Fires in Persistent Voice Rooms

File: src/app/components/CallEmbedProvider.tsx (line 337342) Status: RESOLVED (June 2026)

  • Issue: Joining a persistent voice room (not a DM or transient group call) showed the incoming call ringing modal and animation.
  • Root Cause: The isPrivateGroup condition included JoinRule.Restricted and JoinRule.Knock rooms. Lotus Guild voice rooms are Restricted join-rule rooms. Their m.space.parent state event was being checked but some rooms were set up with only the space-side m.space.child relationship, leaving no m.space.parent on the room itself — so they passed as isPrivateGroup and triggered ringing.
  • Fix Applied: Narrowed isPrivateGroup to only JoinRule.Invite to match the exact set of rooms where the call button is shown. Also added room.isCallRoom() early-exit so rooms with m.join_rule.call type never ring.

6. Animated Chat Backgrounds Affect Message Content

File: src/app/features/lotus/chatBackground.ts Status: RESOLVED (June 2026)

  • Issue: Animated backgrounds that use filter: brightness() or opacity animations (Digital Rain glow, Grid Pulse brightness, Fireflies glow/blink) applied those effects to the entire <Page> element, causing all message content and the composer to flash/flicker in sync with the animation.
  • Root Cause: filter and opacity CSS properties affect an element AND all its descendants. Applying these as part of the animation shorthand on the Page container made them "inherited" visually by everything inside the room view.
  • Side Effect: filter animation also created a CSS stacking context on Page, which pushed Seasonal Theme overlays (position:fixed; z-index:9997) behind the Page compositor layer.
  • Fix Applied: Removed animRainGlowKeyframe, animGridBrightnessKeyframe, animFirefliesGlowKeyframe, and animFirefliesBlinkKeyframe from chatBackground.ts. Only backgroundPosition / backgroundSize animations remain — these are safe and do not affect descendants or create stacking contexts.
  • Follow-up (June 2026): The initial fix only removed glow/brightness keyframes from the DARK variant definitions. The LIGHT variant anim-rain and anim-pulse entries still referenced animRainGlowKeyframe and animGridBrightnessKeyframe (which were no longer imported, causing a build error). Both references removed from LIGHT variants to complete the fix.

7. Seasonal Themes Display Behind Chat Background

File: src/app/components/seasonal/SeasonalEffect.tsx Status: RESOLVED (June 2026) — root cause was Bug #6

  • Issue: Seasonal theme overlays (position:fixed; z-index:9997) appeared behind animated chat backgrounds.
  • Root Cause: The filter animation on <Page> created a CSS stacking context, causing Page's GPU compositing layer to render above the fixed-position seasonal overlay in some browsers. Removing the filter animations (Bug #6 fix) resolves the stacking context issue.
  • Fix Applied: See Bug #6. No additional changes to SeasonalEffect required.

8. Avatar Decoration Images Not Rendering in Settings

File: src/app/features/settings/account/ProfileDecoration.tsx / LXC 106 nginx Status: RESOLVED (June 2026)

  • Issue: Under Settings → Account → Avatar Decoration, no decoration images were visible.
  • Initial (incorrect) diagnosis: Suspected loading="lazy" in a nested scroll container. Changed to loading="eager" — images still did not render.
  • Actual Root Cause: The server nginx Content Security Policy (img-src directive) on LXC 106 did not include https://drive.lotusguild.org. The browser silently blocked all 99 APNG requests with CSP violation errors (206 violations visible in DevTools console). The lazy-loading change was a red herring.
  • Fix Applied: Added https://drive.lotusguild.org to the img-src directive in /etc/nginx/sites-available/cinny on LXC 106 (cinny-web-server) and reloaded nginx. Updated config is tracked in pve-infra/containers/106-cinny-web-server/etc/nginx/sites-available/cinny.

9. Avatar Decoration Grid Spacing Too Tight

File: src/app/features/settings/account/ProfileDecoration.tsx Status: RESOLVED (June 2026)

  • Issue: Decoration preview cells in the settings picker appeared vertically and horizontally squished together with almost no gap between images.
  • Root Cause: The flex container used gap: 20px, but each 52×52 button renders its decoration image with position: absolute; top: -8px; left: -8px (INSET=8), so each image bleeds 8px outside the button on all sides. The visual gap between images was 20 - 8 - 8 = 4px — nearly nothing. Additionally paddingBottom: 4 clipped the bottom overflow of the last row, and paddingRight was absent so the rightmost column clipped.
  • Fix Applied: Increased gap from 20 to 36 (visual gap = 36 - 8 - 8 = 20px), changed paddingBottom from 4 to INSET (8px), added paddingRight: INSET.

10. Windows Taskbar Badge Has Black Square Background and Small Number

File: src-tauri/src/lib.rs (cinny-desktop) — set_badge_count command Status: RESOLVED (June 2026)

  • Issue: The notification badge overlaid on the Windows taskbar icon had a solid black square background instead of a transparent circle, and the number was too small to read at a glance.
  • Root Cause (black square): CreateDIBSection initialises the pixel buffer to zero (BGRA 0x00000000). GDI drawing functions (Ellipse, DrawTextW) paint RGB values but never touch the alpha channel — all pixels retain A=0. When every pixel has A=0, Windows cannot use per-pixel alpha compositing and falls back to the monochrome mask (hbm_mask, all zeros = fully opaque), so the entire 16×16 bitmap is drawn opaque. The corner pixels outside the ellipse are RGB(0,0,0) = black, producing the black square.
  • Root Cause (small number): Bitmap was 16×16 with an 11px font, giving very little room, especially for two-digit counts.
  • Fix Applied:
    1. After all GDI drawing, iterate the pixel buffer and set alpha = 0xFF for every non-zero pixel (*pixel |= 0xFF00_0000). Corner pixels (zero) retain A=0 and composite as transparent.
    2. Increased bitmap size from 16 to 20 and font height from 11 to 14.