Fix EQNotify tag matching: match at word start, not raw substring#266
Merged
Conversation
Batphone tag matching used raw substring containment, so short default tags
like `ct` and `kt` fired inside unrelated words ("ct" in "contact",
"protect"), producing alerts that looked unrelated to anything a user signed
up for.
Tags now match only when a word in the batphone *starts with* the tag. This
kills the mid-word false positives while preserving the intentional
abbreviation/prefix triggers the defaults rely on (`doze` -> "Dozekar",
`cazic` -> "Cazic-Thule", `dain` -> "Dain Frostreaver"). The one tradeoff is
that a tag no longer matches mid-word (`quake` no longer hits "earthquake");
add the fuller keyword if that's wanted.
Implemented with a left word-boundary regex over the lowercased content, with
the tag escaped for regex safety. Adds regression tests, including the
reported "ct"-in-"contact" case.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BWXRmPbtEz35wquwFd8Cu7
Complements the word-start matching change: `quake` no longer matches inside "earthquake", so add `earthquake` as a default alongside `quake` to cover both batphone phrasings. Applies to new registrations; existing subscribers can add it with `/eqnotify add-tag earthquake`. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BWXRmPbtEz35wquwFd8Cu7
ebm5025
added a commit
that referenced
this pull request
Jul 24, 2026
…mit (#267) The add-tag option description introduced in #266 was 108 characters, over Discord's 100-character cap for option descriptions. discord.js validates this only at command-registration time, so it passed tsc/tests but crashed the bot on boot ("ExpectedConstraintError: Invalid string length"). Shortened to 93 characters and noted the limit inline. Claude-Session: https://claude.ai/code/session_01BWXRmPbtEz35wquwFd8Cu7 Co-authored-by: Claude <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
A user received an EQNotify Telegram alert that felt unrelated to anything they'd signed up for. Root cause: tag matching used raw substring containment (
content.includes(tag)), and several default tags are short — notablyctandkt.ctmatches inside ordinary words like "contact", "protect", "select", so a batphone with any such word would trip thectdefault and fire an alert.(The empty-tags path was never the cause —
matchesTags([])correctly returnsfalse. New subscribers simply carry the 9 default tags.)Fix
Tags now match only when a word in the batphone starts with the tag (left word-boundary), instead of matching anywhere as a substring.
ctmatches "CT POP" but not "contact" / "protect".doze→ "Dozekar",cazic→ "Cazic-Thule",dain→ "Dain Frostreaver". (Whole-word-only matching would have regressed these.)quakeno longer hits "earthquake". Add the fuller keyword if that's wanted.Implemented with a left word-boundary regex over the lowercased content, with the tag escaped for regex safety (tags may contain punctuation like
vulak`aerr).Changes
matcher.ts:matchesTagsnow uses a(?<[a-z0-9])<tag>word-start match; addedescapeRegExp+ a documentedtagMatchesContenthelper.word-start (prefix) boundariesblock, including the reportedct-in-contactregression and thedoze→Dozekarabbreviation case (17 tests total, all passing)./eqnotify add-tagdescription and README explain the word-start rule and the default tag set.Testing
yarn tsc— clean.yarn test:ci(eqnotify matcher suite) — 17 tests pass.🤖 Generated with Claude Code
Generated by Claude Code