You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
A rematch that loses is charged as unmatched but still sets prevMatched, so the next letter gets an unearned +5: Score("EditItemManager","em") = 2 vs "EditItxmManager" = 12 #130
In Fuzzy.Contains, a copy of the current pattern letter that loses the rematch is charged as skipped by the losing-rematch else branch (FuzzySearch/Fuzzy.cs:295-301):
else{// A rematch that loses to the current best letter is skipped too, so charge it like one.score+=unmatchedLetterPenalty;ChargeProvisional(firstLetterProvisional,refprovisionalCharges);}prevMatched=true;// line 303: still runs for the losing copy
Control then falls through to prevMatched = true, so the character that was just charged as unmatched is treated as the previous match. The next character then:
gets adjacentMatchBonus (+5) in ApplyBonuses;
is marked as continuing a run (ContinuesRun, ~lines 270 and 361-365);
through displacesRun (~line 269), blocks a later camelCase/separator copy from replacing it.
Changing one unmatched letter (e→x inside "Item") changes the score by 10. With the e present, the mid-word m of "Item" gets +5 for being "adjacent" to the losing e. It is then treated as continuing a run, so the camelCase M of "Manager" can't displace it.
Adding an unmatched a raises the score from 19 to 23.
The README defines the +5 as a "Match adjacent to the previous match". A brute-force enumeration of every alignment over random subjects drawn from abAB_x, with no doubled letters so #101 is excluded, found 642 of 157,532 matching cases where the returned score is higher than any alignment can score under the documented rules (e.g. Baxab/bab 18 vs max 13, b_xbAx_A/ba 19 vs max 14).
Identifiers commonly contain the pattern's letters next to each other inside words like "Item", "System" and "Element". When the first pattern letter matched earlier, those words make a camelCase hit (EditItemManager for "em") lose to a mid-word match, and the ranking flips on a change to letters that aren't matched at all.
Suggested fix
In the losing-rematch branch, treat the character as unmatched for bookkeeping too: set prevMatched = false (update prevLower/prevSeparator and the indices, then continue) instead of falling through to prevMatched = true. With this change applied to a scratch copy, all 116 existing tests pass and:
Priority: Medium. Scores can exceed any alignment the documented rules allow, and ranking flips on letters that aren't matched (camelCase hits lose to mid-word matches in common identifiers such as "Item" and "System"). It is a ranking-quality problem, not a crash or data issue.
Area / suggested assignment:FuzzySearch/Fuzzy.csContains, the losing-rematch branch and its prevMatched bookkeeping. The issue already describes a fix that keeps the 116 existing tests passing.
Activity
matt-edmondson commentedon Nov 2, 2026
Triage
FuzzySearch/Fuzzy.csContains, the losing-rematch branch and itsprevMatchedbookkeeping. The issue already describes a fix that keeps the 116 existing tests passing.dotnet packonmain(CompatibilitySuppressions), so it may need to land first for CI to pass.Generated by Claude Code