feat(core): make the FTS5 tokenizer configurable (CJK recall) - #14
Open
Cyb3rN8 wants to merge 1 commit into
Open
feat(core): make the FTS5 tokenizer configurable (CJK recall)#14Cyb3rN8 wants to merge 1 commit into
Cyb3rN8 wants to merge 1 commit into
Conversation
unicode61 indexes an unbroken run of CJK as a single token, so Chinese, Japanese, and Korean transcripts only match when a phrase happens to be delimited by punctuation or ASCII, and ASCII identifiers glued to CJK text are missed outright. OBELISK_FTS_TOKENIZER selects any built-in FTS5 tokenizer. Left unset, nothing changes. Set, both FTS tables are rewritten from their own sqlite_master definition and repopulated from the content tables, so schema.sql remains the single source of truth for the columns and the triggers are untouched. The build debounce yields to a pending switch, otherwise a newly configured tokenizer would sit silently inactive until the next unthrottled build. Refs tommy0103#9 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This was referenced Aug 19, 2026
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
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in 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.
Closes #9 — but as an opt-in rather than a default change, since switching every user to
trigramwould be a regression for Latin-script transcripts.Problem
messages_ftsis created without atokenizeoption (packages/core/src/schema.sql:37), so FTS5 falls back tounicode61, which indexes an unbroken run of CJK as one token. The repro from #9:One correction to the issue, from measuring a real index rather than the minimal repro: CJK phrases are not uniformly zero-hit. A phrase matches when it happens to be delimited by punctuation or ASCII, so the real failure mode is silent partial recall, which is worse than an obvious zero. Against 379,877 messages (2.5 GB of transcripts), with
LIKEas ground truth:LIKEunicode61trigramitgc(glued to CJK)Approach
OBELISK_FTS_TOKENIZERselects any built-in FTS5 tokenizer. Unset — the default — nothing changes at all.schema.sqlis deliberately untouched. Because it isCREATE VIRTUAL TABLE IF NOT EXISTS, an existing FTS table keeps its original tokenizer forever, so switching means dropping and repopulating. The migration rewrites thetokenizeclause of the table's ownsqlite_masterdefinition instead of restating the columns, soschema.sqlstays the single source of truth and this keeps working if the FTS columns ever change. Triggers live on the content tables and survive the drop.It runs alongside
migrateCoreSchemaColumnsat all three call sites (coreopenDb, appmigrateDb, appinstallSchema), so the CLI and the desktop app converge on the same tokenizer.Two details worth review:
daemon_activestill wins, since the app runs the same migration itself.schema.sqlpass recreates the table and the migration runs again. Wrapping it would add a long write transaction for no additional safety.The env value is interpolated into DDL, so it is whitelisted against
^(unicode61|ascii|porter|trigram)( [A-Za-z0-9_=]+)*$and throws on anything else.Trade-offs (measured, not estimated)
On the same 379,877-message index:
unicode61trigrammessages_ftsinverted indexThe inverted index grows 5.4x, but only +15.7% of the database, since
messages.textis 30 MB of an 817 MB file dominated bytool_results.The real cost is the 3-character floor:
trigramcannot match a shorter query and returns zero without an error, which is a sharp edge for 2-character CJK words and forok/id-style ASCII. That is precisely why this is opt-in. It is documented in the README next to the setting, pointing atsql()+LIKEfor short queries.Verification
tests/fts-tokenizer.test.mjs(10 tests): whitelist rejection, no-op when unset, both tables switching, rows written before the switch becoming searchable after the rebuild, insert/update/delete triggers still feeding the rebuilt table, idempotence, reversibility, the debounce interaction, and daemon precedence.typecheck,lint,build:core,build:cli: no regression. Pre-existing failures on my machine (better-sqlite3cannot build on Node 26) are identical with and without this change — I could not exercise the app runtime path locally, only typecheck it, so that call site deserves a second look.HOME: default build staysunicode61; setting the variable migrates both tables and every query above goes from partial to exact agreement withLIKE; switching back tounicode61and forward totrigramagain both work, the second one inside the debounce window.Not included
The skill still tells agents to translate the request into English topic terms first, which is the right default for
unicode61but leaves recall on the table oncetrigramis on. Happy to follow up there, and on surfacing this in the app's settings UI, if the approach looks right.🤖 Generated with Claude Code