task(A1): builder baseline + sqlite version + snapshot locations
Task A1 step 1-3 완료. plan A5 의 baseline 노트 슬롯 채움. 핵심 발견: - build_match_string() (lexical.rs:177-200): trim → strip_single_quotes raw FTS verbatim / 그 외 whitespace split + escape_fts5_token (\"...\" + inner doubling) + space join (implicit AND). - raw mode = single quote '...' 가 trimmed 전체 감쌈 (lexical.rs:167). - SQLite: rusqlite 0.32 + libsqlite3-sys 0.30.1 bundled (in-tree, SQLite ~3.46.x) → trigram 사용 가능. - Snapshot: tests/lexical.rs::lexical_snapshot_run_1 + tests/hybrid.rs:: hybrid_snapshot_run_1 (KEBAB_UPDATE_SNAPSHOTS=1 로 regenerate). inline normalize_bm25_top_score 는 numerical 무관. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -48,11 +48,22 @@ Codex 리뷰로 현재 `build_match_string()` (lexical.rs:177) 이 trigram 비
|
||||
**Files:**
|
||||
- Read: `crates/kebab-search/src/lexical.rs` (`build_match_string()` 본문, MATCH query 빌드 라인 260-290, lexical snapshot 라인 506 부근)
|
||||
|
||||
- [ ] **Step 1: builder 동작 기록** — `build_match_string()` 의 정확한 동작 (raw query 입력 처리, mode 분기, escape, prefix `*` 처리, raw FTS mode 진입 조건 — `lexical.rs:167` 기준 **사용자가 single quote `'...'` 로 감싼 경우 raw FTS**) 을 Task A5 의 노트에 baseline 으로 기록 (재설계 시 회귀 방지).
|
||||
- [x] **Step 1: builder 동작 기록** — `build_match_string()` (lexical.rs:177-200) baseline:
|
||||
1. `text.trim()` → trimmed. 빈 → `None` 반환.
|
||||
2. `strip_single_quotes(trimmed)` 매치 시 (= `'...'` 전체 감싸기, closing quote 가 trimmed 의 마지막 char) → inner.trim() 빈 아니면 `Some(inner.to_string())` (raw FTS5 verbatim mode).
|
||||
3. 그 외 → `trimmed.split_whitespace().map(escape_fts5_token).collect()` → 빈이면 `None`, 아니면 ` ` join (FTS5 default implicit AND).
|
||||
- `escape_fts5_token` (lexical.rs:218): 토큰을 `"..."` 으로 wrap, inner `"` 은 doubling.
|
||||
- prefix `*` 별도 처리 없음 — 사용자가 raw mode 로 입력해야.
|
||||
- raw mode 진입 조건: 사용자가 single quote `'...'` 로 trimmed 전체를 감싼 경우 (`lexical.rs:167` 주석에 명시).
|
||||
- MATCH 호출: lexical.rs:281 `WHERE chunks_fts MATCH ?` (bound parameter).
|
||||
|
||||
- [ ] **Step 2: SQLite 버전 확인** — `sqlite3 --version` 또는 cargo 가 링크하는 `libsqlite3-sys` 번들 버전. trigram 은 SQLite 3.34.0+ 필요 (대부분 충족). `tokenize = 'trigram'` 단독 사용 (case-insensitive 기본). `remove_diacritics` 옵션은 SQLite 3.45.0+ 요구라 호환성 위해 미사용.
|
||||
- [x] **Step 2: SQLite 버전 확인** — `Cargo.toml`: `rusqlite = { version = "0.32", features = ["bundled"] }` + `Cargo.lock` `libsqlite3-sys = "0.30.1"` (system sqlite 무관, in-tree 빌드). libsqlite3-sys 0.30.1 의 번들 SQLite ~3.46.x — trigram (3.34+) 사용 가능. design 결정대로 `tokenize = 'trigram'` 단독 사용 (case-insensitive 기본). `remove_diacritics` 옵션 미사용.
|
||||
|
||||
- [ ] **Step 3: lexical snapshot 위치 확인** — `lexical.rs:506` 근처 BM25 snapshot 테스트가 어느 파일·함수인지 (`crates/kebab-search/tests/` 또는 `insta` 스냅샷 디렉토리) 확인. Task A4 Step 5 에서 갱신 대상.
|
||||
- [x] **Step 3: lexical snapshot 위치 확인** — Codex round 1 의 "lexical.rs:506" 은 `fn normalize_bm25` (BM25 score → (0,1] mapping) 였음 — numerical transformation 이라 token stream 영향 없음. 진짜 snapshot 은:
|
||||
- `crates/kebab-search/tests/lexical.rs:1012` `lexical_snapshot_run_1` — fixture 기반, `KEBAB_UPDATE_SNAPSHOTS=1` env 로 regenerate, "baseline snapshot must exist; run with KEBAB_UPDATE_SNAPSHOTS=1 to seed".
|
||||
- `crates/kebab-search/tests/hybrid.rs:121` `hybrid_snapshot_run_1` — 동일 패턴 (`hybrid_snapshot drift`). 한국어 trigram 영향 받음 (token stream 변경).
|
||||
- inline `crates/kebab-search/src/lexical.rs:592` `normalize_bm25_top_score_in_unit_interval` — numerical, 영향 없음 (회귀 없음 확인만).
|
||||
Task A4 Step 5 에서 lexical_snapshot_run_1 + hybrid_snapshot_run_1 둘 다 regenerate.
|
||||
|
||||
### Task A2: V007 migration 작성
|
||||
|
||||
@@ -161,7 +172,21 @@ Codex 검증: 현재 `build_match_string()` (lexical.rs:177) 은 whitespace spli
|
||||
|
||||
**사용자 결정** (2자 이하 한국어 query 정책): lexical core 는 정상 0-hit (변경 없음), 안내 메시지는 CLI/TUI 레이어가 출력 ("3자 이상 키워드 권장").
|
||||
|
||||
**A1 baseline 노트:** _(Task A1 Step 1 에서 채움 — 현재 builder 의 raw query 처리, mode 분기, escape, raw FTS 진입 조건)_
|
||||
**A1 baseline 노트** (Task A1 Step 1 에서 채움):
|
||||
|
||||
`build_match_string(text: &str) -> Option<String>` (lexical.rs:177-200) baseline:
|
||||
|
||||
1. `text.trim()` → trimmed. 빈 → `None`.
|
||||
2. `strip_single_quotes(trimmed)` 매치 시 (single quote `'...'` 가 trimmed 전체 감쌈, closing quote 가 마지막 char — `'foo' bar` 는 raw 아님) → inner.trim() 빈 아니면 `Some(inner.to_string())` (raw FTS5 verbatim).
|
||||
3. 그 외 → `trimmed.split_whitespace().map(escape_fts5_token).collect()` → 빈이면 `None`, 아니면 ` ` join (FTS5 default implicit AND).
|
||||
|
||||
`escape_fts5_token(tok)` (lexical.rs:218): `"..."` wrap + inner `"` doubling.
|
||||
|
||||
재설계 시 회귀 방지 — raw mode (single quote `'...'`) 진입 조건은 그대로 유지. escape_fts5_token 도 그대로 (trigram 도 FTS5 special char escape 필요). 변경은 비-raw 경로의 토큰 합성만.
|
||||
|
||||
SQLite: rusqlite 0.32 + libsqlite3-sys 0.30.1 **bundled** (in-tree). SQLite ~3.46.x → trigram 사용 가능.
|
||||
|
||||
Snapshot: `crates/kebab-search/tests/lexical.rs::lexical_snapshot_run_1` + `crates/kebab-search/tests/hybrid.rs::hybrid_snapshot_run_1` (둘 다 `KEBAB_UPDATE_SNAPSHOTS=1` 로 regenerate). inline `normalize_bm25_top_score_in_unit_interval` 는 numerical 영향 없음.
|
||||
|
||||
**Files:**
|
||||
- Modify: `crates/kebab-search/src/lexical.rs` (`build_match_string()`)
|
||||
|
||||
Reference in New Issue
Block a user