Files
kebab/tasks/p9/p9-fb-19-search-cache.md
altair823 9601d63c1f chore(tasks): mark p9-fb-19 completed
PR #78 머지 (e9e37fd). 머지 후 spec status 갱신.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-03 05:08:38 +00:00

2.9 KiB

phase, component, task_id, title, status, depends_on, unblocks, contract_source, contract_sections, source_feedback
phase component task_id title status depends_on unblocks contract_source contract_sections source_feedback
P9 kebab-search + kebab-app p9-fb-19 Search result cache (in-memory LRU + index_version invalidation) completed
../../docs/superpowers/specs/2026-04-27-kebab-final-form-design.md
§7 search
§9 versioning
p9-dogfooding-feedback.md item 15

p9-fb-19 — Search cache

Goal

같은 query 반복 시 SQLite FTS + Lance + RRF 재계산 회피. 우선 in-memory LRU + index_version bump 기반 단순 invalidation.

Allowed dependencies

  • lru = "0.12" (검증된 LRU crate).

Public surface

kebab-app::AppMutex<LruCache<CacheKey, Vec<SearchHit>>> 필드. 호출자 (CLI / TUI) 는 변경 없이 cached 결과 받음.

struct CacheKey {
    query_norm: String,        // NFKC + trim + lowercase
    mode: SearchMode,
    k: u32,
    snippet_chars: u32,
    embedding_version: String,
    chunker_version: String,
    index_version: u64,
}

CLI: kebab search --no-cache "..." 로 강제 bypass.

Behavior contract

  • LRU capacity: 256 entry (cfg.search.cache_capacity, default 256). 메모리 한정 — 1 entry ≈ 5KB → 1.3MB 상한.
  • normalize: query 정규화 후 같은 entry. 사용자 입력 trim 차이가 redundant compute 안 만듦.
  • index_version: SQLite kv 테이블의 kv['index_version'] 단조 증가 카운터. ingest 가 1 chunk 라도 변경하면 +1. embedding 만 추가/삭제도 +1. bump 시 cache 의 모든 entry 가 stale (index_version 키 비교).
  • LRU evict / stale entry 는 next miss 시 자동 garbage. 명시적 wipe API 도 제공 (App::clear_search_cache()).
  • TTL: in-memory LRU 라 process 수명. 영속 cache (SQLite) 는 P+.

Test plan

kind description
unit 같은 query 2 회 → 두번째 cache hit
unit ingest → index_version+1 → 같은 query stale → recompute
unit NFKC 정규화: "Foo" / "FOO" / " Foo " 같은 entry
unit LRU evict: capacity+1 entry 삽입 → 가장 오래된 evict
integration --no-cache flag 가 cache bypass

DoD

  • cargo test -p kebab-search -p kebab-app 통과
  • index_version SQLite 컬럼 + ingest 가 bump
  • frozen design §9 versioning 에 index_version 추가
  • README — --no-cache 안내

Out of scope

  • patch-and-merge incremental (사용자가 말한 "추가만 끼워넣기") — P+ task. 우선 stale 시 전체 recompute.
  • SQLite 영속 cache — P+.
  • per-process 공유 cache (RwLock 다른 process 간) — P+.

Risks / notes

  • patch-and-merge 가 더 효율적이지만 RRF normalization 이 hit set 전체 기준 (2/(k+1)) 이라 incremental 어려움. 우선 단순 LRU 가 도그푸딩 막힘 해결.
  • index_version 신규 — versioning cascade (§9) 에 새 차원 추가. 기존 5 개 (parser/chunker/embedding/prompt_template/index 그 자체 의미 다름) 와 구분 필요. 명확화 작업이 spec 갱신 동반.