Skip to content

fix(settings): unify settings navigation + enforce panel UI contract - #3599

Merged
senamakel merged 8 commits into
tinyhumansai:mainfrom
graycyrus:fix/settings-ui-overhaul
Jun 11, 2026
Merged

senamakel merged 8 commits into
tinyhumansai:mainfrom
graycyrus:fix/settings-ui-overhaul

Conversation

@graycyrus

@graycyrus graycyrus commented Jun 11, 2026 •

Copy link
Copy Markdown
Contributor

Summary

  • Single source of truth for settings routes: new settingsRouteRegistry.ts that SettingsHome, the section pages, DeveloperOptionsPanel, and the settings search all derive from — replacing 4 independent menu definitions that had drifted apart.
  • Routes & breadcrumbs now correct: exact-match route resolution replaces the fragile includes()-chain; breadcrumbs are canonical (one home per panel). Added the missing composio route, removed the dead messaging route.
  • De-duplicated: Developer Options is now debug-only — 20 user-facing settings that were duplicated between section pages and Developer Options collapse back to a single home; persona's 3× duplication removed.
  • Discoverability: the 5 previously-orphaned section pages (Features, AI, Agents, Composio, Crypto) are now reachable from the Settings home screen, so click-paths match URLs.
  • Consistent look & feel: brought 21 panels onto the z-10 relative settings UI contract; gave Intelligence and Webhooks proper SettingsHeader shells instead of bare full-page layouts crammed in the settings card.

Problem

Settings had drifted into an inconsistent mess: the UI differed panel-to-panel, route URLs and breadcrumbs didn't match the flow users actually clicked through, the same option appeared in multiple places, and several section pages weren't reachable from the home screen at all. Navigation was defined in 4 disconnected places (SettingsHome, section-page arrays in Settings.tsx, DeveloperOptionsPanel, and the search registry), each repeating route strings/titles/icons — the root cause of every symptom.

Solution

  • Introduce a declarative registry as the canonical settings map; every navigation surface reads from it, so an entry lives in exactly one place with one canonical breadcrumb trail.
  • Rewrite useSettingsNavigation route resolution to exact-match (no substring collisions) and derive breadcrumbs from each entry's section.
  • Reclassify Developer Options to genuine diagnostics only; move user-facing settings back to their section homes.
  • Surface the orphaned section pages on SettingsHome.
  • Normalize the 21 non-conforming panels to the documented panel contract; wrap the two full-page surfaces (Intelligence, Webhooks) with the standard header shell.
  • Add focused unit coverage for the registry helpers and navigation/breadcrumb logic.

No new i18n keys (all reuse existing keys; parity check passes). No new external network deps.

Submission Checklist

  • Tests added or updated (happy path + at least one failure / edge case) — added settingsRouteRegistry.test.ts (20 tests incl. unknown-id/route edge cases) and useSettingsNavigation.coverage.test.tsx (26 tests incl. removed-route and no-collision cases); updated the 5 specs that asserted the old structure.
  • Diff coverage ≥ 80% — new registry + navigation logic covered by the added unit tests.
  • Coverage matrix updated — N/A: navigation/UI consistency refactor, no new feature rows.
  • All affected feature IDs from the matrix are listed under ## Related — N/A: no matrix rows affected.
  • No new external network dependencies introduced.
  • Manual smoke checklist updated if this touches release-cut surfaces — N/A: no release-cut surface behaviour change.
  • Linked issue closed via Closes #NNN — N/A: no tracking issue.

Impact

Related

  • Closes:
  • Follow-up PR(s)/TODOs: AIPanel.tsx (3.6k lines) decomposition deferred to a focused follow-up.

AI Authored PR Metadata (required for Codex/Linear PRs)

Linear Issue

  • Key: N/A
  • URL: N/A

Commit & Branch

  • Branch: fix/settings-ui-overhaul
  • Commit SHA: dde4935f8f795126571ef38cb65925199de01299

Validation Run

  • pnpm --filter openhuman-app format:check (prettier clean on changed files)
  • pnpm typecheck (tsc --noEmit: 0 errors)
  • Focused tests: pnpm debug unit src/components/settings src/pages → 1159 passed / 1 skipped
  • Rust fmt/check (if changed): N/A — no Rust changed
  • Tauri fmt/check (if changed): N/A — no Tauri changed

Validation Blocked

  • command: N/A
  • error: N/A
  • impact: N/A

Behavior Changes

  • Intended behavior change: settings navigation structure, breadcrumbs, and panel layouts normalized; Developer Options reduced to diagnostics.
  • User-visible effect: consistent settings UI, correct breadcrumbs/URLs, no duplicated options, all sections reachable from the home screen.

Parity Contract

  • Legacy behavior preserved: all routes still resolve (deep-link-only routes retained + commented); panel behaviour unchanged, only chrome/placement normalized.
  • Guard/fallback/dispatch parity checks: exact-match route resolution covered by tests incl. no-substring-collision case.

Duplicate / Superseded PR Handling

Summary by CodeRabbit

  • New Features

    • Centralized settings registry, merged home card, and new hubs surfaced for AI, Agents, Features/Integrations, and Crypto; registry-driven routing yields improved, consistent breadcrumbs.
  • Bug Fixes

    • Removed duplicate/misplaced menu entries and fixed route-resolution and breadcrumb edge cases for clearer navigation.
  • Style

    • Major UI unification: shared settings controls, neutral theme, accessible switches/badges/status lines, and more consistent layouts.
  • Tests

    • Expanded coverage for routing, navigation/breadcrumbs, settings search, and new shared UI controls.

Settings had drifted: routes/breadcrumbs defined in 4 places, 20 options
duplicated between section pages and Developer Options, 21 panels off the
UI contract, and 5 section pages unreachable from the home screen.

- Add settingsRouteRegistry.ts as the single source of truth; SettingsHome,
  section pages, Developer Options, and search all derive from it.
- Replace the fragile includes()-chain route resolution with exact-match
  lookup; breadcrumbs are now canonical (one home per panel). Add the missing
  'composio' route, remove the dead 'messaging' route.
- Developer Options is now debug-only: 20 user-facing settings de-duplicated
  back to their section pages; persona's 3x duplication collapsed.
- Surface the 5 orphaned section pages (Features, AI, Agents, Composio, Crypto)
  on the Settings home screen so click-paths match URLs.
- Bring 21 panels onto the 'z-10 relative' panel contract; give Intelligence
  and Webhooks proper SettingsHeader shells.
- Add registry + navigation unit coverage.
@graycyrus
graycyrus requested a review from a team June 11, 2026 12:57
@coderabbitai

coderabbitai Bot commented Jun 11, 2026 •

Copy link
Copy Markdown
Contributor

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Adds a declarative SETTINGS_ROUTE_REGISTRY and registry-driven navigation/breadcrumbs, derives settings search entries from the registry, flattens SettingsHome into a merged hub list, introduces shared Settings* UI primitives and tests, and migrates many settings panels/pages into the settings shell with standardized controls and neutralized styling.

Changes

Settings Navigation Registry and Hook Refactor

Layer / File(s) Summary
Settings route registry and helpers
app/src/components/settings/settingsRouteRegistry.ts
Adds SettingsSection/SettingsRegistryEntry, SETTINGS_ROUTE_REGISTRY, and helpers: entryRoute, entriesForSection, findEntryById, findEntryByRoute.
useSettingsNavigation hook
app/src/components/settings/hooks/useSettingsNavigation.ts
Resolves current route and breadcrumbs from the registry with exact slug extraction, special-case subroute mapping, and adds sectionRouteForSection. Updates SettingsRoute union.
Registry tests
app/src/components/settings/__tests__/settingsRouteRegistry.test.ts
Unit tests for entryRoute, findEntryById/findEntryByRoute, entriesForSection, and registry integrity checks.

Settings Home and Pages Integration

Layer / File(s) Summary
SettingsHome menu refactor
app/src/components/settings/SettingsHome.tsx
Adds inline SVG hub icons and replaces grouped SettingsGroup construction with separate SettingsItem[] arrays merged into a flat laymanItems for the main home card; trailing Developer & About groups remain.
SettingsHome tests updated
app/src/components/settings/__tests__/SettingsHome.test.tsx
Updates expectations for surfaced hubs (AI, Agents settings, Features, Integrations/composio, Crypto) and navigation clicks.
Pages wrapped in settings shell
app/src/pages/Intelligence.tsx, app/src/pages/Webhooks.tsx
Pages now render inside SettingsHeader and use useSettingsNavigation for breadcrumbs and back navigation; minor header semantics adjustments.
Settings menu cleanup
app/src/pages/Settings.tsx
Removes duplicated/moved menu entries (notifications duplicate, some debug items, persona) and deletes a local PersonaIcon constant.

Search & Controls Library

