Summary
The match index option include_original is accepted by the encrypt config and has no effect on the emitted bloom filter. Encrypting the same plaintext with include_original: true and include_original: false yields the same bloom bits — measured on 0.24 and 0.29, under both EQL v2 and v3. The bloom is trigram-only either way, and a value shorter than the tokenizer's token_length blooms to nothing under both settings.
Silently accepting dead config is what made a downstream bug plausible: a claim that include_original: true appends a whole-value token to the needle's bloom (so a substring contains can never match) propagated into a comment, docs, a changeset, and a "confirming" test whose fake built the extra token itself. It cost a bug report (cipherstash/stack#610) and a limitation callout in published docs. Nothing tied the fiction to ffi because ffi neither honours nor rejects the flag — it just ignores it.
Expected
One of:
- Honour it —
include_original: true actually adds the whole untokenized value as a term, so whole-value match works through the match index; or
- Reject it — error at
newClient/config-normalization time if include_original is set, so callers cannot depend on a no-op.
Either removes the ambiguity. Today the flag reads as meaningful and is not.
Reproduce
import { newClient, encrypt } from '@cipherstash/protect-ffi'
const cfgWith = (includeOriginal) => ({
v: 1,
tables: { t: { col: {
cast_as: 'text',
indexes: { match: {
tokenizer: { kind: 'ngram', token_length: 3 },
token_filters: [{ kind: 'downcase' }],
k: 6, m: 2048,
include_original: includeOriginal,
} },
} } },
})
const on = await encrypt(await newClient({ encryptConfig: cfgWith(true), eqlVersion: 3 }), { plaintext: 'ada@example.com', table: 't', column: 'col' })
const off = await encrypt(await newClient({ encryptConfig: cfgWith(false), eqlVersion: 3 }), { plaintext: 'ada@example.com', table: 't', column: 'col' })
// on.bf and off.bf carry the same bit SET (order is nondeterministic; sort before comparing).
Context
Debunked and worked around in cipherstash/stack (PR that retracts the substring fiction): the stack's v3 match domains now emit include_original: false — the value a substring-search domain wants if a future release ever honours the flag — and a live suite (match-bloom-live.test.ts) pins the current inert behaviour against real ffi as a change-detector, so if ffi starts honouring the flag, that test fails and flags the divergence.
Summary
The
matchindex optioninclude_originalis accepted by the encrypt config and has no effect on the emitted bloom filter. Encrypting the same plaintext withinclude_original: trueandinclude_original: falseyields the same bloom bits — measured on 0.24 and 0.29, under both EQL v2 and v3. The bloom is trigram-only either way, and a value shorter than the tokenizer'stoken_lengthblooms to nothing under both settings.Silently accepting dead config is what made a downstream bug plausible: a claim that
include_original: trueappends a whole-value token to the needle's bloom (so a substringcontainscan never match) propagated into a comment, docs, a changeset, and a "confirming" test whose fake built the extra token itself. It cost a bug report (cipherstash/stack#610) and a limitation callout in published docs. Nothing tied the fiction to ffi because ffi neither honours nor rejects the flag — it just ignores it.Expected
One of:
include_original: trueactually adds the whole untokenized value as a term, so whole-value match works through the match index; ornewClient/config-normalization time ifinclude_originalis set, so callers cannot depend on a no-op.Either removes the ambiguity. Today the flag reads as meaningful and is not.
Reproduce
Context
Debunked and worked around in cipherstash/stack (PR that retracts the substring fiction): the stack's v3 match domains now emit
include_original: false— the value a substring-search domain wants if a future release ever honours the flag — and a live suite (match-bloom-live.test.ts) pins the current inert behaviour against real ffi as a change-detector, so if ffi starts honouring the flag, that test fails and flags the divergence.