Skip to main content

urna_runtime/
lib.rs

1//! mmap-backed runtime for `.urna` files.
2//!
3//! Owns the mmap so `MmapUrnaFile` is `'static`. Section metadata is parsed
4//! once at open time using `UrnaView`, then the mmap is moved into `Self`
5//! and embeddings are read directly from `&self._mmap[offset..]`.
6//!
7//! Supports float32 / float16 / int8 dtypes with a SIMD dispatcher
8//! (AVX2 / NEON / scalar). Optional ANN (`hnsw`) and lexical (`bm25`)
9//! sections rerank into the exact cosine path so the final score is
10//! always the real cosine value.
11
12pub mod ann;
13mod blobs;
14pub mod bm25;
15mod dtype;
16pub mod error;
17pub mod graph;
18mod inspect;
19mod materialize;
20mod mmap_cold;
21mod mmap_file;
22mod order;
23mod rerank;
24mod search;
25pub mod simd;
26mod space_search;
27mod spaces;
28
29pub use dtype::DType;
30pub use error::RuntimeError;
31pub use mmap_file::MmapUrnaFile;
32pub use simd::SimdBackend;
33
34#[derive(Clone, Debug, PartialEq)]
35pub struct SearchHit {
36    pub chunk_id: String,
37    pub score: f32,
38    pub score_type: &'static str,
39    pub source_uri: String,
40    pub offset_start: u64,
41    pub offset_end: u64,
42    pub embedding_model: String,
43    pub index_type: &'static str,
44    pub reranked: bool,
45    pub file_hash: String,
46    pub content_hash: String,
47    pub citation_id: String,
48}
49
50/// What precision the mandatory exact-cosine rerank read its vectors from.
51/// the honesty backbone of `--disclose explain` and `retrieve()`: every
52/// returned `score` IS a real cosine, but at WHICH precision depends on
53/// whether a full-precision `embeddings_fp` (0x09) slab is present.
54///
55/// - `FullPrecision`: a 0x09 fp slab is present (or the stored dtype is
56///   float32), so the rerank read full-precision vectors. "real cosine".
57/// - `StoredPrecision`: no fp slab and the stored dtype is lossy
58///   (float16/int8/int4), so the rerank read the stored quantized slab.
59///   "real cosine at stored precision". still a real recomputed cosine,
60///   never a candidate-generator proxy, but at the on-disk precision.
61///
62/// this enum is computed in the runtime from
63/// `embeddings_fp_slab().is_some()` + the stored dtype and never lies: a
64/// sub-int8 corpus without an fp source reports `StoredPrecision`, so a
65/// newcomer is never shown a stored-precision number as full-precision.
66#[derive(Clone, Copy, Debug, PartialEq, Eq)]
67pub enum RerankSourceKind {
68    /// score recomputed against a full-precision source (0x09 fp slab, or
69    /// the stored slab when the stored dtype is already float32).
70    FullPrecision,
71    /// score recomputed against the lossy stored slab (float16/int8/int4),
72    /// no fp source present. disclosed as "real cosine at stored precision".
73    StoredPrecision,
74}
75
76impl RerankSourceKind {
77    /// classify the precision the rerank reads from by its effective dtype
78    /// (the 0x09 fp slab's dtype when present, else the stored dtype). only
79    /// float32 is full-precision; float16/int8/int4 are stored-precision.
80    /// this is the single source of the honesty marker.
81    pub fn from_dtype(dtype: DType) -> Self {
82        match dtype {
83            DType::Float32 => Self::FullPrecision,
84            DType::Float16 | DType::Int8 | DType::Int4 => Self::StoredPrecision,
85        }
86    }
87
88    /// the one-line honesty marker for `--disclose explain` / `retrieve()`.
89    pub fn disclosure(self) -> &'static str {
90        match self {
91            Self::FullPrecision => "real cosine",
92            Self::StoredPrecision => "real cosine at stored precision",
93        }
94    }
95    /// stable machine token for the json answer-pack / SearchExplain.
96    pub fn as_str(self) -> &'static str {
97        match self {
98            Self::FullPrecision => "full_precision",
99            Self::StoredPrecision => "stored_precision",
100        }
101    }
102}
103
104/// ADDITIVE per-search provenance, attached to every `SearchResult`. zero
105/// format bytes, no `URNA_FORMAT_VERSION` bump: it is computed entirely in
106/// the runtime from the search path and the open file. feeds the lens
107/// `--disclose explain` honesty line and the agent-native `retrieve()`
108/// answer-pack. the load-bearing field is `rerank_source`.
109///
110/// candidate counts are the per-path candidate-set sizes the rerank saw
111/// (0 when that path did not run). `recall_estimate` is `1.0` only on the
112/// exact path (the recall=1.0 ground truth) and `NaN` on every candidate-
113/// generating path (ann/hybrid/graph), mirroring `SearchResult::recall`:
114/// we never claim a recall we did not measure.
115#[derive(Clone, Copy, Debug, PartialEq)]
116pub struct SearchExplain {
117    /// the route taken: "exact" | "hnsw" | "graph" | "hybrid".
118    pub route: &'static str,
119    /// exact-flat candidates considered (the whole corpus on the exact path
120    /// and the graph seed path; 0 when the path used an ann shortlist).
121    pub exact_candidates: usize,
122    /// ann shortlist size (hnsw / hybrid vector path); 0 otherwise.
123    pub ann_candidates: usize,
124    /// bm25 lexical shortlist size (hybrid path); 0 otherwise.
125    pub bm25_candidates: usize,
126    /// graph bfs frontier union size (graph path); 0 otherwise.
127    pub graph_candidates: usize,
128    /// how the candidate lists were combined: "none" | "rrf".
129    pub fusion_mode: &'static str,
130    /// the precision the mandatory exact rerank read from. the honesty
131    /// backbone: see `RerankSourceKind`.
132    pub rerank_source: RerankSourceKind,
133    /// `1.0` on the exact path, `NaN` on every candidate-generating path
134    /// (we never claim a recall we did not measure).
135    pub recall_estimate: f32,
136}
137
138impl SearchExplain {
139    /// the exact-flat path: the whole corpus scored, recall=1.0 ground
140    /// truth, no fusion.
141    pub(crate) fn exact(n: usize, src: RerankSourceKind) -> Self {
142        Self {
143            route: "exact",
144            exact_candidates: n,
145            ann_candidates: 0,
146            bm25_candidates: 0,
147            graph_candidates: 0,
148            fusion_mode: "none",
149            rerank_source: src,
150            recall_estimate: 1.0,
151        }
152    }
153
154    /// the hnsw path: an ann shortlist into the exact rerank, recall=NaN.
155    pub(crate) fn hnsw(ann: usize, src: RerankSourceKind) -> Self {
156        Self {
157            route: "hnsw",
158            exact_candidates: 0,
159            ann_candidates: ann,
160            bm25_candidates: 0,
161            graph_candidates: 0,
162            fusion_mode: "none",
163            rerank_source: src,
164            recall_estimate: f32::NAN,
165        }
166    }
167
168    /// the graph path: exact-cosine top-ef seed, bfs frontier union into
169    /// the exact rerank, recall=NaN.
170    pub(crate) fn graph(seed: usize, frontier: usize, src: RerankSourceKind) -> Self {
171        Self {
172            route: "graph",
173            exact_candidates: seed,
174            ann_candidates: 0,
175            bm25_candidates: 0,
176            graph_candidates: frontier,
177            fusion_mode: "none",
178            rerank_source: src,
179            recall_estimate: f32::NAN,
180        }
181    }
182
183    /// the hybrid path: vector (ann or exact) ∪ bm25, rrf fusion into the
184    /// exact rerank, recall=NaN.
185    pub(crate) fn hybrid(ann: usize, exact: usize, bm25: usize, src: RerankSourceKind) -> Self {
186        Self {
187            route: "hybrid",
188            exact_candidates: exact,
189            ann_candidates: ann,
190            bm25_candidates: bm25,
191            graph_candidates: 0,
192            fusion_mode: "rrf",
193            rerank_source: src,
194            recall_estimate: f32::NAN,
195        }
196    }
197}
198
199#[derive(Clone, Debug, PartialEq)]
200pub struct SearchResult {
201    pub hits: Vec<SearchHit>,
202    pub query_time_ms: f64,
203    pub index_type: &'static str,
204    pub recall: f32,
205    pub truncated: bool,
206    pub k_requested: i32,
207    pub k_returned: usize,
208    /// ADDITIVE per-search provenance (route, candidate counts, fusion
209    /// mode, rerank-source honesty marker, recall estimate). no format
210    /// bytes; computed in the runtime. see `SearchExplain`.
211    pub explain: SearchExplain,
212}