Files
cinny/LOTUS_BUGS.md
T
jared a77c4b6db5
CI / Build & Quality Checks (push) Successful in 10m29s
CI / Trigger Desktop Build (push) Successful in 15s
feat(calls): configurable ringtone volume in Settings (Bug #4 partial)
Adds 'Ringtone Volume' slider (0–100, default 70%) to Settings → Calls.
The IncomingCall audio element reads the setting and applies it as
audioElement.volume before playing, replacing the implicit browser
default of 1.0.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-18 18:56:04 -04:00

36 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 & UI Bugs

1. No Camera Focus During Screenshare

  • File: cinny/src/app/features/call/CallControls.tsx
  • Status: OPEN
  • Issue: Automatic screenshare spotlighting forces primary display override, preventing users from manually focusing on camera feeds.
  • Root Cause: Current spotlighting logic prioritizes active screenshare streams over manual participant selections, effectively ignoring or overriding user-initiated focus states.
  • Proposed Fix: Introduce a manual 'Focus' state that takes precedence over automatic screenshare spotlighting, implemented via a toggle/click UI on participant tiles. Update the video renderer to respect this manual override.

2. Chat Background Animation Flickering

  • File: cinny/src/app/features/lotus/chatBackground.ts
  • Status: FIXED ⚠️ UNTESTED — needs verification on a real device with an animated background active
  • Issue: Animated background properties cause visible flickering on message text and the composer area, particularly on browsers/GPUs susceptible to repaint-induced artifacts.
  • Root Cause: Animation triggers excessive repaints or layout recalculations on descendant elements, likely due to animating non-GPU accelerated properties on parent containers without proper rendering context isolation.
  • Fix Applied: getChatBg() now injects willChange: 'background-position' and contain: 'paint' for any animated variant. This promotes the element to its own compositor layer and isolates repaints from descendants. Background-position animation is already GPU-hinted on modern browsers; contain: paint prevents descendant elements from being invalidated during each frame.

3. Avatar Decorations in Element Call

  • File: cinny/src/app/components/avatar-decoration/AvatarDecoration.tsx
  • Status: OPEN
  • Issue: Avatar decorations are failing to render within the call/room interface member lists.
  • Root Cause: Likely a mismatch between the expected member object structure required by the AvatarDecoration component and the data actually provided by the call/room UI components. Matrix event data for decorations might not be propagating correctly to these UI member objects.
  • Proposed Fix: Analyze the data propagation chain from Matrix events to the member object in cinny/src/app/components/call and room, ensuring that decoration-related properties are correctly mapped and passed to the AvatarDecoration component.

4. DM and Group Message Calls

  • File: cinny/src/app/components/CallEmbedProvider.tsx
  • Status: PARTIALLY FIXED ⚠️ UNTESTED — Volume control added. Remaining: ringtone selection, suppression during active calls.
  • Issue: Incoming call ringtone is hardcoded, lacks volume control, and is suppressed if the user is already in an active call.
  • Root Cause: Ringing logic is tightly coupled to RTCNotification events in CallEmbedProvider.tsx, using a hardcoded audio file path. It lacks an abstraction for sound management or user-configurable settings for ringtones/volumes.
  • Fix Applied: Added ringtoneVolume setting (0100, default 70). IncomingCall reads this setting and applies audioElement.volume = ringtoneVolume / 100 before play(). Slider added to Settings → General → Calls section.
  • Remaining: (a) Ringtone selection (still hardcoded to call.ogg); (b) Suppression during active calls — not investigated.

5. Seasonal Themes and Chat Backgrounds Design

  • File: cinny/src/app/hooks/useTheme.ts, cinny/src/app/features/lotus/chatBackground.ts
  • Status: OPEN
  • Issue: Basic CSS or random moving lines are insufficient for high-fidelity wallpaper/theming. They lack professional design theory, coherence, and aesthetic depth.
  • Root Cause: Current implementation relies on basic CSS, lacks advanced design theory, and does not leverage modern, performant CSS wallpaper techniques.
  • Proposed Fix (Extreme Depth Redesign):
    • Research-Backed Implementation: Implement advanced design techniques (layered oklch gradients, backdrop-filter for refractive "liquid glass" effects, GPU-accelerated transform animations) to create living, breathing backgrounds.
    • Performance Optimization: Ensure all animations strictly use compositor-thread properties (transform, opacity) and apply contain: paint / will-change: transform to prevent layout thrashing/flickering.
    • Design Resources (Examples/Inspiration):
    • Goal: Treat each theme/background as a week-long development sprint to ensure professional polish, WCAG AA contrast compliance for overlaying UI, and seamless integration with the Lotus TDS.

6. Exclusive Background vs. Seasonal Choice

  • File: cinny/src/app/state/settings.ts
  • Status: FIXED ⚠️ UNTESTED — needs verification: (a) pick a background, confirm seasonal theme auto-clears; (b) pick a seasonal theme, confirm background auto-clears; (c) set both via old localStorage data and reload, confirm SeasonalEffect guard suppresses the overlay
  • Issue: Concurrent application of both Chat Backgrounds and Seasonal Themes causes visual clutter and high GPU usage.
  • Root Cause: These are currently handled as independent settings in the settingsAtom and applied simultaneously without mutual exclusion.
  • Fix Applied: Mutual exclusion enforced at two layers: (1) General.tsx — ChatBgGrid clears seasonalThemeOverride→'off' when any non-'none' background is picked; SeasonalBgGrid clears chatBackground→'none' when any real seasonal theme is selected. (2) SeasonalEffect.tsx — runtime guard returns null if chatBackground !== 'none', protecting against legacy persisted state.

7. Tiny Touch Targets in Composer Toolbar

  • File: cinny/src/app/features/room/RoomInput.tsx
  • Status: FIXED ⚠️ UNTESTED — needs verification on a real mobile device: open composer, confirm all toolbar buttons are tappable without mis-taps
  • Issue: Toolbar buttons have hit areas smaller than the WCAG-recommended 44x44px for touch, hindering mobile accessibility.
  • Fix Applied: Added touchTarget = { minWidth: '44px', minHeight: '44px' } computed from mobileOrTablet() and applied as style={touchTarget} to all 8 composer toolbar IconButton elements (attach, format, sticker, emoji, GIF, location, poll, schedule, send).

8. Horizontal Overflow in Room Settings

  • File: cinny/src/app/components/page/style.css.ts
  • Status: FIXED ⚠️ UNTESTED — needs verification: open Room Settings on a narrow mobile screen, confirm nav panel fills full width and no horizontal scrollbar appears
  • Issue: Wide tables and input elements in room settings cause horizontal overflow on mobile viewports.
  • Fix Applied: Added @media (max-width: 750px) { width: '100%' } to both '400' and '300' size variants of the PageNav vanilla-extract recipe in style.css.ts.

9. Modal Float-Style Responsiveness

  • File: Multiple modal files
  • Status: FIXED ⚠️ UNTESTED — needs verification by opening each modal on a real mobile device
  • Issue: Modals appear as floating boxes on mobile, creating navigation and readability challenges.
  • Fix Applied: Created useModalStyle(desktopMaxWidth) hook (src/app/hooks/useModalStyle.ts) that returns fullscreen styles on mobile (no border-radius, no max-width, height: 100%) and desktop box styles otherwise. Applied to all 22+ modal files: LeaveRoomPrompt, LeaveSpacePrompt, ReportRoomModal, ReportUserModal, DeviceVerification, InviteUserPrompt, LogoutDialog, DeviceVerificationSetup, DeviceVerificationReset, JoinAddressPrompt, JumpToTime, EditHistoryModal, ForwardMessageDialog, RemindMeDialog, CreateRoomModal, CreateSpaceModal, ScheduleMessageModal, PollCreator, AddExistingModal, RoomEncryption, RoomUpgrade, Modal500, ReadReceiptAvatars, RoomTopicViewer.
  • Note: UIAFlowOverlay already fullscreen via <Overlay> — no change needed. JoinRulesSwitcher/RoomNotificationSwitcher are dropdowns, not modals.

10. Composer Keyboard Obscurity

  • File: src/index.css
  • Status: FIXED ⚠️ UNTESTED — needs verification on iOS Safari specifically (the worst offender); on Android Chrome 100dvh has been standard since Chrome 108
  • Issue: The chat composer is often partially or fully obscured by the virtual keyboard on mobile.
  • Fix Applied: Added height: 100dvh (dynamic viewport height) to html alongside the existing height: 100% fallback. dvh updates when the software keyboard appears, ensuring the layout shrinks correctly and the composer stays visible.

11. Inline Jotai atom creation

  • File: cinny/src/app/hooks/useSpaceHierarchy.ts
  • Status: FALSE POSITIVE — CLOSED
  • Issue: Inline Jotai atom creation in a hook risks re-rendering components unnecessarily.
  • Resolution: useState(() => atom(...)) IS the correct Jotai pattern for local stable atom references. The factory function form of useState ensures the atom is created only once per component mount. No change warranted.

📦 Barrel File Audit

File Path Note Status
cinny/src/app/plugins/call/index.ts Extensive export * usage OPEN
cinny/src/app/plugins/text-area/index.ts Extensive export * usage OPEN
cinny/src/app/components/message/index.ts Extensive export * usage OPEN

🔍 Technical & Performance Refinements

Category Issue Description File Path Status
State Sync Fire-and-forget network call to set offline presence during pagehide event may not complete reliably, potentially causing UI drift in presence status. cinny/src/app/hooks/usePresenceUpdater.ts OPEN
State Sync Fire-and-forget network call setPresence().catch(...) suppresses errors, meaning the app may falsely assume presence update success. cinny/src/app/hooks/usePresenceUpdater.ts OPEN
Memory Leak Decrypted Media Memory Leak (Gallery & Lightbox) due to missing virtualization and blob revocation. cinny/src/app/features/room/MediaGallery.tsx PARTIALLY FIXED ⚠️ UNTESTED — Blob revocation was already correct; added enabled param to useDecryptedMediaUrl and useNearViewport(300px) to each GalleryTile to gate decryption until near-viewport, reducing burst on pagination. True virtualization (windowing) deferred — requires significant refactor.
Data Persistence Scheduled Messages are ephemeral (lost on refresh) due to fragile localStorage parsing. cinny/src/app/state/scheduledMessages.ts FIXED — now uses atomWithStorage + createJSONStorage (Jotai's built-in persistence with error-safe JSON parsing)
Memory Leak Potential memory leak due to uncleaned handleMouseMove listener in usePan. cinny/src/app/hooks/usePan.ts FALSE POSITIVE — usePan already uses attachedRef to track listeners and cleans them up in an unmount useEffect. No change needed.
Asset Optimization Large unoptimized media asset (213KB) found in public/res. public/res/Lotus.png OPEN
Data Persistence Non-atomic localStorage updates in session management can lead to inconsistent state. cinny/src/app/state/sessions.ts OPEN
Data Persistence Lack of cross-tab synchronization for localStorage updates in session management risks race conditions. cinny/src/app/state/sessions.ts OPEN
Network Resilience uploadContent lacks retry logic, failing immediately upon network error. cinny/src/app/utils/matrix.ts OPEN
Network Resilience rateLimitedActions uses basic retry logic without exponential backoff, which may exacerbate 429 issues. cinny/src/app/utils/matrix.ts FIXED — fallback delay now uses capped exponential backoff (min(1000 * 2^retryCount, 30_000)ms) when server doesn't send Retry-After; server header still takes precedence via getRetryAfterMs().
Matrix Event Robustness useMatrixEventRenderer handles unknown events gracefully by returning null, which may hide potentially important unrendered data. cinny/src/app/hooks/useMatrixEventRenderer.ts OPEN
Data Contract MatrixError instantiation with UploadResponse might be brittle. cinny/src/app/utils/matrix.ts OPEN
Type Safety addRoomIdToMDirect uses as any cast for AccountDataEvent.Direct, bypassing type contract validation. cinny/src/app/utils/matrix.ts OPEN
Robustness rateLimitedActions relies on MatrixError.httpStatus which might not exist on all error variants. cinny/src/app/utils/matrix.ts FALSE POSITIVE — MatrixError.httpStatus is defined as readonly httpStatus?: number in matrix-js-sdk/lib/http-api/errors.d.ts. It is optional (not on all instances) but the ?. optional chain already guards against undefined. No change needed.
Type Contract Custom types in cinny/src/types/matrix mirror SDK types instead of using them, risking drift and contract mismatches. cinny/src/types/matrix/ OPEN

🏗️ Architectural & Hygiene Audit

Category Issue Description File Path Status
Hygiene No stale development notes or TypeScript strictness issues found N/A OPEN

🏗️ TDS Compliance & Styling Issues

Issue Description File Path
Hardcoded inline style cursor: 'pointer' cinny/src/app/plugins/react-custom-html-parser.tsx
Hardcoded color #00D4FF, #FFB300 VERIFIED COMPLIANT cinny/src/app/components/event-readers/EventReaders.tsx
Hardcoded color #EE1D52, #9146ff, #ff4500, #cb3837, #f48024 ⚠️ BRAND EXCEPTION cinny/src/app/components/url-preview/UrlPreviewCard.tsx + UrlPreview.css.tsx — official third-party brand colors in SVG logos and site badge backgrounds; cannot convert to CSS variables without inventing new tokens (violates TDS rule 3)
Massive number of hardcoded backgroundColor values ⚠️ PATTERN CONTENT EXCEPTION cinny/src/app/features/lotus/chatBackground.ts — each background's base color is aesthetic content that defines the pattern identity; converting requires inventing 40+ CSS variables (violates TDS rule 3) or using CSS4 relative-color-syntax in inline styles (insufficient browser support); these are visual content, not UI chrome
Hardcoded colors #00FF88, #FF6B00 VERIFIED COMPLIANT cinny/src/app/features/call/CallControls.tsx
Hardcoded fallback hexes in toast colors FIXED cinny/src/app/features/toast/LotusToastContainer.tsx

🌐 Localization, Accessibility & Performance

Category Issue Description File Path Status
Localization Hardcoded UI string: "Chat Room" src/app/components/create-room/CreateRoomTypeSelector.tsx OPEN
Localization Hardcoded UI string: "Messages, photos, and videos." src/app/components/create-room/CreateRoomTypeSelector.tsx OPEN
Localization Hardcoded UI string: "Voice Room" src/app/components/create-room/CreateRoomTypeSelector.tsx OPEN
Localization Hardcoded UI string: "Live audio and video conversations." src/app/components/create-room/CreateRoomTypeSelector.tsx OPEN
Localization Hardcoded UI string: "Download" src/app/components/image-viewer/ImageViewer.tsx OPEN
Localization Hardcoded UI string: "Open Location" src/app/components/message/MsgTypeRenderers.tsx OPEN
Localization Hardcoded UI string: "Thread" src/app/components/message/Reply.tsx OPEN
Localization Hardcoded UI string: "View" src/app/components/message/content/ImageContent.tsx OPEN
Localization Hardcoded UI string: "Spoiler" src/app/components/message/content/ImageContent.tsx OPEN
Localization Hardcoded UI string: "Retry" src/app/components/message/content/ImageContent.tsx OPEN
Localization Hardcoded UI string: "Close" src/app/components/DeviceVerification.tsx OPEN
Localization Hardcoded UI string: "Accept" src/app/components/DeviceVerification.tsx OPEN
Localization Hardcoded UI string: "They Match" src/app/components/DeviceVerification.tsx OPEN
Localization Hardcoded UI string: "Okay" src/app/components/DeviceVerification.tsx OPEN
Localization Hardcoded UI string: "Join Server" src/app/components/url-preview/UrlPreviewCard.tsx OPEN
Localization Hardcoded UI string: "Invite" src/app/components/invite-user-prompt/InviteUserPrompt.tsx OPEN
Localization Hardcoded UI string: "Files" src/app/components/upload-board/UploadBoard.tsx OPEN
Localization Hardcoded UI string: "Send" src/app/components/upload-board/UploadBoard.tsx OPEN
Localization Hardcoded UI string: "Upload Failed" src/app/components/upload-board/UploadBoard.tsx OPEN
Localization Hardcoded UI string: "Password" src/app/components/uia-stages/PasswordStage.tsx OPEN
Bundle Size Large unoptimized media asset (213KB) public/res/Lotus.png OPEN
Matrix Logic Inefficient repeated mx.getRoom() calls in component render loops src/app/features/lobby/Lobby.tsx OPEN
Matrix Logic Inefficient repeated mx.getRoom() calls in component render loops src/app/components/emoji-board/EmojiBoard.tsx OPEN
Performance Numerous event handlers (e.g., handleUserClick, handleReplyClick) lack useCallback, leading to unnecessary re-renders of message components. cinny/src/app/features/room/RoomTimeline.tsx OPEN
Performance The submit function and file handling callbacks (e.g., handleSendUpload) are re-created on every render, causing re-renders of the editor and toolbar components. cinny/src/app/features/room/RoomInput.tsx OPEN
Accessibility button for edit history lacks aria-label cinny/src/app/components/message/content/FallbackContent.tsx FIXED ⚠️ UNTESTED — added aria-label="View edit history"
Accessibility button for reaction lacks aria-label cinny/src/app/components/message/Reaction.tsx FIXED ⚠️ UNTESTEDReaction component now computes aria-label="{shortcode} reaction, N people" internally using getShortcodeFor; custom (mxc://) emoji falls back to "custom emoji reaction".
Accessibility button for ThreadIndicator lacks aria-label cinny/src/app/components/message/Reply.tsx FIXED ⚠️ UNTESTED — added aria-label="View thread"
Accessibility button for ReplyLayout lacks aria-label cinny/src/app/components/message/Reply.tsx FIXED ⚠️ UNTESTED — added aria-label="Jump to original message"

🔧 Infrastructure, DevEx & Type Safety

Category Issue Description File Path Status
Dependencies lodash pinned to non-existent version 4.18.1 cinny/package.json OPEN
Dependencies Various pinned versions of @atlaskit, matrix-js-sdk cinny/package.json OPEN
Dependencies matrix-js-sdk pinned to Release Candidate (41.6.0-rc.0) cinny/package.json OPEN
Dependencies Unstable/experimental versions for build tools (vite 8.0.14, typescript 6.0.3, eslint 9.39.4) cinny/package.json OPEN
CI/CD package-manager-cache set to false cinny/.github/workflows/build-pull-request.yml OPEN
CI/CD Inefficient sequential execution in deployment cinny/.github/workflows/prod-deploy.yml OPEN
CI/CD Aggressive 1-minute timeout for Netlify deploy cinny/.github/workflows/prod-deploy.yml OPEN
DevEx Stale upstream bug tracker link/donations/CLA cinny/CONTRIBUTING.md OPEN
DevEx Alignment issue between README and CONTRIBUTING cinny/README.md OPEN
Testing No evident automated testing configuration/files cinny/src/ OPEN
Type Safety Extensive use of as any type assertions cinny/src/ OPEN
Security Hardcoded public CDN URL; consider moving to environment variable /root/code/cinny/scripts/syncDecorations.mjs OPEN
Architecture Modifying node_modules directly is brittle; use patch-package instead /root/code/cinny/scripts/patch-folds.mjs OPEN
Robustness Missing security headers (HSTS, CSP, etc.) and inefficient asset serving using rewrites instead of try_files /root/code/cinny/contrib/nginx/cinny.domain.tld.conf OPEN
Robustness Incomplete documentation/placeholder path in Caddyfile /root/code/cinny/contrib/caddy/caddyfile OPEN
Matrix SDK Inefficient listener management (setMaxListeners: 150) and incomplete SDK state transition handling. src/client/initMatrix.ts OPEN
PWA Robustness Service worker lacks caching strategy for application assets, resulting in no offline capability. cinny/src/sw.ts OPEN
PWA Integrity manifest: false in vite.config.js might prevent correct PWA installation if not handled externally. cinny/vite.config.js OPEN
PII Leakage Potential PII exposure via console.error (parameter e likely contains event data). cinny/src/app/plugins/call/CallEmbed.ts OPEN
PII Leakage Potential PII exposure via console.warn (parameter imgError/videoError/thumbError object). cinny/src/app/features/room/msgContent.ts OPEN
PII Leakage Potential PII exposure via console.error (parameter e likely contains event data). cinny/src/app/features/room/RoomInput.tsx OPEN

🏗️ Architectural & Resilience Audit

Category Issue Description File Path Status
Element Call Integration Lacks robust iframe failure monitoring beyond initial 'preparing' event; can result in a permanently hung 'Loading...' state with no user-visible error or recovery path. src/app/plugins/call/CallEmbed.ts OPEN
Component Resilience RoomTimeline has no ErrorBoundary wrapper — a single malformed event crashing the renderer takes down the entire timeline with no fallback UI. src/app/features/room/RoomTimeline.tsx OPEN
Component Resilience RoomInput has no ErrorBoundary wrapper — a crash in the composer leaves users unable to send messages. src/app/features/room/RoomInput.tsx OPEN
Fallback Logic No explicit empty/error fallback for Matrix SDK data calls in RoomTimeline; relies purely on SDK internal error propagation, meaning silent failures show a blank timeline. src/app/features/room/RoomTimeline.tsx OPEN
Dependency Potential for complex dependency chains due to deep nesting in src/app/features/ and src/app/hooks/. src/app/ OPEN
Hydration/Race Condition The SyncState listener registered by useSyncState may miss the initial 'PREPARED' event if the client initializes synchronously from IndexedDB before the effect runs, leading to an infinite loading state. cinny/src/app/pages/client/ClientRoot.tsx OPEN
Structure High number of small, highly coupled utility hooks (src/app/hooks/) may obscure dependency graphs. src/app/hooks/ OPEN
Dead Code Potential for unused CSS modules or UI components in src/app/features/. src/app/ OPEN
Security Sensitive session data (access tokens, device ID) stored in localStorage is vulnerable to XSS. src/app/state/sessions.ts OPEN
Privacy Sensitive user status messages and expiry timestamps are persisted in localStorage. src/app/features/settings/account/Profile.tsx OPEN
Privacy Unsent composer drafts stored in localStorage without encryption could leak info on shared devices. src/app/features/room/RoomInput.tsx OPEN
Persistence Scheduled messages relying on fragile localStorage parsing are prone to data loss on session expiry or error. src/app/state/scheduledMessages.ts OPEN
Bundle Bloat Inefficient lodash import; risks including entire library instead of necessary utilities. cinny/package.json OPEN
Bundle Bloat Large matrix-js-sdk (RC version) dependency; high potential for tree-shaking overhead. cinny/package.json OPEN
Build-Time Overhead lotusDenoise plugin performs heavy, sequential fs operations during closeBundle, significantly slowing build times. cinny/vite.config.js OPEN
Build-Time Overhead Complex manual viteStaticCopy configuration requiring multiple renames and path manipulations; risks redundant processing. cinny/vite.config.js OPEN
Architectural Debt Redundant style variant logic in SpacingVariant could be simplified. cinny/src/app/components/message/layout/layout.css.ts OPEN
Overhead Analysis Potential CSS bloat from DropTarget composition across multiple recipes (SidebarItem, SidebarFolder). cinny/src/app/components/sidebar/Sidebar.css.ts OPEN

🏗️ Git Workflow & History Audit

Category Issue Description File Path Status
Workflow Monolithic "Fix all bugs" commits (e.g., 10f6544e, aa48c9ef) make git bisect difficult. Git History OPEN
Workflow Inconsistent commit message prefixes (e.g., fix, feat, docs, assets). Git History OPEN
Workflow Use of fix or feat for large-scale changes affecting multiple disparate systems (e.g., 938ead79). Git History OPEN