Layer / File(s) Summary
Search registry derivation
app/src/components/settings/search/settingsSearchRegistry.ts
Replaces static search manifest with a derived SETTINGS_SEARCH_ENTRIES computed from SETTINGS_ROUTE_REGISTRY, filtering hiddenDeepLink entries and projecting route/section/keywords/devOnly and badge i18n overrides.
Shared Settings controls
app/src/components/settings/controls/*, app/src/components/settings/controls/__tests__/*
Adds SettingsBadge, SettingsCheckbox, SettingsEmptyState, SettingsListItem, SettingsNumberField, SettingsRow, SettingsSection, SettingsSelect, SettingsStatusLine, SettingsSwitch, SettingsTextArea, SettingsTextField, index barrel, and unit tests covering interactions and accessibility.

Panel Migrations and Theming

Layer / File(s) Summary
DeveloperOptionsPanel re-scope
app/src/components/settings/panels/DeveloperOptionsPanel.tsx, test updates
Re-scopes panel to debug-only groups, removes user-facing routes moved to canonical pages, reorganizes DEV_GROUPS, and updates localization/test expectations.
Panel UI migration & theming
app/src/components/settings/panels/*.tsx
Applies className="z-10 relative" to many panel roots, standardizes neutral palette classes (stone → neutral), migrates raw HTML controls to shared Settings* components, and consolidates status/saved/error UI into SettingsStatusLine. Multiple panels and tests were updated accordingly.
  • Estimated code review effort: 🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

Suggested reviewers

  • senamakel
  • sanil-23

"I’m a rabbit in the codewood glade,
I stitched the routes where breadcrumbs braid,
Badges and switches, headers bright,
Panels hop into neutral light,
Hop through hubs — the settings parade!"

@coderabbitai coderabbitai Bot added feature Net-new user-facing capability or product behavior. working A PR that is being worked on by the team. labels Jun 11, 2026

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
app/src/components/settings/panels/ComposioPanel.tsx (1)

205-223: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Apply the same wrapper contract in the loading branch.

Line [207] returns a bare root <div> while the normal render path uses className="z-10 relative" (Line [226]). This creates inconsistent panel stacking during initial load.

Suggested patch
   if (loading) {
     return (
-      <div>
+      <div className="z-10 relative">
         {!embedded && (
           <SettingsHeader
             title={t('settings.composio.title')}
             showBackButton
             onBack={navigateBack}
             breadcrumbs={breadcrumbs}
           />
         )}
         <div className={embedded ? '' : 'p-4'}>
           <p className="text-sm text-stone-500 dark:text-neutral-400">
             {t('settings.composio.loading')}
           </p>
         </div>
       </div>
     );
   }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@app/src/components/settings/panels/ComposioPanel.tsx` around lines 205 - 223,
The loading branch in the ComposioPanel component returns a bare root <div>,
causing inconsistent stacking compared to the normal render which uses
className="z-10 relative"; update the loading return to use the same wrapper
contract (apply className="z-10 relative" to the outer container when not
embedded, preserving the embedded conditional and existing children like
SettingsHeader, navigateBack, breadcrumbs) so the panel stacking is consistent
during initial load.
🧹 Nitpick comments (1)
app/src/components/settings/hooks/useSettingsNavigation.ts (1)

19-85: ⚖️ Poor tradeoff

Consider programmatically deriving SettingsRoute from the registry.

The SettingsRoute union is manually maintained and could drift from SETTINGS_ROUTE_REGISTRY. While TypeScript will catch most call-site mismatches, a future refactor could extract all unique id values from the registry to generate this type programmatically (e.g., type SettingsRoute = typeof SETTINGS_ROUTE_REGISTRY[number]['id']), eliminating the maintenance surface.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@app/src/components/settings/hooks/useSettingsNavigation.ts` around lines 19 -
85, Replace the manually maintained SettingsRoute union with a type derived from
the settings registry: remove the hard-coded union and define SettingsRoute in
terms of SETTINGS_ROUTE_REGISTRY so the union automatically reflects each
registry entry's id (reference SETTINGS_ROUTE_REGISTRY and the SettingsRoute
type name to locate where to change). Ensure the derived type uses the array
element id (e.g., typeof SETTINGS_ROUTE_REGISTRY[number]['id']) so future
registry updates do not require manual edits to SettingsRoute.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@app/src/components/settings/search/settingsSearchRegistry.ts`:
- Around line 94-96: Replace the direct console.debug call with the repository’s
namespaced debug logger: inside the existing browser guard (if (typeof window
!== 'undefined')), call the module-level debug function with a descriptive
namespace (e.g. debug('settings:search-registry') or the project’s standard
namespace) and log the SETTINGS_SEARCH_ENTRIES.length there; update the
import/initializer to use the existing frontend debug helper if not already
present and ensure no PII is logged.

In `@app/src/pages/Webhooks.tsx`:
- Around line 10-13: Replace the direct console.debug call in Webhooks.tsx with
the project's namespaced debug logger: remove console.debug('[settings]
Webhooks: rendering with settings shell') and call the imported/debug instance
instead (e.g., debug('settings:webhooks', '[settings] Webhooks: rendering with
settings shell')). Ensure you add or reuse the debug import/initializer at the
top of the file (or module-level) so Webhooks.tsx uses the project's debug
function; keep useSettingsNavigation(), navigateBack and breadcrumbs unchanged.

---

Outside diff comments:
In `@app/src/components/settings/panels/ComposioPanel.tsx`:
- Around line 205-223: The loading branch in the ComposioPanel component returns
a bare root <div>, causing inconsistent stacking compared to the normal render
which uses className="z-10 relative"; update the loading return to use the same
wrapper contract (apply className="z-10 relative" to the outer container when
not embedded, preserving the embedded conditional and existing children like
SettingsHeader, navigateBack, breadcrumbs) so the panel stacking is consistent
during initial load.

---

Nitpick comments:
In `@app/src/components/settings/hooks/useSettingsNavigation.ts`:
- Around line 19-85: Replace the manually maintained SettingsRoute union with a
type derived from the settings registry: remove the hard-coded union and define
SettingsRoute in terms of SETTINGS_ROUTE_REGISTRY so the union automatically
reflects each registry entry's id (reference SETTINGS_ROUTE_REGISTRY and the
SettingsRoute type name to locate where to change). Ensure the derived type uses
the array element id (e.g., typeof SETTINGS_ROUTE_REGISTRY[number]['id']) so
future registry updates do not require manual edits to SettingsRoute.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 391ba065-c2ff-43b8-8652-4e67cb9f0f31

📥 Commits

Reviewing files that changed from the base of the PR and between 70210a2 and dde4935.

📒 Files selected for processing (32)
  • app/src/components/settings/SettingsHome.tsx
  • app/src/components/settings/__tests__/SettingsHome.test.tsx
  • app/src/components/settings/__tests__/settingsRouteRegistry.test.ts
  • app/src/components/settings/hooks/__tests__/useSettingsNavigation.coverage.test.tsx
  • app/src/components/settings/hooks/__tests__/useSettingsNavigation.test.tsx
  • app/src/components/settings/hooks/useSettingsNavigation.ts
  • app/src/components/settings/panels/AIPanel.tsx
  • app/src/components/settings/panels/AgentChatPanel.tsx
  • app/src/components/settings/panels/AppearancePanel.tsx
  • app/src/components/settings/panels/CompanionPanel.tsx
  • app/src/components/settings/panels/ComposioPanel.tsx
  • app/src/components/settings/panels/CronJobsPanel.tsx
  • app/src/components/settings/panels/DeveloperOptionsPanel.tsx
  • app/src/components/settings/panels/EventLogPanel.tsx
  • app/src/components/settings/panels/LocalModelDebugPanel.tsx
  • app/src/components/settings/panels/MascotPanel.tsx
  • app/src/components/settings/panels/MemoryDebugPanel.tsx
  • app/src/components/settings/panels/ModelHealthPanel.tsx
  • app/src/components/settings/panels/NotificationsTabbedPanel.tsx
  • app/src/components/settings/panels/PersonaPanel.tsx
  • app/src/components/settings/panels/TaskSourcesPanel.tsx
  • app/src/components/settings/panels/TasksPanel.tsx
  • app/src/components/settings/panels/ToolsPanel.tsx
  • app/src/components/settings/panels/VoicePanel.tsx
  • app/src/components/settings/panels/WebhooksDebugPanel.tsx
  • app/src/components/settings/panels/WorkflowRunnerPanel.tsx
  • app/src/components/settings/panels/__tests__/DeveloperOptionsPanel.test.tsx
  • app/src/components/settings/search/settingsSearchRegistry.ts
  • app/src/components/settings/settingsRouteRegistry.ts
  • app/src/pages/Intelligence.tsx
  • app/src/pages/Settings.tsx
  • app/src/pages/Webhooks.tsx

Comment thread app/src/pages/Webhooks.tsx Resolved
Settings panels were visually inconsistent — bare native checkboxes, ad-hoc
inputs/selects/buttons, irregular section spacing, undefined legacy tokens.
This introduces a reusable settings form-language and applies it to every panel.

- New primitives in app/src/components/settings/controls/: SettingsSection,
  SettingsRow, SettingsSwitch, SettingsCheckbox, SettingsTextField/TextArea,
  SettingsNumberField, SettingsSelect, SettingsBadge, SettingsListItem,
  SettingsEmptyState, SettingsStatusLine — built on ui/{Button,Input,Card},
  light+dark first-class, a11y (role=switch, focus rings, motion-reduce).
- Migrated ~50 panels to the primitives: booleans → switches, lists → list
  items + badges + empty states, numbers → unit/range field, all buttons →
  ui/Button variants. Bespoke product UI (provider cards, theme picker, mascot,
  billing/marketing cards, data tables/charts, log streams) intentionally kept.
- AgentAccessPanel is the canonical reference (the screenshot pain point).
- Resolved undefined legacy tokens (text-ink/border-line/stone-*) → neutral-*.
- No new i18n keys (parity preserved). Primitives carry data-testids through.
- Updated unit tests for role changes; added primitive coverage.
- Fixed 4 Playwright settings specs that asserted the pre-refactor menu layout
  (dev-options is debug-only; notifications moved to its hub; AI breadcrumb
  label is 'AI & Models').

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🧹 Nitpick comments (12)
app/src/components/settings/panels/TaskSourcesPanel.tsx (1)

1-597: ⚡ Quick win

File exceeds the 500-line guideline.

At 597 lines, this file is slightly above the recommended ≤ 500 line limit. Consider extracting the "Add a source" form (lines 356-488) or the source list rendering (lines 514-577) into separate child components to improve maintainability.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@app/src/components/settings/panels/TaskSourcesPanel.tsx` around lines 1 -
597, The file is too large; extract parts of TaskSourcesPanel into child
components to stay under 500 lines: create a TaskSourceForm component (move the
"Add a source" JSX and its local form state and handlers: provider, name,
primary, labels, assignedToMe, databases, buildFilter, addSource, previewFilter,
browseDatabases, primaryLabel) and a TaskSourceList component (move the
configured sources list JSX and handlers: sources rendering, toggleSource,
fetchNow, removeSource, syncAll, load, formatSyncNotice), then import and use
these new components inside TaskSourcesPanel passing required props (e.g., t,
busyKey, setBusyKey, loading, sources, setSources, status, setStatus,
notice/setNotice, error/setError, load) so existing logic and state updates
remain intact while reducing TaskSourcesPanel size.

Source: Coding guidelines

app/src/components/settings/panels/ScreenIntelligencePanel.tsx (1)

143-195: 💤 Low value

Consider using SettingsCheckbox for consistency.

The "Enabled" toggle (Lines 143-152) and "Screen monitoring" toggle (Lines 181-195) still use raw <input type="checkbox"> elements. Since this PR introduces SettingsCheckbox as a shared primitive, these could be migrated for consistency with the rest of the settings UI.

♻️ Optional refactor for consistency
+import { SettingsCheckbox, SettingsRow, SettingsSection, SettingsSelect, SettingsStatusLine } from '../controls';

         {/* Enabled toggle */}
