Skip to content

Match required glob tokens by any word under ByWordAll [patch] - #96

Merged
matt-edmondson merged 1 commit into
mainfrom
claude/textfilter-95-required-token-bywordall
Sep 23, 2026
Merged

matt-edmondson merged 1 commit into
mainfrom
claude/textfilter-95-required-token-bywordall

Conversation

@matt-edmondson

Copy link
Copy Markdown
Contributor

Fixes #95

DoesMatchGlob chose its required-token matcher from the match option:

Func<string, HashSet<string>, bool> requiredMatchFunc = textFilterMatchOptions is TextFilterMatchOptions.ByWordAny
    ? AnyTokenMatchesGlobFilter
    : AllTokensMatchGlobFilter;

Under ByWordAll that asks whether every word in the text matches the glob world, rather than whether world appears among them. So DoesMatchGlob("hello world", "hello* +world", ByWordAll) returned false — "hello" does not match world. Any text with more than one word fails, which makes +token unusable in that mode.

The fix

Required tokens now always use AnyTokenMatchesGlobFilter, as the issue suggests, and the ByWordAll branch is gone.

The asymmetry the issue points at is the argument for it: excluded tokens, six lines above, have always used AnyTokenMatchesGlobFilter under every match option. A required token and an excluded token ask the same question — does this token appear among the text's words — and only differ in what they do with the answer. There was never a reason for one to vary by match option while the other did not, which is why this reads as a copy/paste slip rather than a decision. A comment at the call site now says so, since "always Any" is otherwise the kind of line a later reader would try to make symmetric with the optional-token branch just above it.

The match option still does its job for the optional tokens, whose Any/All branch is untouched: ByWordAll means the text must match all of the optional tokens, not every word must match each required token.

Tests

Three cases in TextFilterTests, all under ByWordAll, which the issue notes had no +token coverage at all — every existing required-token test passes ByWordAny.

test asserts
DoesMatchGlobWithRequiredTokenByWordAllReturnsTrue the issue's acceptance criterion: "hello world" against "hello* +world" is true
DoesMatchGlobWithAllRequiredTokensByWordAllReturnsTrue two required tokens and no optional token, so the required branch is the only thing under test
DoesMatchGlobWithMissingRequiredTokenByWordAllReturnsFalse a genuinely absent required token still returns false — the fix widens what matches, and this is what stops it widening to everything

Confirmed the tests depend on the change by substituting the original requiredMatchFunc back in and re-running: 2 failed, 69 passed, both as assertion failures on the two positive cases.

The third passes either way, by design — +missing matches no word, so Any and All agree. It is kept as the regression guard for the direction this change could have broken, and is not evidence for the fix.

Full suite green on the fix: 71 total, 0 failed (68 before, 3 added). Release build clean, zero warnings.

Not covered

AllTokensMatchGlobFilter is public API and keeps its own tests; this only stops DoesMatchGlob reaching for it in a place where it answered the wrong question. DoesMatchRegex has no token types at all, so its Any/All branch is a different thing that happens to look similar, and is untouched.

🤖 Generated with Claude Code

https://claude.ai/code/session_01UscjStBJdW3uHm5NR289DX


Generated by Claude Code

DoesMatchGlob picked AllTokensMatchGlobFilter for required tokens
whenever the match option was not ByWordAny, so a "+world" token asked
whether *every* word in the text matched the glob "world" rather than
whether "world" appeared among them. Any multi-word text failed, making
+token filters unusable under ByWordAll.

Required tokens now always use AnyTokenMatchesGlobFilter, matching the
excluded-token branch a few lines above, which asks the same question and
never varied by match option.

Fixes #95

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UscjStBJdW3uHm5NR289DX
@sonarqubecloud

Copy link
Copy Markdown

@matt-edmondson
matt-edmondson merged commit 7d2191b into main Sep 23, 2026
12 checks passed
@matt-edmondson
matt-edmondson deleted the claude/textfilter-95-required-token-bywordall branch September 23, 2026 00:01
matt-edmondson pushed a commit that referenced this pull request Sep 23, 2026
PR #96 landed after this branch was cut and rewrote the same
requiredMatchFunc selection in DoesMatchGlob that the method-group-to-
lambda change here touches, leaving the PR conflicted.

Resolved as the PR described: keep #96's always-Any choice for required
tokens, and retain the captured caseSensitivity argument so the required
call site still honours the sensitivity.

Both sides' tests survive the resolution: 84 pass, 0 fail (this branch's
79 plus #96's 5). Restoring this branch's side of the hunk fails 2 of
#96's ByWordAll required-token tests, which is what pins the choice.
Release build clean across all five TFMs, 0 warnings.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017wK8pxTxpgg3R2m3siPY3Y
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Required glob tokens (+token) are matched with the wrong function under ByWordAll, making them effectively unusable

2 participants