New workspace member crate `kb-store-sqlite` (allowed deps only:
kb-core, kb-config, rusqlite[bundled], refinery, serde, serde_json,
time, blake3, tracing, anyhow, thiserror; dev-deps add kb-parse-md /
kb-normalize / kb-chunk for the contract round-trip test).
Migration V001 replaces the P0-1 stub with the full §5 DDL (assets,
documents, document_tags, blocks, chunks with policy_hash,
embedding_records, jobs, ingest_runs, answers, eval_runs,
eval_query_results) plus the §5 indexes. FTS5 virtual table + triggers
remain deferred to V002 (P2-1).
Public surface per task spec:
SqliteStore::open / run_migrations / put_asset_with_bytes
impl DocumentStore for SqliteStore (7 trait methods)
impl JobRepo for SqliteStore (4 trait methods)
StoreError { Sqlx, Migration, Conflict }
Behavior:
- Pragmas at open: foreign_keys=ON, journal_mode=WAL,
synchronous=NORMAL, temp_store=MEMORY.
- Asset writer: byte_len ≤ copy_threshold_mb * 1MiB → copy to
data_dir/assets/<aa>/<asset_id> (mode 0o644 on Unix), else
reference. blake3(bytes) verified against asset.checksum; mismatch →
Conflict.
- Idempotency: put_document UPSERTs and bumps doc_version + 1 on
conflict; put_blocks / put_chunks DELETE-then-INSERT; document_tags
re-derived per put_document.
- get_document rehydrates blocks via payload_json ordered by stream
ordinal.
- list_documents builds dynamic WHERE from DocFilter (lang / trust_min
/ path_glob via GLOB / tags_any via document_tags subquery).
- JobRepo: jobs.kind/status are stored as lowercase enum tags; create
mints a 32-hex JobId via blake3(kind || payload || nanos).
Tests follow in subsequent commits.
36 lines
1.4 KiB
TOML
36 lines
1.4 KiB
TOML
[package]
|
|
name = "kb-store-sqlite"
|
|
version = { workspace = true }
|
|
edition = { workspace = true }
|
|
rust-version = { workspace = true }
|
|
license = { workspace = true }
|
|
repository = { workspace = true }
|
|
description = "SQLite-backed DocumentStore + JobRepo for kb (§5 DDL, §7.2 traits)"
|
|
|
|
[dependencies]
|
|
kb-core = { path = "../kb-core" }
|
|
kb-config = { path = "../kb-config" }
|
|
# `bundled` ships SQLite source + builds in-tree (no system libsqlite3).
|
|
# Explicitly NOT `bundled-sqlcipher` per task allowed-deps list.
|
|
rusqlite = { version = "0.32", features = ["bundled"] }
|
|
refinery = { version = "0.8", features = ["rusqlite"] }
|
|
serde = { workspace = true }
|
|
serde_json = { workspace = true }
|
|
time = { workspace = true }
|
|
blake3 = { workspace = true }
|
|
tracing = { workspace = true }
|
|
anyhow = { workspace = true }
|
|
thiserror = { workspace = true }
|
|
|
|
[dev-dependencies]
|
|
tempfile = "3"
|
|
serde_json = { workspace = true }
|
|
# kb-parse-md / kb-normalize / kb-chunk are dev-only — used to build a
|
|
# CanonicalDocument + Vec<Chunk> from a fixture in the contract round-trip
|
|
# test. Forbidden as regular deps per design §8 (store consumes domain
|
|
# types from kb-core only); `cargo tree -p kb-store-sqlite --depth 1`
|
|
# (default scope, excludes dev-deps) confirms this.
|
|
kb-parse-md = { path = "../kb-parse-md" }
|
|
kb-normalize = { path = "../kb-normalize" }
|
|
kb-chunk = { path = "../kb-chunk" }
|