Skip to content

fix(web):-make-WSL-settings-searchable

MacroscopeApp / Macroscope - UI Consistency failed Aug 31, 2026 in 8m 29s

UI Consistency: 1 issue found

1 finding

  • apps/web/src/components/settings/settingsSearch.ts (lines 262-267): the new wsl-backend catalog entry is gated only by desktopOnly, but the row it anchors to is Windows-only. renderWslRow() returns null when WSL is unavailable (the desktop side reports available: false for any non-win32 platform, and enabled/wslOnly are false there), so on macOS/Linux desktop builds searching "wsl" or "backend" produces a result that navigates to /settings/connections#wsl-backend, scrolls and focuses nothing, and leaves the hash stranded because the search-target ref never runs. Suggested fix: add a client-platform gate (e.g. a windowsOnly flag evaluated with isWindowsPlatform over desktopBridge?.getClientPlatform?.() ?? navigator.platform) alongside the existing isElectron filter, or omit the entry until such a gate exists.

The three searchableSetting("wsl-backend") call sites in ConnectionsSettings.tsx are mutually exclusive branches of renderWslRow(), so they do not produce duplicate DOM ids; SettingsRow correctly consumes id (anchor + tabIndex={-1}) and title (heading), so the spread itself is consistent with the established pattern.

Details

Note

Your check run agent prompt is: .macroscope/check-run-agents/ui-consistency.md
More information about how Check Run Agents work can be found in our Help Center.

Verification performed:

  • Traced searchableSetting -> SettingsRow (settingsLayout.tsx): id lands on the outer div via ...rowProps and is wired to useSettingsSearchTarget; title renders the h3 heading, not a native tooltip. Prop spread is contract-correct.
  • Confirmed the three changed call sites are in mutually exclusive early-return branches of renderWslRow() (load-error retry row, WSL-unavailable recovery row, distro picker row), so only one #wsl-backend element can exist at a time.
  • Traced search navigation in SettingsSidebarNav.tsx (handleSearchResultClick -> navigate({ hash: item.targetId ?? item.id })) and SettingsPageContainer / SettingsSearchTargetProvider scroll+focus+onTargetHandled flow to establish what happens when the anchor is absent.
  • Checked desktop gating: renderWslRow() sits inside desktopBridge ? ... : ... within the canManageLocalBackend branch; DesktopWslEnvironment.isAvailable returns false for platform !== "win32", and getWslState() always resolves an object, so the row renders nothing on non-Windows desktop.
  • Reviewed catalog precedents for conditionally rendered anchors (archive, source-control conditional ids; environment-identification using a stable parent targetId) \u2014 the "This environment" section here has no id, so no stable ancestor anchor is available.
  • Test changes reviewed: searchSettings("wsl") returning [] is valid in the jsdom test env (isElectron is false), and toContainEqual matches the literal catalog object. No further tests requested \u2014 this is a catalog/anchor change, not a primitive composition change.

No Tailwind/CSS ownership, theme variant, scroll/virtualization, or environment-routing issues were introduced by this diff.


🔍 Agent activity — 11 tool calls

💭 Looking at the PR changes, I see it replaces plain title strings with a searchableSetting helper call in three places, adds a search item marked desktopOnly, and includes a test. I want to check settingsSearch.ts and the helper implementation to understand how desktopOnly is handled, and verify whether all three call sites truly shared the same "WSL backend" title/context. I also notice the diff inserts a new expectation into what looks like an existing test block, so I should look at the actual test file to confirm how it's structured before drawing conclusions.

1. browse_code — apps/web/src/components/settings/settingsSearch.ts

2. browse_code — apps/web/src/components/settings/settingsSearch.test.ts

💭 I realize searchableSetting returns an id, and spreading it across three call sites creates duplicate DOM ids of wsl-backend, which would break anchor scrolling since search would jump to the first match rather than the intended one. I need to check ConnectionsSettings.tsx around lines 2700-2860 to confirm this.

3. browse_code — apps/web/src/components/settings/ConnectionsSettings.tsx

💭 Since these three call sites are mutually exclusive early-return branches within renderWslRow, only one ever renders at a time, so the duplicate id isn't actually a problem. I want to check whether the third branch renders SettingsRow alongside another wsl-only toggle row, and confirm renderWslRow is only invoked once, then verify how SettingsRow handles the id prop for DOM anchoring and search navigation scrolling. I'm now noticing the WSL row is desktopOnly, but that flag alone doesn't restrict it to Windows — WSL itself is Windows-specific, so on macOS or Linux desktop the row never renders, meaning a search result could point to an anchor that isn't there. I want to check whether the codebase has any platform-specific flag beyond desktopOnly, how missing anchors are typically handled, and look at the test file diff to see if they added an expectation for searching "wsl". I also want to trace how SettingsRow renders its title/id and whether search navigation uses targetId ?? id to scroll to the right element, since the WSL row's placement in the connections page could interact with existing anchors like remote-environments.

4. browse_code — In apps/web/src/components/settings, show me: (1) the SettingsRow component definition including its props (does it accept id and title, and where do they land in the DOM?), (2) the component that renders settings search results and performs the scroll/anchor navigation using SettingsSearchItem id/targetId, and (3) how the WSL backend row's visibility is gated (platform / isElectron / canManageLocalBackend) in ConnectionsSettings.tsx.

