Skip to content

Add opt-in Japanese query tokenization - #2958

Open
fujimogn wants to merge 2 commits into
Graphify-Labs:v8from
fujimogn:worktree-graphify-janome-upstream
Open

Add opt-in Japanese query tokenization#2958
fujimogn wants to merge 2 commits into
Graphify-Labs:v8from
fujimogn:worktree-graphify-janome-upstream

Conversation

@fujimogn

@fujimogn fujimogn commented Aug 23, 2026

Copy link
Copy Markdown

Summary

Japanese text commonly omits whitespace between words, which makes the existing query tokenizer less effective for Japanese-language questions. This change adds an explicit, opt-in Japanese tokenizer powered by Janome.

  • Add a japanese optional dependency extra and include it in the all extra.
  • Add --tokenizer janome_content to the CLI.
  • Add the corresponding tokenizer option to the MCP query_graph tool.
  • Extract Japanese nouns, verbs, adjectives, and adverbs as query terms.
  • Keep the existing baseline tokenizer as the default, so existing installations and retrieval behavior remain unchanged unless the new option is selected.

For Japanese-speaking users, this improves term-level matching for queries without spaces and can reduce missed relevant graph nodes in Japanese code and documentation. The opt-in design keeps retrieval behavior stable for existing corpora because tokenization can affect search results.

Validation

  • uv run --frozen --group dev --extra japanese pytest -q tests/test_serve.py tests/test_cli_export.py — 198 passed
  • uv run --frozen --group dev --extra japanese ruff check graphify/serve.py graphify/cli.py graphify/__main__.py tests/test_serve.py tests/test_cli_export.py — passed
  • uv sync --all-extras --frozen && uv run --frozen pytest tests/ -q --tb=short — 4883 passed, 11 skipped, and 4 environment-dependent failures in this workspace (test_detect, test_export, test_extract, and test_hooks); none involve the changed tokenizer paths

@graphify-labs graphify-labs Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Graphify reviewed this change.

Looks safe to merge — no coupling regressions and no blocking issues, checked against the code graph (not a self-assessment).

Formal verification. 3 change(s) tested, no difference found (not proven).


Graphify review — findings

Adds an opt-in janome_content query tokenizer for Japanese content-word segmentation via the optional japanese/Janome extra, wiring it through _query_terms/_query_graph_text, the graphify query --tokenizer CLI flag, and the MCP query_graph tool schema. Raises clear ImportError/ValueError when Janome is missing or an unsupported tokenizer name is passed, with the CLI reporting these as errors and exiting non-zero. Defaults everywhere remain baseline, preserving existing behavior.

No blocking issues surfaced. 4 lower-confidence candidates did not survive cross-model review.

Analysis details — impact, health, verification

Impact & health

Graphify review

Impact — 755 functions depend on the 497 functions this change touches.

Health — this change adds coupling hotspots:

  • new: dispatch_command() — 2 callers, 119 callees
  • new: _make_graph() — 34 callers, 6 callees
  • new: _query_graph_text() — 20 callers, 9 callees
  • new: _query_terms() — 24 callers, 4 callees
  • new: _score_query() — 15 callers, 5 callees
  • new: run_benchmark() — 16 callers, 3 callees
  • new: _stale_graph_sources() — 7 callers, 6 callees
  • new: _build_server() — 2 callers, 16 callees
  • …and 12 more — each is listed as a finding

Verification — 755 functions in the blast radius were not formally verified this run (proofs are advisory here).

Gate & verification

graphify gate

PASS — objectively clean (no health regressions, tests not run — proofs not run this pass (advisory)). Grounded, not self-assessed.

Advisory (not blocking):

  • verification_scope: 755 function(s) in the blast radius were not formally verified this run

Formal verification

Could not verify: Could not verify dispatch\_command.

The verifier did not have enough to check dispatch\_command, so it is saying so rather than guessing. No false assurance is the whole point.

Guarantee: No guarantee either way, this is an honest abstention, not a pass.

Note: Reason: not verifiable: all 23 sampled inputs raised on both versions — the function never executed, so 'no divergence' would be vacuous (mostly SystemExit — names the real obstacle, not a sampling gap)

No difference found (not proven): No behavior difference found in \_run\_cli (not a proof).

The verifier ran both versions of \_run\_cli on many inputs and saw identical behavior every time. Strong evidence the change is safe, but evidence, not a proof.

Guarantee: Empirical: differential testing (both versions run on many generated inputs). A divergence on an untested input remains possible, so this is 'no counterexample found', not 'proven equivalent'.

Note: An input the sampler did not try could still differ.

Could not verify: Could not verify \_build\_server.

The verifier did not have enough to check \_build\_server, so it is saying so rather than guessing. No false assurance is the whole point.

Guarantee: No guarantee either way, this is an honest abstention, not a pass.

Note: Reason: not verifiable: all 23 sampled inputs raised on both versions — the function never executed, so 'no divergence' would be vacuous

No difference found (not proven): No behavior difference found in \_query\_graph\_text (not a proof).

The verifier ran both versions of \_query\_graph\_text on many inputs and saw identical behavior every time. Strong evidence the change is safe, but evidence, not a proof.

Guarantee: Empirical: differential testing (both versions run on many generated inputs). A divergence on an untested input remains possible, so this is 'no counterexample found', not 'proven equivalent'.

Note: An input the sampler did not try could still differ.

No difference found (not proven): No behavior difference found in \_query\_terms (not a proof).

The verifier ran both versions of \_query\_terms on many inputs and saw identical behavior every time. Strong evidence the change is safe, but evidence, not a proof.

Guarantee: Empirical: differential testing (both versions run on many generated inputs). A divergence on an untested input remains possible, so this is 'no counterexample found', not 'proven equivalent'.

Note: An input the sampler did not try could still differ.

· 2 grounded finding(s) anchored inline below; 18 more finding(s) on lines outside this diff (see the check run).

Comment thread graphify/serve.py
_JANOME_TOKENIZER_LOCK = threading.Lock()


def _load_graph(graph_path: str) -> nx.Graph:

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Health regression_load_graph()

9 callers depend on it (afferent coupling).

Grounded coupling-delta finding (deterministic), not an LLM guess.

Comment thread graphify/serve.py
if _is_searchable(tok):
terms.append(tok)
content = [t for t in terms if t not in _QUERY_STOPWORDS]
def _query_terms(question: str, *, tokenizer: str = "baseline") -> list[str]:

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Health regression_query_terms()

24 callers depend on it (afferent coupling).

Grounded coupling-delta finding (deterministic), not an LLM guess.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant