fix(prompt-hook): bound the call/trace/affect/connect stems on the right so ordinary words can't fire the gate (#1138) (#1147)

The multilingual structural-question gate (#1134) matches stems as open
prefixes (left boundary only) so derived forms fire without enumeration.
Four English stems have common non-structural completions — callus,
calligraphy, Connecticut, connective, affectionate, Tracey — that
false-fired the HIGH (full-explore) tier. Those four now enumerate their
structural suffixes and re-assert the right boundary; callbacks/callable/
call sites are included so no structural form regresses. Also documents
the verified-unfixable Korean homograph class on the unsegmented table
(#1140): segmentation can't split 구조대 from 구조가, and a denylist would
break 구조대로.

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Colby Mchenry
2026-07-02 17:05:51 -05:00
committed by GitHub
co-authored by Claude Fable 5
parent 81cb59a86e
commit 713ab7af43
3 changed files with 51 additions and 3 deletions
+26
View File
@@ -232,6 +232,32 @@ describe('hasStructuralKeyword — Latin-script languages, Cyrillic, JA/KO (#112
expect(hasStructuralKeyword('water the flower')).toBe(false); // unchanged guarantee
});
it('bounded stems reject ordinary-English completions (#1138)', () => {
expect(hasStructuralKeyword('he has a callus on his palm')).toBe(false);
expect(hasStructuralKeyword('a lovely calligraphy font')).toBe(false);
expect(hasStructuralKeyword('Connecticut is a state')).toBe(false);
expect(hasStructuralKeyword('connective tissue damage')).toBe(false);
expect(hasStructuralKeyword('she is very affectionate')).toBe(false);
expect(hasStructuralKeyword('Tracey went home early')).toBe(false);
});
it('bounded stems keep every structural derived form (#1138)', () => {
// call
expect(hasStructuralKeyword('list the callers of parseToken')).toBe(true);
expect(hasStructuralKeyword('what callbacks fire on save')).toBe(true);
expect(hasStructuralKeyword('is submitOrder callable from the worker')).toBe(true);
expect(hasStructuralKeyword('find every call site of dispose')).toBe(true);
expect(hasStructuralKeyword('who called setupRouter')).toBe(true);
// trace ("tracing" is covered by the exact-word list — the e drops)
expect(hasStructuralKeyword('trace the request')).toBe(true);
expect(hasStructuralKeyword('we traced it to the cache layer')).toBe(true);
expect(hasStructuralKeyword('add tracing to the pipeline')).toBe(true);
// affect / connect
expect(hasStructuralKeyword('which modules are affected by this change')).toBe(true);
expect(hasStructuralKeyword('how do the connections get pooled')).toBe(true);
expect(hasStructuralKeyword('the connector registers itself at boot')).toBe(true);
});
it('non-structural prose stays a no-op in every covered language', () => {
expect(hasStructuralKeyword('corrige cette faute de frappe')).toBe(false); // FR "fix this typo"
expect(hasStructuralKeyword('arregla este error tipográfico')).toBe(false); // ES