💭 Since only one call site renders at a time, there's no duplicate id risk at runtime. But I'm noticing the row won't render on non-Windows desktop when WSL is unavailable, meaning a search result there could point to a nonexistent anchor — and desktopOnly seems to be the only flag available to guard against that, so I need to check if there's precedent for hiding items in this situation. The enumerated rules cover UI consistency, primitives, Tailwind, scroll, and environment routing rather than this exact scenario, but it feels like a real behavioral gap — a macOS desktop search for "WSL" would scroll to nothing. I want to check if there's an isWindows-style helper available, and also grep for any remaining title="WSL backend" occurrences that the diff might have missed, since that would create catalog drift.

5. git_tools — WSL backend

6. browse_code — apps/web/src/env.ts

💭 I should check whether an id like "wsl-backend" is already claimed elsewhere, since the pattern seen in other entries is to prefix search item ids when a control already owns that id. I also need to check for a section id like "wsl", and look at the nested WSL-only row to see its title, confirming that both the distro row and the nested row render together inside the fragment.

7. git_tools — wsl-backend|id="wsl|SettingsSection|searchableSetting

8. browse_code — apps/web/src/components/settings/ConnectionsSettings.tsx

💭 I'm checking the pattern used for conditionally-rendered anchors elsewhere, like in SourceControlSettings, to confirm only one element owns the id since the branches are mutually exclusive at runtime. I want to verify whether renderWslRow() gets called more than once in the JSX, so I'm looking at the surrounding section around line 3010-3100. I'm also weighing whether the search item's desktopOnly gate is a real concern — since the row can return null on macOS/Linux, or when admin scope is missing on Windows, or when WSL is unused, the search entry could point to a missing anchor. This feels like a search-anchor correctness issue rather than one covered directly by the primitives/Tailwind/theme/scroll rules, but the catalog's own rationale for desktopOnly is exactly to avoid search results landing on missing anchors, so I need to think through whether this violates that intent even if the row-conditional pattern elsewhere handles the reverse case. On macOS this creates a dead search result — "WSL backend" would still surface but navigate to a page with an unhandled hash, which is a real regression matching the catalog's own desktopOnly rationale. I want to double check if searching "backend" also matches, and whether the desktopWslState actually resolves to null on macOS so the row doesn't render at all, which would change my conclusion.

9. browse_code — Two questions: (1) On macOS/Linux desktop (Electron), what does the desktop bridge's WSL state (desktopWslStateAtom / getWslState) return — is it null, or an object with available:false? Does the WSL row in ConnectionsSettings render at all on non-Windows desktop? (2) Is there any renderer-side platform detection helper available in apps/web/src (e.g. isWindows, platform from desktopBridge, navigator.platform, server config os) that a settings search catalog entry could use to gate a Windows-only item?

10. browse_code — apps/web/src/components/settings/ConnectionsSettings.tsx

💭 The "wsl-backend" catalog entry is only gated by desktopOnly, but it's actually Windows-specific and admin-scoped, so on macOS/Linux desktop the search still surfaces a dead "WSL backend" result linking to a nonexistent settings anchor—precisely the bug desktopOnly was meant to prevent. Now I'm checking whether this falls within the UI consistency check's defined scope. Since this is a concrete behavioral regression introduced by the changed lines in settingsSearch.ts, I think it warrants reporting. I'm weighing possible fixes: adding a stricter platform gate to the catalog, excluding the WSL row from indexing entirely, or pointing its targetId to a stable parent section instead of a nonexistent anchor. I'm checking whether clicking this dead search result actually breaks anything — worst case the hash stays unconsumed in the URL since no target renders to trigger onTargetHandled, which is a minor but real annoyance rather than a crash. I also verify the retry-recovery and Windows-switch rows share ids safely since their render branches are mutually exclusive, and I check that the test expectations align with how isElectron resolves to false under jsdom. I'm also noticing that the catalog's claimed "result order matching panel order" doesn't quite hold — wsl-backend is listed after remote-environments in the catalog, but visually the WSL row sits above the Remote Environments section in the panel. Still, no query seems to match both entries simultaneously, so this ordering mismatch has no actual observable effect on search results today, just a minor documentation inconsistency worth flagging. Let me verify this actually breaks something: on macOS desktop, the WSL state loads as unavailable and disabled, so the row renders as null, yet the search catalog still surfaces "WSL backend" for desktop since it only checks isElectron rather than the OS. Clicking that result navigates to an anchor that doesn't exist on the page, producing a dead result on every non-Windows desktop install—that's a real, concrete defect worth flagging, with the fix being to gate the catalog entry on the actual platform rather than just Electron. Since the fix spans both the catalog item and the filter logic in separate parts of settingsSearch.ts, a clean single-hunk diff isn't really possible—I'll describe the fix in words rather than force an incomplete diff, anchoring my comment near the newly added item lines around 262-267 in that file. I don't think I need to flag the test since it correctly gates on desktopOnly. This looks like a real regression—the search result would be dead on macOS/Linux desktop builds, which undermines what the PR is trying to fix—so I'll mark the review as a failure with this one finding and post it.

11. modify_pr — One finding: the new wsl-backend search entry is only gated by desktopOnly, but the row it anchors to is Windows-only, so macOS/Linux desktop builds get a search result that lands on a missing anchor. Details inline.


Agent Credits: 322 credits

Token usage: 90 uncached input · 1,782,374 cache-read input · 226,687 cache-write input · 30,202 output
Agent Credits may also include non-token charges from external tools such as web research.