SubstitutionGuard
Rejects matches whose prompts are identical except for one word.
The guard that does not need a vocabulary. EntityGuard catches a swapped name only when the name is capitalized, which is a convention rather than a fact about meaning — real traffic is full of "sales tax in oregon" against "sales tax in washington", where every other guard has nothing to say. Measured on prompts nobody tuned against, capitalization was carrying about a third of the entity catches; lowercase them and the protection disappears.
So this reads structure instead of spelling. If two prompts have the same content words in the same order and differ in exactly one position, one term was substituted for another, whatever it was and whatever case it was written in. postgres for mysql, ibuprofen for naproxen, .heic for .webp.
Three conditions keep it from eating real paraphrases:
Same length, same order. A paraphrase almost never preserves word order exactly while changing one word; it adds, drops or reorders. "How do I merge two hashes in Ruby?" against "How do I combine two hashes into one in Ruby?" differs in length and is left alone.
The differing words must be genuinely different. Text.isSameWord absorbs typos, spelling variants and inflections first, so organise/organize and raed/read are not a substitution.
Enough words to be sure. Below minTokens content words, a one-word difference is as likely to be a verb synonym — "define recursion" against "explain recursion" — as a substituted term.
Properties
Short stable identifier, surfaced in dev.kmemo.CacheLookup.Miss.detail.