-        <label className="flex items-center justify-between px-4 py-3">
-          <span className="text-sm text-neutral-700 dark:text-neutral-200">
-            {t('common.enabled')}
-          </span>
-          <input
-            type="checkbox"
-            checked={enabled}
-            onChange={event => setEnabled(event.target.checked)}
-          />
-        </label>
+        <SettingsRow
+          htmlFor="checkbox-enabled"
+          label={t('common.enabled')}
+          control={
+            <SettingsCheckbox
+              id="checkbox-enabled"
+              checked={enabled}
+              onCheckedChange={setEnabled}
+            />
+          }
+        />

         {/* Screen monitoring toggle */}
-        <label className="flex items-center justify-between px-4 py-3">
-          <span className="text-sm text-neutral-700 dark:text-neutral-200">
-            {t('settings.screenAwareness.screenMonitoring')}
-          </span>
-          <input
-            type="checkbox"
-            checked={screenMonitoring}
-            onChange={event =>
-              setFeatureOverrides(current => ({
-                ...current,
-                screen_monitoring: event.target.checked,
-              }))
-            }
-          />
-        </label>
+        <SettingsRow
+          htmlFor="checkbox-screen-monitoring"
+          label={t('settings.screenAwareness.screenMonitoring')}
+          control={
+            <SettingsCheckbox
+              id="checkbox-screen-monitoring"
+              checked={screenMonitoring}
+              onCheckedChange={checked =>
+                setFeatureOverrides(current => ({
+                  ...current,
+                  screen_monitoring: checked,
+                }))
+              }
+            />
+          }
+        />
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@app/src/components/settings/panels/ScreenIntelligencePanel.tsx` around lines
143 - 195, The two raw checkbox inputs in ScreenIntelligencePanel should be
replaced with the shared SettingsCheckbox component for UI consistency: swap the
input used for the "Enabled" toggle (where checked={enabled} and onChange calls
setEnabled) and the "Screen monitoring" toggle (where onChange updates
setFeatureOverrides.screen_monitoring) to use SettingsCheckbox, wiring its
checked/value and onChange props to the same state handlers (setEnabled and the
setFeatureOverrides updater) and preserving the existing labels and layout;
reference the SettingsCheckbox component and the ScreenIntelligencePanel
handlers setEnabled and setFeatureOverrides when making the change.
app/src/components/settings/panels/AutocompleteDebugPanel.tsx (1)

1-779: ⚖️ Poor tradeoff

Consider breaking this debug panel into smaller modules.

At 780 lines, this file significantly exceeds the ~500 line guideline. The file has clear section boundaries (Runtime, Test, Live Logs, Advanced settings, Personalization History) that could be extracted into separate components. While the current structure is well-organized and functional, extracting these sections would improve maintainability.

Given this is a debug panel (not production-critical) and is already clearly structured, this refactor can be deferred.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@app/src/components/settings/panels/AutocompleteDebugPanel.tsx` around lines 1
- 779, The file AutocompleteDebugPanel.tsx is too large and should be split into
smaller components; extract the major sections (Runtime, Test, Live Logs,
Advanced settings, Personalization History) into separate components (e.g.,
RuntimeSection, TestSection, LiveLogsSection, AdvancedSettingsSection,
PersonalizationHistorySection) and update AutocompleteDebugPanel to compose
them. Move or expose the related state and handlers (status, isLoading,
isSaving, error, message, logs, historyEntries, focusDebug, debounceMs,
maxChars, overlayTtlMs, styleInstructions, styleExamplesText and helper
functions appendLogs, appendUiLog, trackStatusChanges, load, loadHistory,
refreshStatus, start, stop, testCurrent, acceptSuggestion, debugFocus,
saveAdvancedConfig, clearHistory, clearLogs, waitForAcceptedHistoryEntry) by
either hoisting state into AutocompleteDebugPanel and passing props/callbacks
into the new components or by moving cohesive state+handlers into the new
component modules. Keep shared utilities like parseAutocompleteConfig and
DEFAULT_CONFIG in the original file or a shared utils module, and ensure imports
still use SettingsHeader and SettingsSection where needed. Ensure each new
component receives the minimal props required (e.g., RuntimeSection needs
status, isLoading, refreshStatus, start, stop; TestSection needs
contextOverride, setContextOverride, testCurrent, acceptSuggestion, debugFocus,
focusDebug; LiveLogsSection needs logs, clearLogs; AdvancedSettingsSection needs
debounceMs, setDebounceMs, maxChars, setMaxChars, overlayTtlMs, setOverlayTtlMs,
styleInstructions, setStyleInstructions, styleExamplesText,
setStyleExamplesText, saveAdvancedConfig, isSaving;
PersonalizationHistorySection needs historyEntries, isHistoryLoading,
isClearingHistory, clearHistory) and export them for reuse.

Source: Coding guidelines

app/src/components/settings/controls/SettingsListItem.tsx (1)

8-9: ⚡ Quick win

Consider making removeLabel optional to match onRemove.

The onRemove callback is optional, but removeLabel is required. Since the remove button is only rendered when onRemove is provided (line 35), callers who don't supply onRemove must still pass a removeLabel that will never be used. This creates an awkward API contract.

♻️ Suggested type adjustment
 export interface SettingsListItemProps {
   label: string;
   badge?: ReactNode;
   onRemove?: () => void;
-  removeLabel: string;
+  removeLabel?: string;
   mono?: boolean;
   'data-testid'?: string;
 }

Then add a runtime guard or require both together:

// Option A: Runtime guard
{onRemove && removeLabel && (
  <Button ... aria-label={removeLabel}>{removeLabel}</Button>
)}

