extractUserRequest matches the trigger phrase mid-token, extracting the wrong text as the user's request
Type: bug (trigger/extraction mismatch)
Severity: low-medium
Area: src/utils/extract-user-request.ts
Effort: trivial
Summary
The trigger matcher and the request extractor disagree about what counts as
an occurrence of the trigger phrase.
checkContainsTrigger (src/github/validation/trigger.ts) only accepts the
phrase at a word boundary — preceded by start-of-text or whitespace and
followed by whitespace/punctuation/end:
const regex = new RegExp(
`(^|\\s)${escapeRegExp(triggerPhrase)}([\\s.,!?;:]|$)`,
"i",
);
But extractUserRequest (src/utils/extract-user-request.ts) takes the
first raw substring match:
const triggerIndex = commentBody
.toLowerCase()
.indexOf(triggerPhrase.toLowerCase());
An occurrence embedded inside a token — which the matcher correctly refuses
to treat as a trigger — therefore wins the extraction.
Failure scenario
Comment body:
Email security@claude.dev ASAP. @claude please review the auth module
checkContainsTrigger: security@claude.dev is rejected (preceded by
y), the second occurrence matches → the action runs.
extractUserRequest: indexOf finds @claude inside security@claude.dev
first → the "user's request" becomes
.dev ASAP. @claude please review the auth module.
The prompt then leads with wrong text; at best the model recovers, at worst
it acts on garbage. The same applies to any earlier mention of the phrase in
a URL, code span, or username-like token (@claude-bob, cc @claude/bot).
Suggested fix
Scan occurrences left to right and honor only the first one whose preceding
and following characters satisfy the same boundary semantics as the trigger
matcher, keeping the file's string-operations approach (no RegExp built from
the phrase). Happy to open a PR.
extractUserRequest matches the trigger phrase mid-token, extracting the wrong text as the user's request
Type: bug (trigger/extraction mismatch)
Severity: low-medium
Area:
src/utils/extract-user-request.tsEffort: trivial
Summary
The trigger matcher and the request extractor disagree about what counts as
an occurrence of the trigger phrase.
checkContainsTrigger(src/github/validation/trigger.ts) only accepts thephrase at a word boundary — preceded by start-of-text or whitespace and
followed by whitespace/punctuation/end:
But
extractUserRequest(src/utils/extract-user-request.ts) takes thefirst raw substring match:
An occurrence embedded inside a token — which the matcher correctly refuses
to treat as a trigger — therefore wins the extraction.
Failure scenario
Comment body:
checkContainsTrigger:security@claude.devis rejected (preceded byy), the second occurrence matches → the action runs.extractUserRequest:indexOffinds@claudeinsidesecurity@claude.devfirst → the "user's request" becomes
.dev ASAP. @claude please review the auth module.The prompt then leads with wrong text; at best the model recovers, at worst
it acts on garbage. The same applies to any earlier mention of the phrase in
a URL, code span, or username-like token (
@claude-bob,cc @claude/bot).Suggested fix
Scan occurrences left to right and honor only the first one whose preceding
and following characters satisfy the same boundary semantics as the trigger
matcher, keeping the file's string-operations approach (no RegExp built from
the phrase). Happy to open a PR.