Pull Request Overview
- Opened on September 11, 2026
- Status Open
- Commit count 1 with first commit September 11, 2026
Total Delta
Open Days
Test Delta
How long has this pull request spent in each phase of its lifecycle?
| Fraction of total time | Business days | Phase |
|---|---|---|
|
|
0.0 days | Authoring 1 commit before pull request opened for review |
|
|
0.0 days | Awaiting first review |
|
|
5.0 days | Revising work with 0 commits in response to 1 review that left 2 comments |
Total time for pull request still awaiting merge: 5.0 business days
fix(settings-ui): reject empty normalized search queries
Summary of the Pull Request
Prevent Settings search from passing queries that normalize to empty or whitespace-only text into fuzzy matching, and make the shared matcher return its existing no-match result for whitespace-only queries.
PR Checklist
- [x] Communication: Scoped to the requested atomic Settings search-safety audit follow-up; submitted as a draft.
- [x] Tests: Added focused regression coverage; all 46 selected tests pass.
- [x] Localization: No new user-facing strings; normalization and existing localized search behavior are unchanged.
Issue closure, development/user documentation, and new-binary checklist items are N/A. No new projects, dependencies, binaries, or persisted settings changes.
Detailed Description of the Pull Request / Additional comments
Trigger: A query consisting of U+00A8 (spacing diaeresis) passes the initial whitespace check in src\settings-ui\Settings.UI\Services\SearchIndexService.cs. FormKD normalization decomposes it into U+0020 plus a combining mark; removing nonspacing marks leaves a single space. Previously, src\common\Common.Search\FuzzSearch\StringMatcher.cs checked only for null/empty input before trimming, then indexed the first element of an empty token array. With a populated search index, the resulting IndexOutOfRangeException can propagate through Parallel.ForEach to the live search handler, which catches cancellation only. This is a source/unit-test finding, not a claim of a reproduced live application crash.
The Settings service now returns no results after normalization when no searchable text remains. The shared matcher rejects null/empty/whitespace queries before its per-start-index matching loop, preventing empty trimmed/tokenized input from reaching the indexed access. Both use existing no-match behavior rather than adding an exception catch.
Shared-caller risk: Common.Search is also used by Shortcut Guide and the Command Palette PowerToys extension. Their existing blank-query handling remains unchanged, as do the matching algorithm, separators, scoring, highlighting, and case options for nonempty queries. No public API signature changes. NormalizeString becomes internal solely for direct coverage through the existing Settings test friend assembly.
Tests are in the existing src\settings-ui\Settings.UI.UnitTests\Search\StringMatcherTests.cs and src\settings-ui\Settings.UI.UnitTests\Search\SearchIndexServiceTests.cs; there is no standalone Common.Search test project on current main. The service fixture supplies a nonempty in-memory index, restores it afterward, and does not load Settings resources or change user settings.
This PR deliberately excludes expander-result filtering and prebuilt search-index generation/embedding changes. It does not auto-close the different search-crash reports #41817 or #47118.
Validation Steps Performed
- Ran the repository first-build prerequisite
tools\build\build-essentials.cmd -Platform x64 -Configuration Releaseafter the fresh worktree reported missing NuGet assets; restore and essentials completed successfully. - Built
Settings.UI.UnitTestsin Release x64 usingtools\build\build.ps1with the worktreeSolutionDir; exit code 0. - Ran the existing Microsoft.Testing.Platform runner with
--filter "FullyQualifiedName~Settings.UI.UnitTests.Search" --minimum-expected-tests 46 --report-trx: 46 passed, 0 failed, 0 skipped. - Covered null/empty/ASCII whitespace, Unicode spaces, U+00A8 compatibility normalization, combining-only queries, both Search overloads with a nonempty index, both case options, ordinary/padded/multiword queries, unchanged scores/highlights, exact-match ranking, and accented/fullwidth normalization.
- Did not launch or modify the installed/running PowerToys instance or user settings.
Comments Threads Pending Resolution
Resolved Comment Threads
No resolved comments have been left on this PR.
### π’ Approval recommended
The focused guards address the failure path without changing nonempty-query behavior, with comprehensive regression coverage.
Pull request overview
Prevents normalized blank Settings queries from reaching fuzzy matching and hardens the shared matcher against whitespace-only input.
**Changes:**
- Rejects empty normalized queries before searching.
- Adds shared matcher validation for whitespace-only queries.
- Adds regression tests for normalization, scoring, highlighting, and case handling.
File summaries
| File | Description |
| ---- | ----------- |
| `SearchIndexService.cs` | Rejects blank normalized queries and exposes normalization internally for tests. |
| `StringMatcher.cs` | Returns no match for whitespace-only queries. |
| `StringMatcherTests.cs` | Covers matcher edge cases and unchanged matching behavior. |
| `SearchIndexServiceTests.cs` | Covers normalization and search regressions. |
Review details
- **Files reviewed:** 4/4 changed files
- **Comments generated:** 0
- **Review effort level:** Balanced
---
π‘ Add a `code-review` agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.