Match a coworker's connector by name, not as a substring of another word - #293
Open
kevin9327 wants to merge 1 commit into
Open
Match a coworker's connector by name, not as a substring of another word#293kevin9327 wants to merge 1 commit into
kevin9327 wants to merge 1 commit into
Conversation
When the intent router falls back and exactly one coworker can reach a system the message names, the message is routed to that coworker. onlyCoworkerReaching matched the system id with `haystack.includes(...)`, a bare substring test. So "how do I deal with a slacker" matched the `slack` connector, and "escribe un cuento sobre una jirafa" — a giraffe — matched `jira`. A message that named neither system was read as naming one, and because a fallback pins the channel to one coworker for the life of the thread, it misrouted the whole conversation to a specialist that could not answer it. Every untagged message takes this path when the router endpoint is down, which is the case that surfaced it. The id is now matched on word boundaries: bounded by a non-alphanumeric character or an edge of the message, with the id's own characters taken literally. A system named on its own still routes to its holder, and one buried inside a longer word does not. Separator loosening is unchanged, so google-drive still answers to "google drive". Word boundaries do not settle a name that genuinely appears as its own word for another reason (a `linear` connector and "linear regression"); that is a limit of a lexical reach hint, not this substring defect, and is left as is. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
kevin9327
requested review from
MikeRyanDev,
davidmckayv,
guidovizoso and
tylerslaton
as code owners
August 30, 2026 06:15
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
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
注册 for free
to join this conversation on GitHub.
Already have an account?
登录 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.
What this changes
When the intent router falls back — it is unreachable, its answer does not parse, it names nobody on the roster, or no specialist is a confident match — and exactly one coworker can reach a system the message names, the message is routed to that coworker instead of the default (
onlyCoworkerReaching,server/src/routing/classify.ts).The system id was matched against the message with
haystack.includes(...), a bare substring test. So a system id that appears inside a longer word was read as the message naming that system:slackconnectorjiraconnectorA message that named neither system was routed to that specialist — and because a fallback pins the channel to one coworker for the life of the thread, it misrouted the whole conversation to a Bot that could not answer it. Every untagged message takes the fallback path when the router endpoint is down, which is the state that surfaced it.
The fix matches the id on word boundaries: it has to sit bounded by a non-alphanumeric character or an edge of the message, with the id's own characters taken literally (so a custom server id with regex metacharacters is safe). Separator loosening is unchanged —
google-drivestill answers to "google drive" — and a system named on its own still routes to its holder.Reproduced before the fix (all now pass): "slacker" and "jirafa" both fell to the connector holders; after, both stay on the default, while "post this to slack" still routes to the Slack coworker.
A name that genuinely appears as its own word for another reason — a
linearconnector and "linear regression", anotionconnector and "no notion" — is a limit of using lexical presence as a reach hint, not this substring defect, and is left as is.Where it runs
onlyCoworkerReaching/messageNames/boundedare pure string functions with no state. They run inside the API's routing decision (server/src/app.tswirescreateIntentRouter), per message.Boundary and audit
undecidedreason is still recorded exactly as before; this only changes which coworker a reach fallback names.Changelog
Unreleased: "A message no longer routes to a specialist because a longer word contained a connector's name".Proof
Verified locally (bun 1.3.14):
bun test server/tests/routing-classify.test.ts— 27 pass / 0 fail, including the new cases: a system id inside an unrelated word ("slacker", "jirafa") is not a match and stays on the default; the same system named on its own still routes to its holder. Every pre-existing routing test (positive reach match, hyphen-as-space, two-holder default, confident-match-wins) still passes.cd server && bun run typecheck— clean.bunx biome format/bunx biome linton the changed source and test — clean.(Server integration tests that need Postgres fail locally with
Connection closed; that is the absent local DB, not this change. The routing suite is pure and needs none.)