본 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
26 KiB
Plan closure round 1 — 한국어 morphological tokenizer
Verdict: ACCEPT Reviewed by: closure verifier (sonnet) Reviewed at: 2026-05-28
Task A — Step → Spec traceability matrix
Forward matrix (Step → Spec sections)
| Step | Title | Plan 에 명시된 Spec sections | Spec content match? | Notes |
|---|---|---|---|---|
| S1 | V009 migration + design §5.5 + CI rename | §5.1, §5.2, §5.3 | ✅ | spec §5.1 DDL skeleton, §5.2 corpus_revision bump SQL, §5.3 design §5.5 갱신 + CI diff-check rename 정확히 cover. |
| S2 | lindera dep | §6.1, §10.1 | ✅ | spec §6.1 라이브러리 선정 (lindera + lindera-dict-ko-dic), §10.1 license 검증 + Appendix D cross-link 반영. |
| S3 | tokenize_korean_morphological + ingest 통합 | §6.2 | ✅ | spec §6.2 Pre-tokenize 우회 + Invariant + 실패 처리 전체 cover. chunk struct 신규 field + store INSERT path 포함. |
| S4 | first-boot eager backfill | §8.1, §8.2, §6.2 (backfill atomic transaction) | ✅ | spec §8.1 V007 trigram DROP 처리, §8.2 자동 eager backfill 전략, §6.2 의 backfill atomic transaction invariant 모두 cover. |
| S5 | short_query_hint 제거 + lexical.rs 정리 | §7.2, §7.3 | ✅ | spec §7.2 lexical.rs 조정 (보존 선택), §7.3 CLI hint 제거 범위 cover. wire schema 영향 확인 절차(§11.3 cross-check)도 포함. |
| S6 | lexical_index_version bump | §11.1, §11.3 | ✅ | spec §11.1 index_version bump (format 갱신), §11.3 wire content 변화 명시 (lexical test 갱신) cover. |
| S7 | 신규 unit/integration test | §9.1, §9.2 | ✅ | spec §9.1 lexical-mode scenarios 4개 중 한국어 3개 + 영어 회귀 1개, §9.2 test 시그니처 verbatim 반영. fts_v009_matches_design_section_5_5_verbatim 은 S1 에서 이미 생성됨(plan 내 명시). |
| S8 | eval golden regenerate | §11.3 | ✅ | spec §11.3 "eval golden baseline 재생성 필수" 를 plan scope 포함으로 결정 + deviation 시 P5 follow-up 분리 가능 명시. |
| S9 | docs sync | §7.4 | ✅ | spec §7.4 Surface cascade list (README / SKILL / HANDOFF / ARCHITECTURE) + tasks/HOTFIXES.md entry 모두 cover. |
| S10 | version bump | §12.1 | ✅ | spec §12.1 v0.20.1 patch release strategy (Cargo.toml version bump + release notes draft) cover. |
| S11 | final sanity | §9.3, §12.2 | ✅ | spec §9.3 verifier checklist + §12.2 dogfood verification cover. |
Reverse matrix (Spec section → 커버 여부)
| Spec section | Title | Cover 여부 | 담당 Step |
|---|---|---|---|
| §1 Summary | 배경 요약 | 직접 step 불필요 (서술) | — |
| §2 Background (§2.1~§2.3) | V007 한계 + 도그푸딩 + HOTFIXES 맥락 | 직접 step 불필요 (서술) | — |
| §3 Goals + Non-Goals | 목표 범위 | 직접 step 불필요 (서술) | — |
| §4 Design Decision (§4.1~§4.2) | Option A 선택 | 직접 step 불필요 (설계 결정) | — |
| §5.1 DDL skeleton | V009 migration SQL | ✅ covered | S1 |
| §5.2 corpus_revision bump | kv UPDATE + search cache 무효화 | ✅ covered | S1 |
| §5.3 Design contract 변경 + CI diff-check | §5.5 갱신 + test rename | ✅ covered | S1 |
| §6.1 라이브러리 선정 | lindera + lindera-dict-ko-dic | ✅ covered | S2 |
| §6.2 Pre-tokenize 우회 + Invariant + 실패 처리 | tokenize helper + ingest 통합 + backfill | ✅ covered | S3, S4 |
| §6.3 Vendoring 전략 | feature flag (default-enabled) | ⚠ PARTIAL | S2 에서 workspace dep 추가는 cover 하나, kebab-app/[features] 의 feature gate 등록(§6.3 "fts_korean_morphological = ["lindera"]") 이 plan 의 어떤 step 에도 명시적으로 언급되지 않음. |
| §7.1 Search CLI 경로 (변경 없음) | query path 변경 없음 | 직접 step 불필요 (서술) | — |
| §7.2 lexical.rs 조정 | build_match_string() 단순화 검토 | ✅ covered | S5 |
| §7.3 CLI hint 제거 | short_query_hint 제거 | ✅ covered | S5 |
| §7.4 Surface cascade list | docs sync | ✅ covered | S9 |
| §8.1 기존 V007 처리 | DROP + V009 교체 | ✅ covered | S4 |
| §8.2 자동 eager backfill | first-boot hook + idempotency | ✅ covered | S4 |
| §9.1 Lexical-mode search scenarios | 4 AC scenario | ✅ covered | S7, S11 |
| §9.2 Test coverage | test 시그니처 | ✅ covered | S7 |
| §9.3 Verifier checklist | final checklist | ✅ covered | S11 |
| §10.1 License verification | cargo deny / SPDX | ✅ covered | S2 |
| §10.2 Dict size + binary bloat | binary 크기 실측 | ✅ covered (evidence 는 S2 에서 cargo tree + 실측 reconcile) | S2 |
| §10.3 Ingest latency 증가 | latency 측정 | plan S5~Risk 절에 mitigation 언급 (formal step 없음, 허용 범위) | S11 |
| §10.4 다른 언어 | 별 PR | 직접 step 불필요 (out of scope 명시) | — |
| §11.1 index_version bump | lexical_index_version 함수 갱신 | ✅ covered | S6 |
| §11.2 parser/chunker_version | 변경 없음 | 직접 step 불필요 (서술) | — |
| §11.3 Wire schema 변경 + hit ordering | wire shape 불변 + eval golden | ✅ covered | S6, S8 |
| §12.1 v0.20.1 patch release | version bump + release notes | ✅ covered | S10 |
| §12.2 Dogfood verification | fresh KB + 2자 query | ✅ covered | S11 |
| Appendix A (Option B/C 비교) | 설계 rationale | 직접 step 불필요 (서술) | — |
| Appendix B (segmentation evidence) | lindera 실측 | S3 의 test fixture + mitigation 에서 반영 | S3 |
| Appendix C (cost evidence) | binary/DB/latency 추정 | S2 의 cargo build 실측 + plan §10 risks 에서 반영 | S2 |
| Appendix D (license) | SPDX 검증 | ✅ covered | S2 |
누락 section 발견: §6.3 의 feature flag (fts_korean_morphological) 등록이 plan 어디에도 명시적 step/task 가 없음. 아래 Task B 와 연계하여 micro-patch 권장.
Task B — AC actionability (per step)
| Step | AC text excerpt | Actionable? | 비고 / 권장 수정 |
|---|---|---|---|
| S1 | cargo test -p kebab-store-sqlite --test fts fts_v009_matches_design_section_5_5_verbatim -j 4 → exit 0 |
✅ | 명령 + 기대 결과 명확. |
| S1 | cargo test -p kebab-store-sqlite --test fts v009_bumps_corpus_revision -j 4 → exit 0, corpus_revision 값 strict-monotonic 증가 |
✅ | "strict-monotonic 증가" 는 SELECT v 값이 V008 적용 시점 대비 +1 이상 = verifier 가 SQL query 로 확인 가능. |
| S1 | grep -c "fts_v007_matches_design_section_5_5_verbatim" crates/kebab-store-sqlite/tests/fts.rs → 0 |
✅ | grep count 0 = rename 완료 mechanical 확인. |
| S1 | cargo clippy -p kebab-store-sqlite --all-targets -j 4 -- -D warnings → clean |
✅ | exit code 0 = clean. |
| S2 | cargo build --workspace -j 4 2>&1 | grep -E "^error\[E" | wc -l → 0 |
✅ | 명확한 명령 + wc -l 0 check. |
| S2 | cargo tree --depth 1 -p lindera -p lindera-dict-ko-dic 2>&1 | grep -iE "MIT|Apache" | wc -l → ≥ 2 |
✅ | SPDX license 포함 여부 mechanical check. |
| S2 | grep -c "lindera" Cargo.toml → ≥ 1 |
✅ | |
| S2 | grep -c "lindera" crates/kebab-chunk/Cargo.toml → ≥ 1 |
✅ | |
| S3 | cargo test -p kebab-chunk --test tokenize_korean tokenize_korean_morphological_splits_2char_word -j 4 → exit 0, token "한국" 포함 |
✅ | 명령 + fixture 명시. |
| S3 | cargo test -p kebab-chunk --test tokenize_korean tokenize_korean_morphological_empty_returns_none -j 4 → exit 0 |
✅ | |
| S3 | cargo build --workspace -j 4 2>&1 | grep -c "warning: unused" 가 baseline 대비 증가하지 않음 |
⚠ PARTIAL | "baseline 대비" 가 verifier 가 별도로 baseline 수치를 보유하고 있어야 함. 더 actionable 한 형태: cargo build --workspace -j 4 2>&1 | grep -c "warning: unused import.*lindera" → 0 (lindera 가 실제 사용됨) 으로 수정 권장. |
| S3 | grep -n "tokenized_korean_text" crates/kebab-chunk/src/lib.rs → ≥ 1 |
✅ | |
| S3 | cargo clippy -p kebab-chunk --all-targets -j 4 -- -D warnings → clean |
✅ | |
| S4 | cargo test -p kebab-store-sqlite --test fts backfill_tokenized_korean_text_populates_nullable_rows -j 4 → exit 0, idempotency 확인 |
✅ | idempotency 는 test body 에서 두 번째 호출 반환값 0 확인으로 mechanical 검증. |
| S4 | App::open_with_config 두 번 연속 호출 시 두번째 backfill_count = 0 |
⚠ PARTIAL | 이 AC 는 unit test 명령이 없음. "두 번 연속 호출" 의 test binary 이름이 명시되지 않아 verifier 가 어느 test 로 확인하는지 불명확. 권장: cargo test -p kebab-app -j 4 -- backfill_idempotent (또는 동급 test 명) 으로 명시. |
| S4 | cargo clippy -p kebab-app --all-targets -j 4 -- -D warnings → clean |
✅ | |
| S5 | grep -rn "short_query_hint" crates/ tests/ 2>/dev/null | wc -l → 0 |
✅ | doc-comment 1줄 허용 예외가 있으나 ≤1 조건으로 처리 가능. |
| S5 | cargo build --workspace -j 4 2>&1 | grep -E "error|warning: unused" | wc -l → baseline 과 동등 |
⚠ PARTIAL | S3 AC 와 동일한 "baseline 대비" 문제. 권장: cargo build --workspace -j 4 2>&1 | grep -E "^error" | wc -l → 0 으로 대체. |
| S5 | cargo test -p kebab-cli --test wire_search_response -j 4 → exit 0, test 가 list 에서 사라짐 |
✅ | test list 에서 사라짐 = cargo test -- --list grep 으로 확인. |
| S5 | cargo clippy --workspace --all-targets -j 4 -- -D warnings → clean |
✅ | |
| S6 | cargo test -p kebab-search --test lexical lexical_index_version_is_returned_unchanged -j 4 → exit 0 |
✅ | |
| S6 | ./target/debug/kebab schema --json | jq -r '.index_versions.lexical // empty' 2>/dev/null | grep -c "fts5-v009" → ≥ 1 |
⚠ PARTIAL | target/debug/kebab 의 빌드 여부가 이 step 에서 보장되지 않음. 권장: 명령 앞에 cargo build -p kebab-cli -j 4 && 를 prepend 하거나, release path 용 cargo build --release -p kebab-cli -j 4 선행 명시. |
| S6 | cargo clippy -p kebab-app --all-targets -j 4 -- -D warnings → clean |
✅ | |
| S7 | cargo test -p kebab-store-sqlite --test fts fts_v009_korean_morphological_2char_query_hits -j 4 → exit 0 |
✅ | |
| S7 | cargo test -p kebab-store-sqlite --test fts fts_v009_english_whole_token_only -j 4 → exit 0 |
✅ | |
| S7 | cargo test -p kebab-app --test search_korean korean_morphological_2char_query_lexical_mode -j 4 → exit 0 |
✅ | |
| S7 | cargo test -p kebab-app --test search_korean korean_morphological_mixed_english_korean_query -j 4 → exit 0 |
✅ | |
| S7 | 신규 test binary 2개 추가로 workspace test count baseline +4 이상 | ⚠ PARTIAL | 검증 명령이 없음. 권장: cargo test --workspace --no-fail-fast -j 1 2>&1 | grep "^test result" | awk -F'[,;]' '{sum+=\$2} END{print sum}' 의 before/after 비교, 또는 cargo test -p kebab-store-sqlite --test fts -- --list | wc -l 과 cargo test -p kebab-app --test search_korean -- --list | wc -l 각 ≥ 1 로 대체 가능. |
| S8 | cargo test -p kebab-eval -j 4 2>&1 | grep "test result.*failed" | grep -v "0 failed" | wc -l → 0 |
✅ | |
| S8 | git diff --stat crates/kebab-eval/goldens/ → 변경 라인 수 > 0 |
✅ | baseline 이 실제로 갱신됐는지 mechanical 확인. |
| S8 | cargo clippy -p kebab-eval --all-targets -j 4 -- -D warnings → clean |
✅ | |
| S9 | git diff --stat README.md HANDOFF.md docs/ARCHITECTURE.md integrations/claude-code/kebab/SKILL.md tasks/HOTFIXES.md → 5 file 모두 변경 |
✅ | |
| S9 | grep -c "한국어 2자" README.md → ≥ 1 |
✅ | |
| S9 | grep -c "V009" tasks/HOTFIXES.md → ≥ 1 |
✅ | |
| S9 | grep -c "lindera" docs/ARCHITECTURE.md → ≥ 1 |
✅ | |
| S10 | grep "^version" Cargo.toml | head -1 → version = "0.20.1" |
✅ | |
| S10 | ./target/release/kebab --version 2>&1 → kebab 0.20.1 |
⚠ PARTIAL | release binary 빌드 여부가 S10 에서 보장되지 않음. 권장: cargo build --release -p kebab-cli -j 4 && ./target/release/kebab --version 로 명시. |
| S10 | cargo build --workspace -j 4 2>&1 | tail -3 → success |
✅ | |
| S11 | cargo test --workspace --no-fail-fast -j 1 → 모두 pass (baseline +4 이상) |
✅ | S11 은 전체 suite run — workspace sanity 기준. |
| S11 | dogfood smoke (fresh KB, 3 query) | ✅ | 명령 verbatim 명시됨. |
| S11 | V007 snapshot backfill 시나리오 | ✅ (best-effort 명시) | snapshot 부재 시 best-effort 허용으로 명시됨. |
요약: PARTIAL AC 총 6건 (S3, S4, S5, S6, S7, S10) — 모두 minor actionability gap 이며, 명령 보강으로 해소 가능. NEEDS_REWRITE 수준 아님 → micro-patch 권장.
Task C — Dependencies sanity
그래프 cycle-free 여부
의존 관계를 DAG 로 표현:
S1, S2 → S3 → S4, S5, S6 → S7 → S8 → S9 → S10 → S11
(S1 also → S4, S6, S7 directly)
- S1 → S3 (V009 schema 필요), S1 → S4 (backfill은 V009 schema 필요), S1 → S6 (verbatim test rename 결과), S1 → S7 (fts.rs V009 test 기반).
- S2 → S3 (lindera dep 필요).
- S3 → S4 (backfill API 가 tokenize_korean_morphological 호출), S3 → S5 (short_query_hint 제거 후 cascade clean 필요), S3 → S7 (search_korean 통합 test 의 ingest path).
- S4, S5, S6 → S7 (test가 backfill + hint 제거 + version bump 모두 의존).
- S7 → S8 (eval golden 재생성은 new test baseline 기반), S7 → S11.
- S8 → S11.
- S9 → S10 (docs sync 후 version bump 의 커밋 순서).
- S10 → S11.
사이클 없음 (topological order: S1 → S2 → S3 → {S4, S5, S6} → S7 → S8 → S9 → S10 → S11). 그래프 cycle-free: ✅
parallel-dispatch 가능 step 명시 정확성
plan §3 의 명시:
- Group 1: S1 + S2 병렬. ✅ 두 step 은 파일 overlap 없음 (S1은 migration+design+fts.rs, S2는 Cargo.toml 만).
- Group 2: S4 + S5 + S6 병렬. ✅ S4 (store.rs + lib.rs), S5 (app.rs + tui/*.rs + cli/tests), S6 (app.rs:991-993 한 줄) — file overlap이 app.rs 에서 발생할 수 있음. S5 는
crates/kebab-app/src/app.rs:98,532,616를 수정하고, S6 은crates/kebab-app/src/app.rs:991-993을 수정 — 동일 파일의 다른 행이나 병렬 에이전트가 동시에 수정 시 merge conflict 가능. plan 이 "file overlap 0" 이라고 명시하나 실제로는 app.rs 가 공유됨. 이는 runtime conflict risk 이며 cycle 이 아니므로 NEEDS_REWRITE trigger 아님. micro-patch 권장: Group 2 의 S6 을 S5 직후 sequential 로 명시하거나, "app.rs 의 편집 구역 분리 (line 범위 기준)" 를 executor 에게 주의 사항으로 기록.
subagent-driven-development "tasks mostly independent" criterion
- S1, S2 가 진정으로 독립적 (entry point, 파일 무중복). ✅
- S4, S5 는 파일 overlap 최소 (서로 다른 crate). ✅
- S4/S5 vs S6 는 app.rs 공유 — conditional ✅ (행 단위 비겹침이나 실측 merge 주의 필요).
- S7 → S8 → S9 → S10 은 sequential 이므로 독립성 불요.
전반적으로 "tasks mostly independent" criterion 충족. ✅
Task D — Cost optimization 정합성
| Step | Title | Plan 권장 모델 | 사용자 요청 부합 | 판단 |
|---|---|---|---|---|
| S1 | V009 migration + design §5.5 + CI rename | opus | 복잡: spec §5.5 verbatim 정합 + CI diff-check marker 형식 일관성 + design doc 갱신. trigger CASE expression 한 글자 오차로 CI fail 위험. | ✅ opus 적절 |
| S2 | lindera dep | sonnet | 단순 mechanical: Cargo.toml dep 추가 + cargo tree SPDX 확인. | ✅ sonnet 적절 |
| S3 | tokenize_korean_morphological + ingest 통합 | opus | 복잡: lindera API 호출 (0.32 builder pattern 확인), chunk struct cascade, multi-crate 동시 변경, transaction invariant 보장. | ✅ opus 적절 |
| S4 | first-boot eager backfill | sonnet | spec 에 API signature 와 body outline 이 상세 명시됨. batch commit 패턴 표준. | ✅ sonnet 적절 |
| S5 | short_query_hint 제거 + lexical.rs 정리 | sonnet | 다중 파일 cascade 이나 mechanical search+delete. wire schema grep + if-then 분기 있으나 명시됨. | ✅ sonnet 적절 |
| S6 | lexical_index_version bump | sonnet | 단일 함수 + test fixture 1줄 갱신. | ✅ sonnet 적절 |
| S7 | 신규 test | sonnet | spec §9.2 verbatim 시그니처 따라. fixture 조정 필요 시 plan 에 가이드 있음. | ✅ sonnet 적절 |
| S8 | eval golden regenerate | sonnet | baseline regenerate 명령 실행 + commit. | ✅ sonnet 적절 |
| S9 | docs sync | sonnet | mechanical text edit, README narrow scope 지켜짐. | ✅ sonnet 적절 |
| S10 | version bump | sonnet | 한 줄 변경. | ✅ sonnet 적절 |
| S11 | final sanity | sonnet | 검증 명령 실행만. | ✅ sonnet 적절 |
| PR-level final review | 전체 diff | opus | merge 직전 cross-file 일관성. | ✅ opus 적절 |
종합: 사용자 요청("가벼운 작업은 sonnet, 복잡한 것은 opus") 과 plan 의 routing 이 완전히 일치. S1 (§5.5 verbatim), S3 (lindera API + multi-crate) 두 step 만 opus 로 격상, 나머지 9 step 은 sonnet. ✅ 정합 이상 없음.
Task E — 0 new substantive finding
plan 이 spec 의 design decision 을 재해석·변경·추가했는지 mechanical 검토:
-
§6.3 feature gate: plan S2 의 구현 outline 은 workspace dep 추가를 기술하나, spec §6.3 의
[features] fts_korean_morphological = ["lindera"]등록을 plan 의 어느 step 에도 명시하지 않았다. 이는 spec design 을 변경한 것이 아니라 누락한 것이다 (Task A 에서도 PARTIAL 로 분류). design 재해석이 아니므로 substantive finding 에는 해당하지 않는다. -
S4.1 의 backfill batch commit (1000 row 마다): spec §8.2 에서 batch 크기를 구체적으로 명시하지 않았고 plan 이 1000 row 로 구체화했다. 이는 implementation detail 의 구체화이며, spec 의 design decision (backfill 정책 자체, idempotency, atomic transaction) 을 변경하지 않았다. substantive finding 아님.
-
S10.3 의 release notes draft 파일 (
docs/release-notes/v0.20.1-draft.md): spec §12.1 의 release notes 4 단락 본문이 plan 에서 별도 파일 보관으로 구체화됐다. spec 의 release strategy 를 변경하지 않는 implementation 선택. substantive finding 아님. -
S5 의
search_plain_emits_short_query_hint_to_stderrtest 처리: plan S5.5 에서 "삭제 또는 inverted rename" 두 가지 선택지를 열어 뒀다. spec §7.3 은 함수 정의+호출 제거 범위만 명시하고 test 처리를 직접 다루지 않으므로, plan 이 spec design 을 변경한 것이 아니라 executor 에게 선택을 위임한 것이다. substantive finding 아님. -
S3.1 의
OnceCell/lazy_statictokenizer 캐시 패턴: spec §6.2 에는 dictionary load 의 캐시 패턴이 명시되지 않았다. plan 이 performance optimization 을 추가 제안했으나, 이는 spec 의 invariant ("동일 Rust transaction 내 INSERT") 를 위반하지 않는 implementation hint 다. design 추가가 아니라 실행 guidance. substantive finding 아님.
None. — 새로운 substantive finding 없음.
Task F — Final verifier checklist completeness
spec §9 AC 커버
| spec §9 항목 | plan §7 checklist 커버 | 비고 |
|---|---|---|
§9.1 Scenario 1: kebab search '한국' → hit ≥ 1 |
✅ kebab search '한국' (fresh V009 KB) → hit ≥ 1 |
|
§9.1 Scenario 2: kebab search '서울' → hit ≥ 1 |
✅ kebab search '서울' (fresh V009 KB) → hit ≥ 1 |
|
§9.1 Scenario 3: kebab search '지하철' → hit ≥ 1 |
✅ kebab search '지하철' (fresh V009 KB) → hit ≥ 1 |
|
§9.1 Scenario 4: kebab search 'pipeline' → whole-token 매칭만 (substring 0-hit) |
⚠ PARTIAL | plan checklist 에 pipeline 검색 확인이 없음. S11.5 dogfood smoke 에 해당 query 없음. |
§9.2 fts_v009_korean_morphological_2char_query_hits pass |
✅ cargo test --workspace --no-fail-fast -j 1 → baseline +4 이상 에 포함 |
|
§9.2 fts_v009_english_whole_token_only pass |
✅ 동상 | |
§9.2 fts_v009_matches_design_section_5_5_verbatim pass |
✅ 동상 (S1 에서 생성됨) | |
§9.2 korean_morphological_2char_query_lexical_mode pass |
✅ 동상 | |
§9.2 korean_morphological_mixed_english_korean_query pass |
✅ 동상 | |
§9.3 chunks.tokenized_korean_text 모든 한국어 chunk 에 채워짐 |
✅ V009 migration apply 후 기존 V007 KB → eager backfill 확인 | |
§9.3 FTS5 query MATCH "한국" → hit |
✅ 상동 | |
§9.3 kebab schema --json wire schema 변경 없음 |
✅ S11.4 schema 무결성 (jq -e '.wire.schemas | length') |
|
| §9.3 Hybrid/vector search 변경 없음 | ⚠ PARTIAL | plan checklist 에 hybrid/vector mode 회귀 검증 명령이 없음. spec §9.3 "Hybrid/vector search 는 변경 없음" 항목을 S11 의 dogfood smoke 에서 별도 확인하도록 명시되지 않음. |
spec §10 risk 커버
| spec §10 risk | plan checklist 커버 | 비고 |
|---|---|---|
| §10.1 License (cargo deny) | ✅ "(deferred to P9) cargo deny check" 명시 + cargo tree SPDX 수동 대체 | |
| §10.2 Dict size + binary bloat | ⚠ PARTIAL | plan checklist 에 binary size 실측 확인 항목 없음. S2 에서 cargo build 출력 확인은 있으나, release binary 의 ls -lh 또는 size 측정이 checklist 에 없음. |
| §10.3 Ingest latency 증가 | ⚠ PARTIAL | plan checklist 에 ingest latency 측정 항목이 없음. spec §12.2 "Performance measurement: ingest duration 전후 비교" 를 plan §7 checklist 가 cover 하지 않음. |
| §10.4 일본어/중국어 | 직접 check 불필요 (out of scope) | ✅ |
spec §12 release strategy 커버
| spec §12 항목 | plan checklist 커버 | 비고 |
|---|---|---|
| §12.1 v0.20.1 version bump | ✅ Cargo.toml workspace version = "0.20.1" |
|
| §12.1 release notes 4 단락 | ✅ docs/release-notes/v0.20.1-draft.md 4 단락 |
|
| §12.2 fresh KB + 2자 query dogfood | ✅ S11.5 smoke | |
| §12.2 hybrid/vector mode 변경 없음 확인 | ⚠ PARTIAL | 상동 (§9.3 과 동일 gap) |
| §12.2 performance measurement | ⚠ PARTIAL | checklist 에 ingest duration 비교 없음 |
누락 항목 요약:
- English substring 0-hit 회귀 확인 (
'pipeline'또는'token'query → 0-hit on substring-only string) — plan §7 checklist 미포함. - Hybrid/vector search 변경 없음 확인 명령 — plan §7 checklist 미포함.
- Release binary size 실측 — plan §7 checklist 미포함 (spec §10.2 risk).
- Ingest latency 측정 — plan §7 checklist 미포함 (spec §12.2 + §10.3).
4건 모두 낮은 위험도의 검증 gap 이며, NEEDS_REWRITE trigger 수준 아님. micro-patch 로 처리 가능.
Verdict rationale
Task A~F 의 결과를 종합한다:
- Task A: spec §6.3 feature flag 등록이 plan 에 누락됐으나, design 재해석이 아닌 implementation detail 누락이며 micro-patch 수준. spec 의 모든 core section (§5.1~§12.2) 이 적어도 한 step 에 의해 cover 됨.
- Task B: PARTIAL AC 6건이 모두 "baseline 대비" 모호성, binary 빌드 사전 보장 누락 등 minor actionability gap. 명령 1줄 추가로 해소 가능. critical AC vagueness ("올바르게 작동" 류) 는 0건.
- Task C: 그래프 cycle-free 확인. S5/S6 의 app.rs 공유로 인한 merge conflict 가능성이 있으나 plan 이 "file overlap 0" 이라고 잘못 명시한 것은 micro-patch 주의 수준. cycle 은 아님.
- Task D: 모든 model routing 이 사용자 요청("가벼운 작업 sonnet")과 정합. 이상 없음.
- Task E: 새로운 substantive design finding 없음. plan 은 spec 의 implementation 일정만 기술.
- Task F: 4건의 minor checklist gap (영어 substring 회귀 확인, hybrid/vector 회귀 확인, binary size, ingest latency). 모두 낮은 위험도.
NEEDS_REWRITE trigger (그래프 cycle, spec section 미커버, new substantive design 변경) 에 해당하는 항목 없음. ACCEPT.
Recommended micro-patches (plan author 가 별 round 없이 직접 적용 가능)
다음은 plan 자체의 수정 없이 executor 에게 전달하거나, plan 의 해당 줄을 최소 보완하는 수준의 권장 사항이다.
MP-1 (Task A, §6.3 feature flag): S2 또는 S3 의 "Files to modify" 에 crates/kebab-app/Cargo.toml — [features] 에 fts_korean_morphological = ["dep:lindera"] + default = ["fts_korean_morphological"] 추가 항목 삽입. spec §6.3 의 feature gate 등록을 누락하지 않도록.
MP-2 (Task B, S3 AC): cargo build --workspace -j 4 2>&1 \| grep -c "warning: unused" → cargo build --workspace -j 4 2>&1 \| grep -c "warning: unused import.*lindera" → 0 으로 수정.
MP-3 (Task B, S4 AC): App::open_with_config 두 번 연속 호출 시 backfill_count = 0 AC 에 구체적인 test 이름 또는 검증 명령 추가. 예: cargo test -p kebab-app -j 4 -- backfill_is_idempotent_on_second_open (또는 backfill_tokenized_korean_text_populates_nullable_rows 의 두번째 호출 assertion 이 이미 커버하는 경우 S4 AC 에 그 사실 cross-link).
MP-4 (Task B, S5 AC): cargo build --workspace -j 4 2>&1 \| grep -E "error\|warning: unused" \| wc -l → cargo build --workspace -j 4 2>&1 \| grep -E "^error" \| wc -l → 0 으로 대체.
MP-5 (Task B, S6 AC): ./target/debug/kebab schema --json ... 앞에 cargo build -p kebab-cli -j 4 && 선행 명시.
MP-6 (Task B, S7 AC): 신규 test binary 2개 추가로 workspace test count baseline +4 이상 항목에 검증 명령 추가. 예: cargo test -p kebab-store-sqlite --test fts -- --list 2>&1 \| grep "fts_v009_korean" \| wc -l → ≥ 1 + cargo test -p kebab-app --test search_korean -- --list 2>&1 \| wc -l → ≥ 2.
MP-7 (Task B, S10 AC): ./target/release/kebab --version 앞에 cargo build --release -p kebab-cli -j 4 && 선행 명시.
MP-8 (Task C, Group 2 주의): §3 Dependencies 의 Group 2 주의 사항에 "S5 와 S6 은 모두 crates/kebab-app/src/app.rs 를 수정함. 병렬 에이전트 실행 시 편집 행 범위를 사전 분리할 것 (S5: line 98,532,616; S6: line 991-993)." 한 줄 추가.
MP-9 (Task F, §7 checklist): plan §7 verifier checklist 에 다음 3개 항목 추가:
./target/release/kebab --config /tmp/kebab-smoke-v009/config.toml search 'token' --json \| jq '.hits \| length'→ 0 (영어 substring 매칭 회귀 확인, V009 는 whole-token only)../target/release/kebab --config /tmp/kebab-smoke-v009/config.toml search 'tokenizer' --json \| jq '.hits \| length'→ ≥ 1 (whole-token 매칭 정상).- hybrid/vector 회귀:
./target/release/kebab --config /tmp/kebab-smoke-v009/config.toml search '한국' --mode hybrid --json \| jq '.hits \| length'→ ≥ 1 (또는 mode flag 실제 이름으로 대체).