// Option B: Make both required together (stricter but clearer)
type SettingsListItemProps = 
  | { label: string; badge?: ReactNode; mono?: boolean; 'data-testid'?: string; onRemove?: never; removeLabel?: never }
  | { label: string; badge?: ReactNode; mono?: boolean; 'data-testid'?: string; onRemove: () => void; removeLabel: string };
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@app/src/components/settings/controls/SettingsListItem.tsx` around lines 8 -
9, The props API currently requires removeLabel while onRemove is optional,
forcing callers to pass an unused label; update SettingsListItemProps to make
removeLabel optional or make the two props required together and add a runtime
guard before rendering the remove Button: either change the type so
removeLabel?: string and in SettingsListItem render the Button only when
onRemove && removeLabel, or implement a discriminated union for
SettingsListItemProps such that one variant requires both onRemove and
removeLabel and the other forbids both; ensure the JSX around the Button (the
element that uses aria-label={removeLabel}) checks both values before rendering.
app/src/components/settings/panels/MascotPanel.tsx (1)

1-738: 🏗️ Heavy lift

File exceeds the 500-line guideline (738 lines).

This file is 48% larger than the recommended 500-line limit. While the color picker (lines 322-425), voice picker (lines 427-577), and character picker (lines 579-731) sections are marked as "intentional bespoke UI," they could be extracted into focused sub-components to improve testability and maintainability.

💡 Suggested refactor approach

Consider extracting:

  1. MascotColorPicker.tsx (lines 322-425)
  2. MascotVoicePicker.tsx (lines 427-577)
  3. MascotCharacterPicker.tsx (lines 579-731)

Each would receive the necessary state/callbacks as props, keeping MascotPanel as a coordinator under 300 lines.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@app/src/components/settings/panels/MascotPanel.tsx` around lines 1 - 738,
File is too large; extract three focused subcomponents to reduce MascotPanel
size: create MascotColorPicker, MascotVoicePicker, and MascotCharacterPicker.
MascotColorPicker should own the swatch grid UI and custom color controls and
accept props: available (filtered COLOR_OPTIONS), activeColor, customPrimary,
customSecondary, handleSelect, dispatch handlers
setCustomPrimaryColor/setCustomSecondaryColor (or callbacks), and
getMascotPalette/hexToArgbInt usage moved in or passed as needed.
MascotVoicePicker should accept voice state/handlers: voiceGender,
useLocaleDefault, visiblePresets, effectiveVoiceId, storedVoiceId, voiceDraft,
voicePasteMode, isPreviewingVoice, voicePreviewError, onGenderChange,
onLocaleDefaultToggle, onPresetChange, onSavePaste, onVoiceReset,
onVoicePreview, localeDefaultVoiceId, and
isCuratedVoicePreset/defaultVoiceIdForLocale usage moved in or passed.
MascotCharacterPicker should accept backendList, backendListError,
selectedMascotId, customMascotGifUrl, customGifDraft, customGifError,
activeDetail, detailError, handleSelectBackend, onSaveCustomGif,
onResetCustomGif, and render BackendMascot/CustomGifMascot. Keep MascotPanel as
coordinator: maintain state/logic (fetches, preview refs, dispatch calls) and
pass only the necessary props/callbacks to the new components.

Source: Coding guidelines

app/src/components/settings/controls/SettingsTextField.tsx (1)

5-7: ⚡ Quick win

API consistency: Consider adding inputSize prop to match SettingsSelect.

Multiple call sites (EventLogPanel.tsx:243, MemoryDebugPanel.tsx:218, 312, 328, 420, MigrationPanel.tsx:184, PermissionsPanel.tsx:287) pass inputSize="sm" to SettingsTextField, but this prop is not defined in the interface. SettingsSelect explicitly defines inputSize?: SettingsSelectSize, but SettingsTextField relies on passthrough to the underlying Input component.

For API consistency and self-documentation, consider explicitly defining inputSize in SettingsTextFieldProps:

+export type SettingsTextFieldSize = 'sm' | 'md';
+
 export interface SettingsTextFieldProps extends InputProps {
   mono?: boolean;
+  inputSize?: SettingsTextFieldSize;
 }

Then forward it to Input or map it to the appropriate classes.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@app/src/components/settings/controls/SettingsTextField.tsx` around lines 5 -
7, Add an explicit optional inputSize prop to SettingsTextFieldProps and pass it
through (or map it) to the underlying Input in SettingsTextField so callers can
use the same API as SettingsSelect; update the interface to include inputSize?:
SettingsSelectSize, accept it in the SettingsTextField component signature, and
forward it into the Input component props (or convert to the appropriate class
names) while leaving mono and other InputProps untouched.
app/src/components/settings/panels/AgentEditorPage.tsx (1)

1-659: ⚡ Quick win

File exceeds 500-line guideline; consider extracting ToolsPickerModal.

This file is 659 lines. As per coding guidelines, frontend files should be ≤ ~500 lines. The inline ToolsPickerModal component (lines 482–635) is a natural extraction candidate—moving it to a separate AgentEditorToolsPickerModal.tsx would bring the main file under the threshold and improve modularity.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@app/src/components/settings/panels/AgentEditorPage.tsx` around lines 1 - 659,
Extract the ToolsPickerModal (and its helper Checkbox component) out of
AgentEditorPage into a new component file to reduce AgentEditorPage size: create
a new AgentEditorToolsPickerModal.tsx exporting ToolsPickerModal and Checkbox,
move the ToolsPickerModal function (including its props type and internal
state/useEffects) and the Checkbox function there, import ToolsPickerModal into
AgentEditorPage and update any referenced symbols (ToolsPickerModal, Checkbox)
accordingly; ensure the new file imports useT, agentRegistryApi, AgentToolInfo,
Button, SettingsTextField, LuSearch, LuX and preserves prop types
(allToolsSelected, selected, onToggleAll, onToggleTool, onClose) and behavior so
existing calls from AgentEditorPage remain unchanged.

Source: Coding guidelines

app/src/components/settings/panels/EmbeddingsPanel.tsx (1)

1-722: ⚡ Quick win

File exceeds 500-line guideline; consider extracting modals.

This file is 722 lines. As per coding guidelines, frontend files should be ≤ ~500 lines. The inline setup popup (lines 500–688) and confirm dialog (lines 691–710) could be extracted into separate components (EmbeddingsSetupModal.tsx, EmbeddingsConfirmWipeModal.tsx) to improve modularity and bring the main panel under the threshold.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@app/src/components/settings/panels/EmbeddingsPanel.tsx` around lines 1 - 722,
The file is too large (722 lines); extract the inline setup popup and
confirm-wipe dialog into separate components to reduce EmbeddingsPanel size.
Create EmbeddingsSetupModal and EmbeddingsConfirmWipeModal components and move
the JSX currently rendered when setupProvider is truthy and when pendingWipe is
truthy (the entire modal blocks) into those files; expose props for the required
state and handlers (e.g., setupProvider, setupKey, setupShowKey, setupTesting,
setupTestResult, setupSaving, setupError, customEndpoint, customModel,
customDims, setSetupProvider, setSetupKey, setSetupShowKey, setCustomEndpoint,
setCustomModel, setCustomDims, setupTest, setupSave, setupSaveCustom for the
setup modal; pendingWipe, setPendingWipe, confirmWipe for the confirm modal).
Import and render <EmbeddingsSetupModal .../> and <EmbeddingsConfirmWipeModal
.../> from EmbeddingsPanel, keeping the existing function names
(doProviderSwitch, setupTest, setupSave, setupSaveCustom, confirmWipe) and state
hooks intact so behavior is unchanged.

Source: Coding guidelines

app/src/components/settings/panels/AutocompletePanel.tsx (1)

285-300: ⚡ Quick win

Dual save paths may confuse users.

The numeric fields (debounceMs, maxChars, overlayTtlMs) now auto-save on commit (blur/enter) via onCommit={() => void saveConfig()}, but the panel also retains an explicit "Save Settings" button (lines 337-345). Users may be unclear whether their changes persist immediately on field blur or require clicking the button. Consider either removing the button and relying solely on auto-save, or removing the onCommit handlers and keeping only the explicit save action.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@app/src/components/settings/panels/AutocompletePanel.tsx` around lines 285 -
300, The panel currently has two save UX paths: per-field onCommit handlers
calling saveConfig (see SettingsNumberField usages like the debounceMs field
with onCommit={() => void saveConfig()}) and a separate explicit "Save Settings"
button; pick one to avoid confusion — I recommend removing the per-field
auto-save handlers: delete the onCommit prop from all SettingsNumberField
instances (debounceMs, maxChars, overlayTtlMs) so changes are only persisted
when the Save Settings button calls saveConfig, leaving the button and its
handler intact.
app/src/components/settings/panels/VoicePanel.tsx (1)

1-1318: 🏗️ Heavy lift

File exceeds size guideline by 2.6×.

At 1318 lines, this file is significantly larger than the ~500 line guideline. The component handles multiple concerns (provider chips, API key modal, voice routing, PTT settings) that could be extracted into focused modules. Consider splitting into separate components: VoiceProvidersSection, VoiceRoutingSection, VoiceProviderModal, etc. This would improve maintainability, testability, and align with the codebase's modularity standards.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@app/src/components/settings/panels/VoicePanel.tsx` around lines 1 - 1318, The
file is too large; split VoicePanel into smaller components: extract the
provider chips + modal into VoiceProvidersSection/VoiceProviderModal, and the
routing UI into VoiceRoutingSection, while keeping VoicePanel as the
orchestrator. Move related state and handlers (voiceSettings, setVoiceSettings,
pendingKeySlug, pendingKeyValue, isSavingPendingKey, keyTestResult,
isTestingKey, handleEnableExternalProvider, handleRemoveProvider,
handleInstallWhisper, handleInstallPiper, installButtonLabel, whisperInstall,
piperInstall, isInstallingWhisper, isInstallingPiper, elevenlabsVoiceId,
setElevenlabsVoiceId, sttModel, setSttModel, ttsVoice, setTtsVoice,
persistProviders, loadData, saveRouting) into the parent or into the new
components as appropriate and pass them via props; ensure side-effectful
functions like loadData and persistProviders remain in VoicePanel (or a hook)
and are invoked by children through callbacks, preserve existing prop names and
testids (e.g., data-testid="voice-providers-section",
"voice-provider-key-modal", "stt-provider-select", "tts-provider-select") and
keep translations via t and navigation functions passed down so behavior and
test hooks remain unchanged.

