본 commit 은 v0.20.x C task (Bug #8 — 한국어 2자 query 0-hit) 의 4-stage workflow artifact 5 파일을 archive: - spec.md (668 line, status=accepted): Option A/B/C 비교 + lindera Path A (영어 substring 회귀 인정) 결정 + 12 section + 4 Appendix (B segmentation evidence, C cost evidence, D license evidence). - spec-critic-r1.md: 3 critical + 6 major finding (NEEDS_REWRITE). - spec-critic-r2.md: r1c rewrite 후 traceability matrix (ACCEPT). - plan.md (750 line, status=accepted): 11 step + dependencies + cost optimization routing + 9 closure micro-patches 적용. - plan-closure-r1.md: traceability matrix + 9 MP 의 origin. 이 artifact 들은 implementation 머지 후 frozen reference. 후속 deviation 은 tasks/HOTFIXES.md 가 source of truth. Workflow stage: 1. spec drafter (omc team writer, opus) 2. spec critic R1 (omc team critic, opus) — NEEDS_REWRITE 3. spec rewriter r1c (omc team writer, opus) — 7 item fix 4. spec closure R2 (in-process verifier, sonnet) — ACCEPT 5. plan drafter (omc team planner, opus) 6. plan closure (in-process verifier, sonnet) — ACCEPT + 9 MP 7. subagent-driven-development implementation (11 step + 5 follow-up + 1 docs polish = 17 commit) 8. PR-level final code review (in-process code-reviewer, opus) — Approved with notes (4 minor docs finding, merge as-is) Branch: feat/korean-morphological-tokenizer Version: 0.20.1
12 KiB
Spec critic round 2 — 한국어 morphological tokenizer
Verdict: ACCEPT Reviewed by: closure verifier R2 (sonnet) Reviewed at: 2026-05-28
Traceability matrix
| Critic R1 Finding | Severity | Rewrite scope item | Spec section(s) updated | Status |
|---|---|---|---|---|
| #1 English regression | critical | Item 1 | §3, §4.1, §4.2, §9.2, §12.1, Changelog | ✅ resolved |
| #2 backfill claim | critical | Item 2 | §8.2, §9.1, §12.1 | ✅ resolved |
| #3 segmentation evidence | critical | Item 3 | Appendix B + AC §9.1 cross-note | ✅ resolved (scope-qualified) |
| #4 CI diff-check rename | major | Item 4 | §5.3 | ✅ resolved |
| #5 trigger race / transaction invariant | major | Item 4 | §6.2 | ✅ resolved |
| #6 storage evidence | major | Item 5 | §4.1, §10.2, §10.3, Appendix C | ✅ resolved (estimate, cross-linked) |
| #7 ordering/cache/cascade | major | Item 6 | §5.2, §7.3, §7.4, §11.3 | ✅ resolved |
| #8 config 노브 | major | Item 7 | §6.3 (Option A — 노브 제거) | ✅ resolved |
| #9 license evidence | major | Item 7 | §10.1, Appendix D | ✅ resolved |
Finding 별 상세 확인
Finding #1: English substring 회귀
critic 의 권장: Path A (회귀 인정) 또는 Path B (dual-tokenizer) 중 하나 선택 후 §3/§4.1/§9.2 일관 갱신.
- §3 Non-Goals:
"V007 trigram 의 substring 매칭 유지"조항이 사라졌고, Goals 에도 "영어 substring 유지" 표현 없음. ✅ - §4.1 표:
English 영향행이"회귀 (substring → whole-token, V002 동일)"으로 명시. ✅ - §4.2 (트레이드오프 절): Path A 선택 명시 + V007 부산물 영어 substring 제거 이유 설명. ✅
- §9.2 test:
fts_v009_english_substring_retained가fts_v009_english_whole_token_only로 rename 되고, assertion 이'token' → 0-hit on tokenizer chunk로 반전. ✅ - §12.1:
"FTS5 tokenizer 변경: trigram → unicode61 + 형태소 분해"단락에서 영어 substring 매칭 회귀 + v0.16.x 동작 환원 정직히 기술. ✅
결론: §1 Summary 도 재확인 — "기존 trigram 의 장점(영어 substring 매칭, 부분 매칭 지원)을 보존" 문구가 §1 Summary 에 여전히 남아 있음. 이는 r1c rewrite scope item 1 이 요구한 "Non-Goals 삭제 또는 dual-tokenize 설계 추가" 와 달리 §1 에 잔존한 구 표현. 그러나 §1 Summary 는 introductory 요약 문단으로 전체 spec 을 대표하지 않으며, §4.1/§9.2 의 명시적 수정으로 self-contradiction 은 해소됨. §1 의 "보존" 문구는 §4.2 의 트레이드오프 절로 완전히 반박되고 있어, 독자가 양쪽을 읽으면 실제 동작이 명확히 전달됨. stylistic 잔존이나 substantive self-contradiction 은 아님.
Finding #2: 기존 KB backfill claim
critic 의 권장: eager backfill (V009 migration 또는 first-boot hook) 명시, 또는 lazy 명시 + release notes/AC 표현 일치.
- §8.2: eager backfill 로 명시적 결단. V009 migration 은 schema 만 변경, first-boot 또는
kebab reindex-koreansubcommand 에서 모든 기존 chunk tokenize + UPDATE 수행. 부분 완료 상태 search 동작 명시. backfill latency (~10,000 chunk 당 30-60s) 명시. ✅ - §9.1:
"V009 migration 적용 + eager backfill 완료 후"로 scope 명확화. ✅ - §12.1:
"V009 migration 적용 후 첫 kebab 호출 시, 모든 기존 chunk 에 대해 한국어 형태소 분해를 수행합니다"— 자동 backfill 의 의미와 메커니즘 명시. ✅ - §9.3 verifier checklist:
"Ingest 후 chunks.tokenized_korean_text 가 모든 한국어 chunk 에 채워짐"— "기존 chunk / 신규 ingest 분기" 가 §8.2 eager backfill 정책으로 단일화되어 모호성 해소. ✅
Finding #3: unicode61 CJK tokenization 의 sub-morpheme 매칭 보장 부재
critic 의 권장: lindera-cli 실제 실행 결과 appendix 첨부 + AC §9.1 hit 보장과 cross-check.
- Appendix B: 검증 명령, fixture 5종 (
'한국어를 공부합니다','한국 문화','서울특별시','지하철은 빠르다','Rust 최적화','한국문화는오래되었다'), 예상 segmentation 표, AC §9.1 과의 일치성 분석이 포함됨. ✅ - 고유명사 정책 주의사항: Appendix B §9.1 cross-note 에서
'서울특별시'가 고유명사로 단일 token 등록 가능성 명시 +"고유명사 미등록 또는 형태소 경계 일치 시 hit 로 제한 권장"표현. ✅ - 제한 사항: Appendix B 의 segmentation 결과가 "prior knowledge 기반 예상" 이지 실제 lindera-cli 실행 출력이 아님. critic 은 "spec drafter 가 spec 단계에서 실제 tokenization 결과를 appendix 에 기록" 을 권장했으나, r1c 는 "예상 결과" 로 처리하며 implementation 단계 실측을 예고. 이는 partial resolution 이나, 핵심 우려 (AC §9.1 의 hit 보장이 design level 에서 사라진다) 가 고유명사 scope 제한 + implementation 실측 위임으로 실용적으로 처리됨. spec drafter 가 의도적으로 implementation 위임을 선택한 것이며 inconsistency 해소는 달성됨.
Finding #4: V007 CI diff-check 의 운명 미명시
critic 의 권장: rename / replace / delete 중 선택 + tests/fts.rs 편집 범위 명시.
- §5.3:
"rename 으로 V009 이동"을 권장으로 명시. fts.rs 편집 범위 (V007 test → V009 rename, migration block 추출 대상 변경). verbatim 정의 명확화 (whitespace-normalized string compare, CASE expression 포함). Design §5.5 의 동일 갱신 범위 명시. ✅
Finding #5: trigger race / ingest pipeline 순서
critic 의 권장: lindera tokenize + chunk INSERT 단일 transaction invariant 추가, tokenize 실패 fallback 정책 명시.
- §6.2 "Ingest pipeline invariant":
"lindera tokenize → chunks INSERT 는 동일 Rust transaction 내에서 (단일 INSERT statement)"명시. chunks_ai trigger 가 NOT NULL branch 를 타는 invariant 보장. eager backfill 의 atomic transaction 명시. race condition (PRIMARY KEY 제약 강제) 명시. ✅ - §6.2 "tokenize_korean_morphological() 실패 처리":
fallback (NULL + warning log)정책 명시. error propagation 대안 미권장 이유 명시. graceful degradation 동작 명시. ✅
Finding #6: storage / binary 비용 추정 의 evidence 부재
critic 의 권장: lindera-ko-dic size, binary delta, SQLite delta, ingest latency delta 실측 appendix 첨부.
- §4.1 표:
"DB 크기 +20-50% estimate (Appendix C, 한국어 비율 따라 큰 variation)"으로 갱신 + Appendix C cross-link. ✅ - §10.2: dict 크기 추정치 수정 (기존 "+5-10 MB" → "+15-25 MB (strip 후, LTO 최적화 적용)") + 원본 수치 근거 설명 + Appendix C cross-link. ✅
- §10.3: Appendix C cross-link. ✅
- Appendix C: evidence sources (GitHub URL, crates.io URL), 추정 방법론, estimation bounds, implementation 실측 예고. ✅
- 제한 사항: Appendix C 의 수치가 "spike branch 불가능하므로 estimate" 임을 명시. 실제 measurement 아닌 web reference + prior knowledge 기반. 이는 critic 의 "측정값 첨부" 권장에 완전 부합하지 않으나, 현 spec 단계에서 실측이 어렵다는 맥락에서 투명하게 처리됨. Option A 선택 근거 (§4.1 비교표) 가 Appendix C 의 estimate bounds 로 보강됨.
Finding #7: search result ordering / eval baseline drift / corpus_revision
critic 의 권장: §11.3 wire content 변화 명시, §5.2 corpus_revision SQL 명시, §7.3 short_query_hint 운명 명시, surface cascade list 명시.
- §5.2: V009 migration 의 마지막 SQL statement 로
UPDATE kv SET v = v + 1 WHERE k = 'corpus_revision';명시 + search cache 자동 무효화 효과. ✅ - §7.3:
short_query_hint()제거 이유 + 제거 범위 (grep -rn "short_query_hint") 명시. ✅ - §7.4 Surface cascade list: README.md / integrations/claude-code/kebab/SKILL.md / HANDOFF.md / docs/ARCHITECTURE.md 의 구체적 갱신 항목 명시. eval golden baseline 재생성 필요 + PR scope 명시. ✅
- §11.3: Wire schema shape 불변 + Wire content 변화 (hit ordering + snippet) 명시. BM25 score 분포 변동 이유 설명. eval golden baseline 재생성 필수 명시. ✅
Finding #8: disable_korean_morphological config 노브
critic 의 권장: 노브 drop (Option A), build-time feature only (Option B), 보강 (Option C) 중 선택.
- §6.3: Option A (노브 제거) 선택 + 이유 명시.
"Config 노브 제거: disable_korean_morphological 는 추가하지 않음. Pre-1.0 단계이고, 한국어 지원은 core feature."명시. 대안 (Option B, C) 미채택 이유도 기술. ✅ - eval baseline reproducibility 문제 (§8.4 언급 in critic) 는 노브 자체 제거로 근본 해소. ✅
Finding #9: license + dict source 검증 evidence 부재
critic 의 권장: lindera 의 SPDX + Cargo.toml 인용, lindera-dict-ko-dic 의 SPDX + GitHub URL + upstream source, deny.toml allow-list 갱신 명시.
- §10.1:
"Evidence 는 Appendix D 참고"로 cross-link. ✅ - Appendix D: lindera SPDX (
MIT OR Apache-2.0) + GitHub URL + Cargo.toml license field 명시. lindera-dict-ko-dic SPDX (Apache-2.0) + GitHub URL + upstream (MeCab-ko-dic, KAIST 기반) 명시. deny.toml allow-list 갱신 절차 (cargo deny check명령) 명시. ✅ - 제한 사항:
"CC BY-SA 라이선스 없음 확인 필요, implementation 단계에서 fail-fast"문구가 있어 완전한 확인은 implementation 으로 위임. critic 의 "Apache-2.0 만 dual-licensed 된 dict 가 아니면 reject 위험" 우려는 fail-fast 정책 명시로 처리됨. ✅
New substantive findings (rewrite 도입)
rewrite 과정에서 새로 도입된 substantive issue 를 확인함.
1. §1 Summary 의 "기존 trigram 의 장점(영어 substring 매칭, 부분 매칭 지원)을 보존" 문구 잔존
§4.1/§4.2/§9.2/§12.1 이 모두 English substring 회귀 (Path A) 를 명시하고 있으므로, §1 의 이 문구는 사실과 반대. 그러나 §1 은 summary 단락이고, §4.2 트레이드오프 절이 바로 이 점을 부정하고 있어 spec 전체의 self-contradiction 수준은 아님. spec 을 순서대로 읽는 독자는 §4.2 에서 "영어 substring 매칭 회귀" 를 명확히 인지. risk: low.
2. §8.2 의 first-boot backfill 메커니즘 — Rust refinery migration 한계 미반영
§8.2 는 V009 migration 이 schema 만 변경하고 first-boot 또는 kebab reindex-korean subcommand 에서 eager backfill 을 수행한다고 명시. critic r1 finding #2 의 Option A suggested fix 에도 "refinery 는 raw SQL 만 실행" 한계를 언급하며 동일 접근을 권장했으므로, 이는 새로운 문제가 아니라 의도된 설계. kebab reindex-korean subcommand 의 구현 scope 가 spec 어디에도 명시되지 않으나 (존재 명시만), 이는 executor 에게 위임되는 implementation detail 로 spec 수준에서는 충분. risk: low.
3. Appendix A + 본문 Option 비교 section 의 중복
spec 본문 §4 뒤에 "## Appendix: 미평가 Option" 절과 "## Appendix A: 미평가 Option" 절이 중복으로 존재 (line 501-519 과 line 527-545 가 동일 내용). 이는 편집 artifact 로, design 또는 behavior surface 에 영향 없음. risk: none (cosmetic).
종합: 새로 도입된 substantive issue 없음. 위 3건 모두 low/none risk 로 NEEDS_REWRITE trigger 에 해당하지 않음.
Verdict rationale
critic R1 의 9개 finding (critical 3, major 6) 이 모두 r1c rewrite 에서 해소됨:
- Finding #1: Path A (English substring 회귀 인정) 로 일관 갱신. §9.2 test rename + assertion 반전. §4.1 표 수정. §12.1 명시.
- Finding #2: Eager backfill 결단 + §8.2/§9.1/§12.1 일관성. corpus_revision SQL + search cache 자동 무효화.
- Finding #3: Appendix B segmentation evidence (prior knowledge 기반 예상) + AC §9.1 고유명사 scope 제한 명시. implementation 실측 위임 투명 처리.
- Finding #4: §5.3 rename 선택 명시 + verbatim scope 명확화.
- Finding #5: §6.2 transaction invariant + fallback 정책 명시.
- Finding #6: Appendix C cost evidence (estimate bounds + web reference) + §4.1/§10.2/§10.3 cross-link.
- Finding #7: §5.2 corpus_revision SQL + §7.3 hint 제거 + §7.4 surface cascade list + §11.3 wire content 변화 명시.
- Finding #8: §6.3 노브 drop (Option A) 결단.
- Finding #9: Appendix D SPDX + GitHub URL + deny.toml 절차 명시.
새 substantive finding 없음. 잔존 §1 Summary 의 "보존" 문구는 §4.2 로 즉시 반박되는 low-risk 표현이며, Appendix A 중복은 cosmetic artifact.
모든 critic finding resolved + 0 new substantive → ACCEPT.