리뷰에서 나온 지적 중 실제로 고칠 값이 있는 4건 반영. 1) 압축 트리거를 인메모리 카운터 -> Lance 테이블 version 으로 `upserts_since_compact: AtomicU64` 는 store 인스턴스 수명 동안만 살아 있는데, `kebab ingest-file` 과 MCP `ingest_file`/`ingest_stdin` 은 호출마다 새 App(따라서 새 store)을 연다. 한 번에 수만 건 넣는 ingest 에서만 512 에 닿고, 한 건씩 넣는 경로에서는 카운터가 매번 0 으로 되돌아가 압축이 영영 안 돌았다 — PR 이 잡겠다던 fragment 누적이 그 경로에 그대로 남는 셈. Lance 의 `table.version()` 은 테이블에 저장돼 프로세스를 넘어 단조 증가 하므로 그걸 기준으로 바꿨다. 부수적으로 struct 에서 카운터 필드와 AtomicU64 import 가 사라졌다. 2) `--fail-under` -> `--max-drop` 관용적으로 `--fail-under 0.9` 는 "지표가 0.9 미만이면 실패" 로 읽히는데 실제 의미는 "0.9 이상 떨어지면 실패" 였다. 그대로 두면 CI 에 하한이라고 믿고 적은 값이 아무것도 안 막는다 — recall 0.95 -> 0.10 붕괴도 낙폭 0.85 < 0.9 라 통과. 새로 노출되는 표면이라 지금이 바꿀 수 있는 시점이다. 음수·nan 은 시작 시점에 거부한다(그대로 두면 게이트가 무력화됨). 3) `chrono` 직접 의존 제거 lancedb 가 `chrono::Duration` 을 이미 re-export 한다 (lancedb-0.23.1/src/table.rs:85). 앞 커밋이 Cargo.toml 에 적은 "lancedb 는 chrono 를 re-export 하지 않는다" 는 사실이 아니었다. 4) 안전성 근거 주석 정정 + 측정치 통일 `delete_unverified: true` 의 근거를 "kebab ingest 는 단일 동기 프로세스" 라고 단언했으나, 이 리포는 `kebab mcp` 를 preferred 통합 표면으로 배포하고 그 서버는 ingest 까지 노출한다. 락도 없다. 단언 대신 전제와 그 전제가 코드로 강제되지 않는다는 사실, 그리고 이 플래그 없이는 신규 색인에서 아무것도 회수되지 않는다는 trade-off 를 그대로 적었다. 압축 소요는 사본 측정치(102초) 대신 실 테이블 측정치(153초)로 통일. `is_multiple_of` 는 MSRV(1.85) 보다 높은 1.87 안정화라 `%` 로 대체. 검증: 워크스페이스 186 결과 전부 통과 · 실패 0. `--max-drop` 3경로 실증 (통과 exit 0 / 잘못된 값 exit 2 / 회귀 exit 1). 회귀 경로에서 "측정 불가" 가드가 실제 run 쌍으로 발동하는 것도 확인. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017c9JwQq8ZkGvYjpKXMiDhF
59 lines
2.5 KiB
TOML
59 lines
2.5 KiB
TOML
[package]
|
|
name = "kebab-store-vector"
|
|
version = { workspace = true }
|
|
edition = { workspace = true }
|
|
rust-version = { workspace = true }
|
|
license = { workspace = true }
|
|
repository = { workspace = true }
|
|
description = "LanceDB-backed VectorStore for kb (§5.6 embedding_records, §6.3 lancedb tables, §7.2 VectorStore)"
|
|
|
|
[dependencies]
|
|
kebab-core = { path = "../kebab-core" }
|
|
kebab-config = { path = "../kebab-config" }
|
|
# kb-store-sqlite is allowed for the embedding_records writers only
|
|
# (P3-3 spec: "Allowed dep `kb-store-sqlite` for writing/reading rows in
|
|
# embedding_records"). The Two-phase upsert flow uses
|
|
# `put_embedding_records_pending` + `mark_embedding_records_committed`.
|
|
kebab-store-sqlite = { path = "../kebab-store-sqlite" }
|
|
|
|
# LanceDB embedded vector store. `default-features=false` opts out of
|
|
# the cloud object-store integrations (aws / gcs / azure / dynamodb /
|
|
# oss); kb is always-local for v1, so dragging in those SDKs would just
|
|
# inflate the build.
|
|
lancedb = { workspace = true }
|
|
arrow = { workspace = true }
|
|
arrow-array = { workspace = true }
|
|
arrow-schema = { workspace = true }
|
|
# Embedded async runtime. The VectorStore trait is sync (§7.2) but
|
|
# LanceDB's Rust API is async-only; we own a current-thread
|
|
# tokio::Runtime and `block_on` per trait method. current-thread saves
|
|
# the two worker threads a multi-thread runtime would spawn — kb-app
|
|
# already serializes vector ops behind its own job scheduler so the
|
|
# extra parallelism wouldn't be exploited.
|
|
tokio = { workspace = true }
|
|
# `try_collect` for streaming Lance query results into a Vec<RecordBatch>.
|
|
futures = { workspace = true }
|
|
|
|
serde = { workspace = true }
|
|
serde_json = { workspace = true }
|
|
tracing = { workspace = true }
|
|
thiserror = { workspace = true }
|
|
anyhow = { workspace = true }
|
|
blake3 = { workspace = true }
|
|
time = { workspace = true }
|
|
|
|
[dev-dependencies]
|
|
tempfile = { workspace = true }
|
|
serde_json = { workspace = true }
|
|
# Integration tests seed `documents` / `chunks` fixtures by raw SQL
|
|
# (no kb-parse-md / kb-normalize / kb-chunk dep) so they can construct
|
|
# adversarial filter / dim-mismatch states. rusqlite is a `[dev-]`
|
|
# dep only — the runtime crate uses kb-store-sqlite's typed surface
|
|
# (`filter_chunks`, `put_embedding_records_pending`, …) and does not
|
|
# touch rusqlite directly (P3-3 spec: kb-store-vector must not list
|
|
# rusqlite/globset as direct deps).
|
|
rusqlite = { workspace = true }
|
|
|
|
[lints]
|
|
workspace = true
|