Source: Coding guidelines

app/src/components/settings/panels/WebhooksDebugPanel.tsx (1)

349-360: ⚡ Quick win

Incomplete color token migration in PayloadBlock.

The PayloadBlock component still uses stone-* color tokens (stone-500, stone-200, stone-950, stone-100) while the rest of the file has been migrated to neutral-* tokens. For consistency with the panel's styling and the broader refactor, update these to their neutral-* equivalents.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@app/src/components/settings/panels/WebhooksDebugPanel.tsx` around lines 349 -
360, PayloadBlock still uses stone-* color tokens; update them to match the rest
of the panel by replacing stone-500 with neutral-400 on the summary, stone-200
with neutral-800 for the border, stone-950 with neutral-50 for the background,
and stone-100 with neutral-900 for the pre text so the component uses neutral-*
tokens consistently (look for the PayloadBlock function declaration and the
className strings to change).
app/src/components/settings/panels/NotificationRoutingPanel.tsx (1)

171-201: 💤 Low value

Consider extracting the inline array constant.

The howItWorksLevels array is defined inline within the JSX return statement, causing it to be recreated on every render. While the performance impact is negligible for 4 static items, extracting it as a module-level constant would follow best practices for static reference data.

♻️ Suggested refactor
+const HOW_IT_WORKS_LEVELS = [
+  {
+    label: 'notifications.routing.level.drop',
+    desc: 'notifications.routing.level.dropDesc',
+    color: 'bg-neutral-100 dark:bg-neutral-800 text-neutral-600 dark:text-neutral-300',
+  },
+  {
+    label: 'notifications.routing.level.acknowledge',
+    desc: 'notifications.routing.level.acknowledgeDesc',
+    color: 'bg-blue-100 dark:bg-blue-500/20 text-blue-700 dark:text-blue-300',
+  },
+  {
+    label: 'notifications.routing.level.react',
+    desc: 'notifications.routing.level.reactDesc',
+    color: 'bg-amber-100 dark:bg-amber-500/20 text-amber-700 dark:text-amber-300',
+  },
+  {
+    label: 'notifications.routing.level.escalate',
+    desc: 'notifications.routing.level.escalateDesc',
+    color: 'bg-red-100 dark:bg-red-500/20 text-red-700 dark:text-red-300',
+  },
+] as const;
+
 const NotificationRoutingPanel = ({ embedded = false }: NotificationRoutingPanelProps = {}) => {
   const { t } = useT();
   // ...

   <SettingsSection title={t('notifications.routing.howItWorks')}>
-    {[
-      {
-        label: t('notifications.routing.level.drop'),
-        desc: t('notifications.routing.level.dropDesc'),
-        color: 'bg-neutral-100 dark:bg-neutral-800 text-neutral-600 dark:text-neutral-300',
-      },
-      // ... rest of array
-    ].map(row => (
+    {HOW_IT_WORKS_LEVELS.map(row => (
       <div key={row.label} className="flex items-center gap-3 px-4 py-3">
         <span className={`flex-shrink-0 px-2 py-0.5 rounded text-[11px] font-semibold ${row.color}`}>
-          {row.label}
+          {t(row.label)}
         </span>
-        <span className="text-xs text-neutral-600 dark:text-neutral-300">{row.desc}</span>
+        <span className="text-xs text-neutral-600 dark:text-neutral-300">{t(row.desc)}</span>
       </div>
     ))}
   </SettingsSection>
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@app/src/components/settings/panels/NotificationRoutingPanel.tsx` around lines
171 - 201, Extract the inline array of routing level objects into a module-level
constant (e.g., export or const howItWorksLevels) and replace the inline array
used in NotificationRoutingPanel's JSX map with that constant; ensure each
object keeps the same properties (label, desc, color) and the map still uses
row.label as the key so the UI output and i18n calls (t(...)) remain unchanged.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@app/src/components/settings/controls/SettingsCheckbox.tsx`:
- Around line 12-31: Remove the forwardRef wrapper around SettingsCheckbox and
treat ref as a normal prop: change the component to a plain function component
that accepts a ref prop, keep innerRef = useRef<HTMLInputElement>(null) as a
fallback, compute resolvedRef = (ref ?? innerRef) and ensure you handle both
object refs and callback refs when assigning (if ref is a function, call it with
the element in an effect/assignment), then update the useEffect that sets
resolvedRef.current.indeterminate to use the computed resolvedRef; update any
types to accept ref as an optional prop on SettingsCheckboxProps and remove the
forwardRef import/usage.

In `@app/src/components/settings/panels/HeartbeatPanel.tsx`:
- Around line 48-50: The loading branch incorrectly shows the loading message
even when fetch failed because the conditional uses "snapshot ? ... : loading"
without checking loadError; update the JSX conditional in HeartbeatPanel (and
the sibling AI snapshot panel) to gate the loading branch with "!loadError" so
it renders loading only when there's no error (i.e., snapshot ? <snapshot UI> :
(!loadError ? <loading UI using t('common.loading')> : <error/fallback UI>));
reference the snapshot and loadError variables and replace the simple ternary
with this three-way check so terminal fetch failures display the error state
instead of the loading text.

In `@app/src/components/settings/panels/NotificationRoutingPanel.tsx`:
- Around line 203-269: The per-provider UI in NotificationRoutingPanel.tsx uses
native checkbox inputs for enabled and route_to_orchestrator (currently bound
via updateSetting) which must be replaced with the shared
SettingsSwitch/SettingsCheckbox component for visual/behavioral consistency;
import the shared control (SettingsSwitch or SettingsCheckbox) at the top,
replace the two <input type="checkbox"> usages (the one bound to s.enabled and
the one bound to s.route_to_orchestrator) with the shared component, preserve
props: checked (s.enabled / s.route_to_orchestrator), disabled
(controlsDisabled), and onChange (call void updateSetting(provider, { enabled:
... }) or void updateSetting(provider, { route_to_orchestrator: ... })
respectively), and keep existing labels, hasLoadError handling, and the range
input unchanged.

---

Nitpick comments:
In `@app/src/components/settings/controls/SettingsListItem.tsx`:
- Around line 8-9: The props API currently requires removeLabel while onRemove
is optional, forcing callers to pass an unused label; update
SettingsListItemProps to make removeLabel optional or make the two props
required together and add a runtime guard before rendering the remove Button:
either change the type so removeLabel?: string and in SettingsListItem render
the Button only when onRemove && removeLabel, or implement a discriminated union
for SettingsListItemProps such that one variant requires both onRemove and
removeLabel and the other forbids both; ensure the JSX around the Button (the
element that uses aria-label={removeLabel}) checks both values before rendering.

In `@app/src/components/settings/controls/SettingsTextField.tsx`:
- Around line 5-7: Add an explicit optional inputSize prop to
SettingsTextFieldProps and pass it through (or map it) to the underlying Input
in SettingsTextField so callers can use the same API as SettingsSelect; update
the interface to include inputSize?: SettingsSelectSize, accept it in the
SettingsTextField component signature, and forward it into the Input component
props (or convert to the appropriate class names) while leaving mono and other
InputProps untouched.

In `@app/src/components/settings/panels/AgentEditorPage.tsx`:
- Around line 1-659: Extract the ToolsPickerModal (and its helper Checkbox
component) out of AgentEditorPage into a new component file to reduce
AgentEditorPage size: create a new AgentEditorToolsPickerModal.tsx exporting
ToolsPickerModal and Checkbox, move the ToolsPickerModal function (including its
props type and internal state/useEffects) and the Checkbox function there,
import ToolsPickerModal into AgentEditorPage and update any referenced symbols
(ToolsPickerModal, Checkbox) accordingly; ensure the new file imports useT,
agentRegistryApi, AgentToolInfo, Button, SettingsTextField, LuSearch, LuX and
preserves prop types (allToolsSelected, selected, onToggleAll, onToggleTool,
onClose) and behavior so existing calls from AgentEditorPage remain unchanged.

In `@app/src/components/settings/panels/AutocompleteDebugPanel.tsx`:
- Around line 1-779: The file AutocompleteDebugPanel.tsx is too large and should
be split into smaller components; extract the major sections (Runtime, Test,
Live Logs, Advanced settings, Personalization History) into separate components
(e.g., RuntimeSection, TestSection, LiveLogsSection, AdvancedSettingsSection,
PersonalizationHistorySection) and update AutocompleteDebugPanel to compose
them. Move or expose the related state and handlers (status, isLoading,
isSaving, error, message, logs, historyEntries, focusDebug, debounceMs,
maxChars, overlayTtlMs, styleInstructions, styleExamplesText and helper
functions appendLogs, appendUiLog, trackStatusChanges, load, loadHistory,
refreshStatus, start, stop, testCurrent, acceptSuggestion, debugFocus,
saveAdvancedConfig, clearHistory, clearLogs, waitForAcceptedHistoryEntry) by
either hoisting state into AutocompleteDebugPanel and passing props/callbacks
into the new components or by moving cohesive state+handlers into the new
component modules. Keep shared utilities like parseAutocompleteConfig and
DEFAULT_CONFIG in the original file or a shared utils module, and ensure imports
still use SettingsHeader and SettingsSection where needed. Ensure each new
component receives the minimal props required (e.g., RuntimeSection needs
status, isLoading, refreshStatus, start, stop; TestSection needs
contextOverride, setContextOverride, testCurrent, acceptSuggestion, debugFocus,
focusDebug; LiveLogsSection needs logs, clearLogs; AdvancedSettingsSection needs
debounceMs, setDebounceMs, maxChars, setMaxChars, overlayTtlMs, setOverlayTtlMs,
styleInstructions, setStyleInstructions, styleExamplesText,
setStyleExamplesText, saveAdvancedConfig, isSaving;
PersonalizationHistorySection needs historyEntries, isHistoryLoading,
isClearingHistory, clearHistory) and export them for reuse.

In `@app/src/components/settings/panels/AutocompletePanel.tsx`:
- Around line 285-300: The panel currently has two save UX paths: per-field
onCommit handlers calling saveConfig (see SettingsNumberField usages like the
debounceMs field with onCommit={() => void saveConfig()}) and a separate
explicit "Save Settings" button; pick one to avoid confusion — I recommend
removing the per-field auto-save handlers: delete the onCommit prop from all
SettingsNumberField instances (debounceMs, maxChars, overlayTtlMs) so changes
are only persisted when the Save Settings button calls saveConfig, leaving the
button and its handler intact.

In `@app/src/components/settings/panels/EmbeddingsPanel.tsx`:
- Around line 1-722: The file is too large (722 lines); extract the inline setup
popup and confirm-wipe dialog into separate components to reduce EmbeddingsPanel
size. Create EmbeddingsSetupModal and EmbeddingsConfirmWipeModal components and
move the JSX currently rendered when setupProvider is truthy and when
pendingWipe is truthy (the entire modal blocks) into those files; expose props
for the required state and handlers (e.g., setupProvider, setupKey,
setupShowKey, setupTesting, setupTestResult, setupSaving, setupError,
customEndpoint, customModel, customDims, setSetupProvider, setSetupKey,
setSetupShowKey, setCustomEndpoint, setCustomModel, setCustomDims, setupTest,
setupSave, setupSaveCustom for the setup modal; pendingWipe, setPendingWipe,
confirmWipe for the confirm modal). Import and render <EmbeddingsSetupModal
.../> and <EmbeddingsConfirmWipeModal .../> from EmbeddingsPanel, keeping the
existing function names (doProviderSwitch, setupTest, setupSave,
setupSaveCustom, confirmWipe) and state hooks intact so behavior is unchanged.

In `@app/src/components/settings/panels/MascotPanel.tsx`:
- Around line 1-738: File is too large; extract three focused subcomponents to
reduce MascotPanel size: create MascotColorPicker, MascotVoicePicker, and
MascotCharacterPicker. MascotColorPicker should own the swatch grid UI and
custom color controls and accept props: available (filtered COLOR_OPTIONS),
activeColor, customPrimary, customSecondary, handleSelect, dispatch handlers
setCustomPrimaryColor/setCustomSecondaryColor (or callbacks), and
getMascotPalette/hexToArgbInt usage moved in or passed as needed.
MascotVoicePicker should accept voice state/handlers: voiceGender,
useLocaleDefault, visiblePresets, effectiveVoiceId, storedVoiceId, voiceDraft,
voicePasteMode, isPreviewingVoice, voicePreviewError, onGenderChange,
onLocaleDefaultToggle, onPresetChange, onSavePaste, onVoiceReset,
onVoicePreview, localeDefaultVoiceId, and
isCuratedVoicePreset/defaultVoiceIdForLocale usage moved in or passed.
MascotCharacterPicker should accept backendList, backendListError,
selectedMascotId, customMascotGifUrl, customGifDraft, customGifError,
activeDetail, detailError, handleSelectBackend, onSaveCustomGif,
onResetCustomGif, and render BackendMascot/CustomGifMascot. Keep MascotPanel as
coordinator: maintain state/logic (fetches, preview refs, dispatch calls) and
pass only the necessary props/callbacks to the new components.

In `@app/src/components/settings/panels/NotificationRoutingPanel.tsx`:
- Around line 171-201: Extract the inline array of routing level objects into a
module-level constant (e.g., export or const howItWorksLevels) and replace the
inline array used in NotificationRoutingPanel's JSX map with that constant;
ensure each object keeps the same properties (label, desc, color) and the map
still uses row.label as the key so the UI output and i18n calls (t(...)) remain
unchanged.

In `@app/src/components/settings/panels/ScreenIntelligencePanel.tsx`:
- Around line 143-195: The two raw checkbox inputs in ScreenIntelligencePanel
should be replaced with the shared SettingsCheckbox component for UI
consistency: swap the input used for the "Enabled" toggle (where
checked={enabled} and onChange calls setEnabled) and the "Screen monitoring"
toggle (where onChange updates setFeatureOverrides.screen_monitoring) to use
SettingsCheckbox, wiring its checked/value and onChange props to the same state
handlers (setEnabled and the setFeatureOverrides updater) and preserving the
existing labels and layout; reference the SettingsCheckbox component and the
ScreenIntelligencePanel handlers setEnabled and setFeatureOverrides when making
the change.

In `@app/src/components/settings/panels/TaskSourcesPanel.tsx`:
- Around line 1-597: The file is too large; extract parts of TaskSourcesPanel
into child components to stay under 500 lines: create a TaskSourceForm component
(move the "Add a source" JSX and its local form state and handlers: provider,
name, primary, labels, assignedToMe, databases, buildFilter, addSource,
previewFilter, browseDatabases, primaryLabel) and a TaskSourceList component
(move the configured sources list JSX and handlers: sources rendering,
toggleSource, fetchNow, removeSource, syncAll, load, formatSyncNotice), then
import and use these new components inside TaskSourcesPanel passing required
props (e.g., t, busyKey, setBusyKey, loading, sources, setSources, status,
setStatus, notice/setNotice, error/setError, load) so existing logic and state
updates remain intact while reducing TaskSourcesPanel size.

In `@app/src/components/settings/panels/VoicePanel.tsx`:
- Around line 1-1318: The file is too large; split VoicePanel into smaller
components: extract the provider chips + modal into
VoiceProvidersSection/VoiceProviderModal, and the routing UI into
VoiceRoutingSection, while keeping VoicePanel as the orchestrator. Move related
state and handlers (voiceSettings, setVoiceSettings, pendingKeySlug,
pendingKeyValue, isSavingPendingKey, keyTestResult, isTestingKey,
handleEnableExternalProvider, handleRemoveProvider, handleInstallWhisper,
handleInstallPiper, installButtonLabel, whisperInstall, piperInstall,
isInstallingWhisper, isInstallingPiper, elevenlabsVoiceId, setElevenlabsVoiceId,
sttModel, setSttModel, ttsVoice, setTtsVoice, persistProviders, loadData,
saveRouting) into the parent or into the new components as appropriate and pass
them via props; ensure side-effectful functions like loadData and
persistProviders remain in VoicePanel (or a hook) and are invoked by children
through callbacks, preserve existing prop names and testids (e.g.,
data-testid="voice-providers-section", "voice-provider-key-modal",
"stt-provider-select", "tts-provider-select") and keep translations via t and
navigation functions passed down so behavior and test hooks remain unchanged.

In `@app/src/components/settings/panels/WebhooksDebugPanel.tsx`:
- Around line 349-360: PayloadBlock still uses stone-* color tokens; update them
to match the rest of the panel by replacing stone-500 with neutral-400 on the
summary, stone-200 with neutral-800 for the border, stone-950 with neutral-50
for the background, and stone-100 with neutral-900 for the pre text so the
component uses neutral-* tokens consistently (look for the PayloadBlock function
declaration and the className strings to change).
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 963c20e8-cc05-4710-aa18-4783a7f1e9f9

📥 Commits

Reviewing files that changed from the base of the PR and between dde4935 and 9f6daad.

📒 Files selected for processing (91)
  • app/src/components/dashboard/CostDashboardPanel.tsx
  • app/src/components/settings/controls/SettingsBadge.tsx
  • app/src/components/settings/controls/SettingsCheckbox.tsx
  • app/src/components/settings/controls/SettingsEmptyState.tsx
  • app/src/components/settings/controls/SettingsListItem.tsx
  • app/src/components/settings/controls/SettingsNumberField.tsx
  • app/src/components/settings/controls/SettingsRow.tsx
  • app/src/components/settings/controls/SettingsSection.tsx
  • app/src/components/settings/controls/SettingsSelect.tsx
  • app/src/components/settings/controls/SettingsStatusLine.tsx
  • app/src/components/settings/controls/SettingsSwitch.tsx
  • app/src/components/settings/controls/SettingsTextArea.tsx
  • app/src/components/settings/controls/SettingsTextField.tsx
  • app/src/components/settings/controls/__tests__/controls.test.tsx
  • app/src/components/settings/controls/index.ts
  • app/src/components/settings/panels/AIPanel.tsx
  • app/src/components/settings/panels/AboutPanel.tsx
  • app/src/components/settings/panels/AgentAccessPanel.tsx
  • app/src/components/settings/panels/AgentActivityPanel.tsx
  • app/src/components/settings/panels/AgentChatPanel.tsx
  • app/src/components/settings/panels/AgentEditorPage.tsx
  • app/src/components/settings/panels/AgentsPanel.tsx
  • app/src/components/settings/panels/AppearancePanel.tsx
  • app/src/components/settings/panels/ApprovalHistoryPanel.tsx
  • app/src/components/settings/panels/AutocompleteDebugPanel.tsx
  • app/src/components/settings/panels/AutocompletePanel.tsx
  • app/src/components/settings/panels/AutonomyPanel.tsx
  • app/src/components/settings/panels/BillingPanel.tsx
  • app/src/components/settings/panels/CompanionPanel.tsx
  • app/src/components/settings/panels/ComposioPanel.tsx
  • app/src/components/settings/panels/ComposioTriagePanel.tsx
  • app/src/components/settings/panels/CronJobsPanel.tsx
  • app/src/components/settings/panels/DevWorkflowPanel.tsx
  • app/src/components/settings/panels/DeveloperOptionsPanel.tsx
  • app/src/components/settings/panels/DevicesPanel.tsx
  • app/src/components/settings/panels/EmbeddingsPanel.tsx
  • app/src/components/settings/panels/EventLogPanel.tsx
  • app/src/components/settings/panels/HeartbeatPanel.tsx
  • app/src/components/settings/panels/LedgerUsagePanel.tsx
  • app/src/components/settings/panels/LocalModelDebugPanel.tsx
  • app/src/components/settings/panels/MascotPanel.tsx
  • app/src/components/settings/panels/McpServerPanel.tsx
  • app/src/components/settings/panels/MemoryDataPanel.tsx
  • app/src/components/settings/panels/MemoryDebugPanel.tsx
  • app/src/components/settings/panels/MemorySyncPanel.tsx
  • app/src/components/settings/panels/MigrationPanel.tsx
  • app/src/components/settings/panels/ModelHealthPanel.tsx
  • app/src/components/settings/panels/NotificationRoutingPanel.tsx
  • app/src/components/settings/panels/NotificationsPanel.tsx
  • app/src/components/settings/panels/NotificationsTabbedPanel.tsx
  • app/src/components/settings/panels/PermissionsPanel.tsx
  • app/src/components/settings/panels/PersonaPanel.tsx
  • app/src/components/settings/panels/PrivacyPanel.tsx
  • app/src/components/settings/panels/RecoveryPhrasePanel.tsx
  • app/src/components/settings/panels/SandboxSettingsPanel.tsx
  • app/src/components/settings/panels/ScreenAwarenessDebugPanel.tsx
  • app/src/components/settings/panels/ScreenIntelligencePanel.tsx
  • app/src/components/settings/panels/SearchPanel.tsx
  • app/src/components/settings/panels/SecurityPanel.tsx
  • app/src/components/settings/panels/TaskSourcesPanel.tsx
  • app/src/components/settings/panels/TasksPanel.tsx
  • app/src/components/settings/panels/TeamInvitesPanel.tsx
  • app/src/components/settings/panels/TeamManagementPanel.tsx
  • app/src/components/settings/panels/TeamMembersPanel.tsx
  • app/src/components/settings/panels/TeamPanel.tsx
  • app/src/components/settings/panels/ToolPolicyDiagnosticsPanel.tsx
  • app/src/components/settings/panels/ToolsPanel.tsx
  • app/src/components/settings/panels/VoiceDebugPanel.tsx
  • app/src/components/settings/panels/VoicePanel.tsx
  • app/src/components/settings/panels/WalletBalancesPanel.tsx
  • app/src/components/settings/panels/WebhooksDebugPanel.tsx
  • app/src/components/settings/panels/__tests__/AgentAccessPanel.test.tsx
  • app/src/components/settings/panels/__tests__/AutocompletePanel.test.tsx
  • app/src/components/settings/panels/__tests__/DevicesPanel.test.tsx
  • app/src/components/settings/panels/__tests__/RecoveryPhrasePanel.test.tsx
  • app/src/components/settings/panels/__tests__/SandboxSettingsPanel.test.tsx
  • app/src/components/settings/panels/__tests__/ScreenIntelligencePanel.test.tsx
  • app/src/components/settings/panels/autocomplete/AppFilterSection.tsx
  • app/src/components/settings/panels/autocomplete/CompletionStyleSection.tsx
  • app/src/components/settings/panels/billing/AutoRechargeSection.tsx
  • app/src/components/settings/panels/billing/PayAsYouGoCard.tsx
  • app/src/components/settings/panels/billing/SubscriptionPlans.tsx
  • app/src/components/settings/panels/devices/PairPhoneModal.tsx
  • app/src/components/settings/panels/local-model/ModelDownloadSection.tsx
  • app/src/components/settings/panels/local-model/ModelStatusSection.tsx
  • app/src/pages/Intelligence.tsx
  • app/src/pages/Webhooks.tsx
  • app/src/pages/settings/voice/PttSettingsPanel.tsx
  • app/test/playwright/specs/settings-advanced-config.spec.ts
  • app/test/playwright/specs/settings-ai-skills.spec.ts
  • app/test/playwright/specs/settings-feature-preferences.spec.ts
✅ Files skipped from review due to trivial changes (4)
  • app/src/components/settings/panels/MemoryDataPanel.tsx
  • app/src/components/settings/controls/index.ts
  • app/src/components/settings/panels/MemorySyncPanel.tsx
  • app/src/components/settings/panels/autocomplete/AppFilterSection.tsx
🚧 Files skipped from review as they are similar to previous changes (4)
  • app/src/components/settings/panels/LocalModelDebugPanel.tsx
  • app/src/components/settings/panels/TasksPanel.tsx
  • app/src/components/settings/panels/NotificationsTabbedPanel.tsx
  • app/src/components/settings/panels/DeveloperOptionsPanel.tsx

The form-language migration changed control DOM, breaking E2E specs that
queried the old markup. Fixes:
- SettingsSection title is now a real <h3> (not a <p>) and no longer CSS-
  uppercased, so getByRole('heading') resolves section titles and innerText
  matching isn't corrupted by text-transform (a11y win too).
- autocomplete-flow: 'Autocomplete' now appears twice → scope to .first().
- feature-preferences: tool rows are SettingsRow+SettingsSwitch → target the
  switch by role+name instead of a text-bearing button.
- leaf-workflows: AgentEditor ID field accessible name is now 'ID'.
- Frontend logging: replace console.debug with the namespaced `debug` logger
  (settings:nav/registry/search/developer-mode/webhooks/intelligence) per the
  repo convention.
- SettingsCheckbox: drop forwardRef/RefObject machinery (React 19, no caller
  passes a ref); drive `indeterminate` via an internal ref.
- HeartbeatPanel + LedgerUsagePanel: gate the loading branch with !loadError so
  a terminal fetch failure shows the error state instead of a stuck 'Loading…'.
- NotificationRoutingPanel: migrate native per-provider checkboxes to the shared
  SettingsCheckbox (role=checkbox + 'Enabled' accessible name preserved).

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
app/src/components/settings/panels/AboutPanel.tsx (1)

64-66: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Replace residual console.* logs with the namespaced debug logger.

Line 64 and Line 76 still use console.warn/console.debug in frontend code, while this file now has a namespaced debug logger. Switch both to log(...) for consistency with the project logging contract.

Suggested patch
     invoke<string>('core_rpc_url')
       .then(url => {
         if (!cancelled) setRpcUrl(url);
       })
       .catch(err => {
-        console.warn('[about-panel] failed to resolve core_rpc_url', err);
+        log('failed to resolve core_rpc_url: %o', err);
         if (!cancelled) setRpcUrl(null);
       });
@@
   const handleCheck = async () => {
-    console.debug('[app-update] AboutPanel: manual check');
+    log('manual update check requested');
     const result = await check();
     if (result !== null) setLastCheckedAt(new Date());
   };

As per coding guidelines, frontend logging should use a namespaced debug function.

Also applies to: 76-76

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@app/src/components/settings/panels/AboutPanel.tsx` around lines 64 - 66, Find
the remaining console.* calls inside the AboutPanel component (the promise catch
that currently calls console.warn('[about-panel] failed to resolve
core_rpc_url', err) and the other console.debug call) and replace them with the
namespaced logger call `log(...)` so messages and error objects are preserved
(e.g. log('[about-panel] failed to resolve core_rpc_url', err)). Ensure you
reuse the existing `log` debug/logger instance already in the file and keep the
surrounding behavior (e.g., the cancelled check and setRpcUrl(null)) unchanged.

Source: Coding guidelines

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@app/src/components/settings/panels/AboutPanel.tsx`:
- Around line 64-66: Find the remaining console.* calls inside the AboutPanel
component (the promise catch that currently calls console.warn('[about-panel]
failed to resolve core_rpc_url', err) and the other console.debug call) and
replace them with the namespaced logger call `log(...)` so messages and error
objects are preserved (e.g. log('[about-panel] failed to resolve core_rpc_url',
err)). Ensure you reuse the existing `log` debug/logger instance already in the
file and keep the surrounding behavior (e.g., the cancelled check and
setRpcUrl(null)) unchanged.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: bce2a4ba-93dc-4495-b093-068193acc3bc

📥 Commits

Reviewing files that changed from the base of the PR and between 0bb78b1 and 6d45072.

📒 Files selected for processing (10)
  • app/src/components/settings/controls/SettingsCheckbox.tsx
  • app/src/components/settings/hooks/useSettingsNavigation.ts
  • app/src/components/settings/panels/AboutPanel.tsx
  • app/src/components/settings/panels/HeartbeatPanel.tsx
  • app/src/components/settings/panels/LedgerUsagePanel.tsx
  • app/src/components/settings/panels/NotificationRoutingPanel.tsx
  • app/src/components/settings/search/settingsSearchRegistry.ts
  • app/src/components/settings/settingsRouteRegistry.ts
  • app/src/pages/Intelligence.tsx
  • app/src/pages/Webhooks.tsx
🚧 Files skipped from review as they are similar to previous changes (3)
  • app/src/components/settings/panels/NotificationRoutingPanel.tsx
  • app/src/components/settings/panels/HeartbeatPanel.tsx
  • app/src/components/settings/panels/LedgerUsagePanel.tsx

The form-language migration changed many lines in panels with thin/no unit
coverage (debug/data panels, VoicePanel, Embeddings, Team/billing/Security,
AgentEditor, Webhooks, etc.), dropping changed-line coverage to 62%. Add
focused render/interaction tests targeting the uncovered changed lines:
switches, selects, list/empty/error states, modals, and save/handler flows.
~360 net new tests; all deps mocked, generic placeholder data only.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
app/src/components/settings/panels/__tests__/AutocompletePanel.test.tsx (1)

33-33: ⚠️ Potential issue | 🟡 Minor

Use interface for the RuntimeHarness object shape

Line 33 defines RuntimeHarness via a type alias; switch it to an interface to match the repo’s TS guideline for object shapes.

Proposed patch
-type RuntimeHarness = { status: AutocompleteStatus; config: AutocompleteConfig };
+interface RuntimeHarness {
+  status: AutocompleteStatus;
+  config: AutocompleteConfig;
+}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@app/src/components/settings/panels/__tests__/AutocompletePanel.test.tsx` at
line 33, Replace the type alias RuntimeHarness with an interface to match the
repo guideline: change "type RuntimeHarness = { status: AutocompleteStatus;
config: AutocompleteConfig }" to "interface RuntimeHarness { status:
AutocompleteStatus; config: AutocompleteConfig }", and ensure any usages,
imports or exports referencing RuntimeHarness remain valid (no runtime changes
required).

Source: Coding guidelines

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@app/src/components/settings/panels/__tests__/DevicesPanel.test.tsx`:
- Around line 160-181: Tests are asserting implementation CSS classes
(bg-sage-500/bg-neutral-300); instead make the tests assert semantic state from
the PeerDot component: add a stable attribute (e.g., data-testid="peer-dot" and
a data-online="true"/"false" or aria-label="online"/"offline") in the PeerDot
used inside DevicesPanel, then update the two tests in DevicesPanel.test.tsx to
locate the device row (using screen.findByText('Online iPhone') / 'Offline
iPhone') and query within that row for the peer-dot test id (or aria label) and
assert the data-online or aria-label value rather than querying for Tailwind
class names; keep existing helpers makeDevice and renderWithProviders unchanged.

In `@app/src/components/settings/panels/TaskSourcesPanel.test.tsx`:
- Around line 262-291: Move the vi.mock block and the listDatabasesMock
declaration out of the test into module scope so Vitest can hoist the mock
before imports; declare const listDatabasesMock = vi.fn() at top-level, then
call vi.mock(...) at top-level to return openhumanTaskSourcesListDatabases: ()
=> listDatabasesMock(), and in the test set
listDatabasesMock.mockResolvedValue([...]) (or reset/set per-test) before
importing TaskSourcesPanel so the dynamic import of TaskSourcesPanel picks up
the mocked openhumanTaskSourcesListDatabases; alternatively remove the
ineffective test if you don't intend to validate that flow.

---

Outside diff comments:
In `@app/src/components/settings/panels/__tests__/AutocompletePanel.test.tsx`:
- Line 33: Replace the type alias RuntimeHarness with an interface to match the
repo guideline: change "type RuntimeHarness = { status: AutocompleteStatus;
config: AutocompleteConfig }" to "interface RuntimeHarness { status:
AutocompleteStatus; config: AutocompleteConfig }", and ensure any usages,
imports or exports referencing RuntimeHarness remain valid (no runtime changes
required).
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 75aca5b4-c370-4f4a-86c0-3ab45f53fef0

📥 Commits

Reviewing files that changed from the base of the PR and between 6d45072 and 66bbfa4.

📒 Files selected for processing (30)
  • app/src/components/settings/__tests__/SettingsHome.test.tsx
  • app/src/components/settings/panels/AgentEditorPage.test.tsx
  • app/src/components/settings/panels/McpServerPanel.test.tsx
  • app/src/components/settings/panels/TaskSourcesPanel.test.tsx
  • app/src/components/settings/panels/ToolsPanel.test.tsx
  • app/src/components/settings/panels/__tests__/AgentChatPanel.test.tsx
  • app/src/components/settings/panels/__tests__/AutocompleteDebugPanel.test.tsx
  • app/src/components/settings/panels/__tests__/AutocompletePanel.test.tsx
  • app/src/components/settings/panels/__tests__/AutonomyPanel.test.tsx
  • app/src/components/settings/panels/__tests__/DevicesPanel.test.tsx
  • app/src/components/settings/panels/__tests__/EmbeddingsPanel.test.tsx
  • app/src/components/settings/panels/__tests__/LocalModelDebugPanel.test.tsx
  • app/src/components/settings/panels/__tests__/MascotPanel.test.tsx
  • app/src/components/settings/panels/__tests__/MemoryDebugPanel.test.tsx
  • app/src/components/settings/panels/__tests__/SandboxSettingsPanel.test.tsx
  • app/src/components/settings/panels/__tests__/ScreenAwarenessDebugPanel.test.tsx
  • app/src/components/settings/panels/__tests__/ScreenIntelligencePanel.test.tsx
  • app/src/components/settings/panels/__tests__/SecurityPanel.test.tsx
  • app/src/components/settings/panels/__tests__/TeamInvitesPanel.test.tsx
  • app/src/components/settings/panels/__tests__/TeamManagementPanel.test.tsx
  • app/src/components/settings/panels/__tests__/TeamMembersPanel.test.tsx
  • app/src/components/settings/panels/__tests__/TeamPanel.test.tsx
  • app/src/components/settings/panels/__tests__/VoiceDebugPanel.test.tsx
  • app/src/components/settings/panels/__tests__/VoicePanel.test.tsx
  • app/src/components/settings/panels/__tests__/WebhooksDebugPanel.test.tsx
  • app/src/components/settings/panels/billing/__tests__/AutoRechargeSection.test.tsx
  • app/src/components/settings/panels/billing/__tests__/SubscriptionPlans.test.tsx
  • app/src/components/settings/panels/local-model/ModelDownloadSection.test.tsx
  • app/src/components/settings/panels/local-model/ModelStatusSection.test.tsx
  • app/src/pages/__tests__/Webhooks.test.tsx
🚧 Files skipped from review as they are similar to previous changes (1)
  • app/src/components/settings/tests/SettingsHome.test.tsx

- TaskSourcesPanel.test: hoist the listDatabases mock to module scope (a
  vi.mock inside the test body never applied) and actually exercise the
  Browse Databases → database dropdown flow.
- DevicesPanel: add peer-status-online/offline data-testids to PeerDot and
  assert those instead of Tailwind class names (test behavior, not styling).
The 'Rust Core Coverage' and 'Rust E2E' jobs intermittently die with
'ld terminated with signal 7 [Bus error]' — the instrumented test binaries'
DWARF debug info exhausts the runner's build partition during linking (the
job's own comment documents the disk-pressure root cause). CARGO_BUILD_JOBS=1
was already set but a single link still overflows.

- Set CARGO_PROFILE_DEV_DEBUG=line-tables-only on both jobs to shrink binaries
  sharply. llvm-cov line coverage reads __llvm_covmap, not DWARF, so coverage
  numbers are unaffected; backtraces keep file/line.
- Add the /__t disk-cleanup step to rust-e2e (it had none) to match
  rust-core-coverage.

Unblocks the Coverage Gate, which was skipping for lack of the Rust lcov.
coderabbitai[bot]
coderabbitai Bot previously approved these changes Jun 11, 2026
line-tables-only let Rust E2E link, but the coverage-instrumented openhuman
core binaries are larger and still SIGBUS the linker on disk. Set
CARGO_PROFILE_DEV_DEBUG=0 for the rust-core-coverage job. llvm-cov reads line
data from __llvm_covmap/__llvm_covfun, not DWARF, so coverage is unaffected;
this is the maximum disk-footprint reduction.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

feature Net-new user-facing capability or product behavior. working A PR that is being worked on by the team.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants