Skip to content

prompt-hook: high-frequency ambiguous keywords (pt "como") escalate to HIGH on non-structural prompts — measured follow-up to #1140 #1654

Description

@AndreLFSMartins

Summary

Follow-up to #1140 (and the #994#1126 line that produced the current list).

#1140 closed as working-as-designed with the note: "with #1143 fixed the gate telemetry can now actually tell us if that judgment is wrong in practice (a Korean-locale anomaly in the high-tier share would show up). If that happens, this is the issue we'll reopen."

This is that data point, for Portuguese rather than Korean, measured against a real prompt corpus.

This is a different failure class from #1140. #1140 was a boundary problem in STRUCTURAL_UNSEGMENTED (unsegmented scripts, no word separator). STRUCTURAL_WORDS has correct boundaries — NOT_WORD_BEFORE/NOT_WORD_AFTER work exactly as intended here. The problem is lexical frequency: como is not only Portuguese "how", it is also the ordinary comparative conjunction ("do it like we agreed"), the causal conjunction ("since it didn't work…"), and the first-person present of comer, "to eat". Its English counterpart how is almost always interrogative; como is not. Same for German wie (interrogative and comparative: "so groß wie").

The gate has no way to tell those apart, and HIGH skips the index check that code tokens go through — so a matched keyword injects the full explore payload unconditionally.

Repro

codegraph v1.6.0, darwin-arm64, indexed repo (431 files / 9,033 nodes), .codegraph/ healthy.

run() {
  printf '{"session_id":"repro","transcript_path":"/tmp/x","cwd":"%s","permission_mode":"default","hook_event_name":"UserPromptSubmit","prompt":"%s"}' \
    "$PWD" "$1" | codegraph prompt-hook | wc -c
}
Prompt Meaning Injected
onde fica a logica de decay? "where is the decay logic?" — legitimate 16,253
how does decay work? (EN control) legitimate 16,253
faz como a gente combinou ontem "do it like we agreed yesterday" 16,253
roda os testes como esta e me diz o resultado "run the tests as they are and tell me" 16,247
commita isso como fix, nao como feat "commit this as a fix, not as a feat" 16,261
eu como pizza toda sexta "I eat pizza every Friday" 16,267
run the tests and report back (EN control) non-structural 913

The last row is the point: an English non-structural prompt correctly stays at the low tier, while "I eat pizza every Friday" injects 16 KB. The payload is the same truncated explore in every case — it is not responsive to the prompt.

Measurement

Corpus: 2,841 human prompts under 400 chars from ~/.claude/projects/*/*.jsonl (my own Claude Code history; I write to the agent in Portuguese).

count share
Prompts analysed 2,841
Match the Portuguese entries (como, onde, fluxos?, caminhos?) → HIGH tier 625 22.0% of all prompts
…matching como alone 196 6.9%
Of the 625 firings, those containing no identifier-shaped token at all (no snake_case, no CamelCase, no .py/.ts, no fn(), no /path/) 190 30.4% of firings

That last row is deliberately a mechanical criterion, not a judgement about which prompts are "really" structural — those 190 are prompts where the gate escalated to HIGH on the language keyword alone, with nothing else in the prompt pointing at code. At ~16 KB / ~4k tokens per firing that is ~760k tokens.

What I am not claiming: that all 190 are false positives. A structural question can legitimately lack an identifier ("onde fica a lógica de decay?" is in that set). I tried scoring "is this really a structural question" semantically and got results ranging from 4% to 46% depending on how generous the filter was — which is exactly why I'm reporting only the mechanical number. Treat 30.4% as "fired on the keyword with no corroborating signal", not as a false-positive rate.

Possible directions — genuinely open, I don't have a fix I trust

  1. Route high-frequency ambiguous keywords through the same index check code tokens get, instead of straight to HIGH. como/wie would still fire when the prompt also contains something the index recognises. Costs a lookup on a subset of prompts; the failure mode it reintroduces is prompt-hook gate regex skips non-English (Chinese) prompts — UserPromptSubmit never injects context #994's (silent no-op) for prompts that are structural but name nothing indexed.
  2. A second tier for this class — "ambiguous interrogative": enough to reach MEDIUM, not HIGH. Keeps the non-English fix from prompt-hook gate still skips non-English Latin-script prompts (French) â�� follow-up to #994/#1004 #1126 while capping the blast radius.
  3. Require a second signal for this subset only (a second structural word, or a ?). Cheap; I have not measured its miss rate, and per hasStructuralKeyword: STRUCTURAL_UNSEGMENTED matches CJK/Korean keywords as unbounded substrings — real homograph/compound-word false positives; tried Intl.Segmenter, it doesn't fix it #1140 the denylist-shaped fixes in this area have a habit of trading a rare false positive for a plausible false negative.

I'd lean to (1) since it reuses machinery already in the gate, but I have not measured what it would break, and #1140 is a good reminder that the obvious fix in this area can fail on inspection.

Not verified

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions