feat(v0.20.1): 한국어 morphological tokenizer (V009) + N-gram supplement + eager backfill #191
Reference in New Issue
Block a user
Delete Branch "feat/korean-morphological-tokenizer"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Summary
v0.20.x C task — 한국어 형태소 (morphological) tokenizer + N-gram supplement + v0.20.1 patch release. Bug #8 (한국어 2자 query 0-hit) 의 functional closure.
24 commit (17 implementation + 6 follow-up + 1 spec/plan artifact). spec → plan → subagent-driven-development → PR-level review (opus) → dogfood evidence 의 full workflow.
핵심 변경
chunks_ftstokenizer 가 trigram → unicode61. 한국어 chunk 의 lindera ko-dic 형태소 분해 결과를 별 columntokenized_korean_text에 pre-fill. CASE expression trigger 가 raw text 앞에 prepend 해 단일 query 로 두 column 매칭.대한민국,한국정부등) 을 단일 token 으로 저장하는 정책 한계 해소. 한글 morpheme 길이 ≥ 3 일 때 sliding window 2-gram 추가 emit.대한민국→[대한민국, 대한, 한민, 민국].App::open_with_config의 hook 이 NULLtokenized_korean_textchunks 를 자동으로 lindera tokenize → UPDATE. 1000-row batch transaction + progress callback. KnowledgeBase 1781 doc / 9050 chunk 실측 26.6초 (~3 ms/chunk).'token'query 가'tokenizer'도 hit 하던 부산물 사라짐. V002 (whole-token only) 로 환원 — spec §3 Non-Goals Path A 의 의도된 회귀. vector/hybrid mode 권장.short_query_hint()retired: helper 함수 제거.SearchResponse.hintfield 는 wire schema shape 보존 위해 struct 유지 + 항상None.lex:{chunker_version}:fts5-v009-korean-morphological. eval runner 의 config_snapshot 갱신.Dogfood evidence
'한국'2자 (KnowledgeBase 1781 doc)'한국어'3자'대한','한민','민국'(fixture)'서울특별시'compound[서울, 특별시]'token'(영어, KB)'tokenizer'(KB 에 부재)Snippet evidence (lindera + N-gram window 작동):
testdata/coding-md-corpus/security/security-310-item.md→"¶ 문서 를 한국어 한국 국어 로 다시 정리 하 기"—한국어morpheme 의 N-gram supplement 가[한국, 국어]를 추가 emit.Workflow
Test status
cargo test --workspace --no-fail-fast -j 1→ exit 0 (V009 의 의도된 회귀 — V007 trigram-specific test 3 + corpus_revision baseline test + 10 chunk snapshot — 모두 update 완료).cargo clippy --workspace --all-targets -j 4 -- -D warnings→ 0 warning.cargo fmt --all --check→ clean.kebab schema --json→kebab_version=0.20.1,corpus_revision=2(V004 seed 0 + V009 +1 + ingest +1).Breaking changes
kebab.sqlite+20-30% (Korean-heavy), binary +120MB (lindera ko-dic embedded dict).Migration cascade
lexical_index_versionlex:{chunker}lex:{chunker}:fts5-v009-korean-morphologicalcorpus_revisionTest plan (사용자 dogfood)
git fetch && git checkout v0.20.1 && cargo build --release -p kebab-cli후 새 binary 로 첫 호출 시 backfill progress log 확인.kebab search '한국'/'서울'/'지하철'→ 한국어 corpus 가 있는 KB 에서 hit 확인.kebab search 'tokenizer'→ whole-token 매칭 회귀 확인.kebab schema --json | jq '.index_versions.lexical'→fts5-v009-korean-morphologicalsuffix 포함 확인.cargo test --workspace -j 1→ 모두 pass.docs/release-notes/v0.20.1-draft.md) 의 evidence 검토.References
docs/superpowers/specs/2026-05-28-v0.20.x-korean-morphological-tokenizer-spec.md(668 line, ACCEPT)docs/superpowers/plans/2026-05-28-v0.20.x-korean-morphological-tokenizer-plan.md(750 line, ACCEPT + 9 MP)tasks/HOTFIXES.md2026-05-28 entrydocs/release-notes/v0.20.1-draft.md/build/cache/dogfood/(machine-local, per CLAUDE.md §Dogfood trigger)🤖 Generated with Claude Code
S3 spec compliance reviewer (sonnet) 가 2 blocker 발견: 1. crates/kebab-store-sqlite/src/documents.rs: get_chunk SELECT 가 tokenized_korean_text column 을 미조회 → DB 의 값이 read 시 유실. SELECT column list + row → Chunk 변환 시 row.get 인덱스 추가. ChunkRow struct + chunk_row_from_sql + get_chunk Chunk 생성 cascade. 2. crates/kebab-chunk/src/code_*_ast_v1.rs (9 file): make_chunk 가 tokenized_korean_text: None 하드코딩 → 한국어 주석을 가진 코드 파일이 FTS hit 안 됨. tier2_shared 와 동일 패턴으로 tokenize_korean_morphological(text) 호출 cascade. 이 commit 은 S3 의 rework — amend 아닌 별 commit (S3 boundary 유지). spec §6.2 invariant ("모든 chunker 가 chunk emit 직전에 tokenize 호출") 충족. Spec: docs/superpowers/specs/2026-05-28-v0.20.x-korean-morphological-tokenizer-spec.md §6.2 Plan: docs/superpowers/plans/2026-05-28-v0.20.x-korean-morphological-tokenizer-plan.md (S3 rework) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>V009 unicode61 + 형태소 tokenizer 환경에서 2-char 한국어 query 가 hit 가능해졌으므로 V007 시기의 "3자 이상 권장" hint 가 obsolete. SearchResponse.hint field 는 wire schema 보존 위해 struct 에 유지 + 항상 None. - kebab-app/src/app.rs: short_query_hint 함수 + doc-comment 삭제. 2 호출 site 가 hint = None 으로 정리. - kebab-app/src/lib.rs: re-export 에서 short_query_hint 제거. - kebab-tui/{app.rs,search.rs,run.rs}: short_query_hint field + 4 호출 cascade 제거. - kebab-cli/tests/wire_search_response.rs: search_plain_emits_short_query_hint_to_stderr test 삭제. search_json_emits_hint_field_for_short_query → search_json_hint_absent_for_short_query_v009 으로 교체 (hint 항상 None 검증). - kebab-search/src/lexical.rs::build_match_string: V007 의 trigram multi-token OR-combine 분기는 V009 환경에서 redundant 하나 보존 (future 확장성) — doc-comment 1 줄 추가. Wire schema shape 변경 없음 (search_response.schema.json:33 의 hint field 보존, struct 에 None 으로 항상 셋팅). Spec: docs/superpowers/specs/2026-05-28-v0.20.x-korean-morphological-tokenizer-spec.md §7.2, §7.3, §11.3 Plan: docs/superpowers/plans/2026-05-28-v0.20.x-korean-morphological-tokenizer-plan.md (S5) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>V009 의 FTS5 tokenizer 가 trigram → unicode61 + 한국어 형태소 분해 column 로 갱신됨. lexical_index_version 의 format 에 `fts5-v009-korean-morphological` suffix 추가하여 V007 baseline 과 구별. eval runner 의 config_snapshot 및 search cache 무효화에 자동 picks up. 기존 format: lex:{chunker_version} 신규 format: lex:{chunker_version}:fts5-v009-korean-morphological Wire schema shape 변경 없음 (SearchHit.index_version 의 string content 만 변화). lexical_index_version_is_returned_unchanged test 는 IndexVersion 의 임의 string 을 사용해 unchanged. Spec: docs/superpowers/specs/2026-05-28-v0.20.x-korean-morphological-tokenizer-spec.md §11.1, §11.3 Plan: docs/superpowers/plans/2026-05-28-v0.20.x-korean-morphological-tokenizer-plan.md (S6)신규 4 test 추가: - crates/kebab-store-sqlite/tests/fts.rs: - fts_v009_korean_morphological_2char_query_hits: tokenized_korean_text column 이 채워진 chunk 의 '한국' 2-char query hit. - fts_v009_english_whole_token_only: V007 trigram substring 매칭 회귀 (Path A) — 'token' query 가 'tokenizer' chunk 에서 0-hit. - crates/kebab-app/tests/search_korean.rs: - korean_morphological_2char_query_lexical_mode: end-to-end 한국어 wiki fixture ingest → '한국' / '서울' query hit. - korean_morphological_mixed_english_korean_query: 'Rust' English whole-token + '최적화' Korean morpheme hit. crates/kebab-search/src/lexical.rs: - build_match_string() 의 MIN_TRIGRAM_CHARS(3) → MIN_QUERY_CHARS(2). V009 unicode61 은 최소 token 길이 제한 없어 2자 한국어 morpheme query 가 통과되어야 함. 1자 단독은 여전히 필터. - 관련 unit test 2개 V009 동작으로 갱신. fixture text 는 lindera ko-dic 의 실제 segmentation 동작에 의존 (spec Appendix B prior-knowledge 예측). 실측 시 fixture 조정 가능. Spec: docs/superpowers/specs/2026-05-28-v0.20.x-korean-morphological-tokenizer-spec.md §9.1, §9.2 Plan: docs/superpowers/plans/2026-05-28-v0.20.x-korean-morphological-tokenizer-plan.md (S7) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>opus PR-level final review (Approved with notes) 의 4 minor finding mechanical 정정: 1. README.md — `kebab search` row 의 영어 substring 매칭 표현이 V007 시절 그대로였음. V009 의 whole-token 회귀 (substring → V002 동작) 를 정직히 명시 + vector/hybrid mode 권장 안내. 2. tasks/HOTFIXES.md — 2026-05-28 entry 의 file path 정정. lexical.rs 는 lindera 호출자가 아니라 build_match_string 의 MIN_QUERY_CHARS 3→2 갱신만; lindera helper 의 실제 owner 는 kebab-chunk/src/lib.rs. ingest.rs 는 본 PR scope 외, eager backfill hook 위치는 kebab-app/ src/app.rs::App::open_with_config. 3. docs/wire-schema/v1/search_response.schema.json — `hint` field description 이 V007 trigram 3-char minimum 시절 advisory 시그니처 그대로. v0.20.1 에서 helper retired + always-omit 사실 명시 (forward-compat 차원에서 field 만 schema 에 보존). 4. integrations/claude-code/kebab/SKILL.md — `hint` field 설명의 self-contradiction ("present only with trigram in edge cases" vs "Korean 2-char now supported") 해소. retired + reuse 가능 명시. PR-level reviewer recommendation: "Merge as-is — block 사유 아님 (모든 finding minor)". 본 commit 은 reviewer 의 옵션 1 (별 docs hotfix commit) 채택. Spec: docs/superpowers/specs/2026-05-28-v0.20.x-korean-morphological-tokenizer-spec.md Plan: docs/superpowers/plans/2026-05-28-v0.20.x-korean-morphological-tokenizer-plan.md (PR-level finding follow-up)