ITER-0003B: index wiring & ranking equivalence - #15
Merged
Conversation
nnunley
force-pushed
the
index-wiring
branch
2 times, most recently
from
June 8, 2026 02:25
318cbdf to
3f1bfdb
Compare
… (STORY-0096) ITER-0001 dependency hygiene per the usage-site rule: the leit_wind_tunnel harness uses only rapidhash in its library surface; leit_core/leit_index/ leit_text are used solely by its #[cfg(test)] integration tests, so they move to [dev-dependencies] and no longer appear in the harness's production dependency graph. The bench crates were already correct (empty lib; all deps dev). Library build, 17 unit tests, and both bench crates verified green.
… (STORY-0112) ITER-0001: BlockId, FilterExprId, SegmentOrd, SegmentLocalDocId in leit_core, each a #[repr(transparent)] newtype over a [u8; 4] little-endian inner deriving bytemuck Pod/Zeroable. The on-disk form is the in-memory form: a &[u8] slice from an mmap'd buffer casts in place to &[Id] with no allocation or deserialization (zero-copy), stable across host endianness; ordering is numeric. bytemuck chosen over zerocopy because zerocopy's derives emit internal #[allow(non_ascii_idents)]/#[allow(non_local_definitions)] that conflict with the workspace's forbid-level Linebender lints (E0453); bytemuck is no_std and lint-clean under the same forbid set. Proven by SCENARIO-0005 (6 unit tests: value + slice + unaligned round-trip, numeric ordering, LE byte layout).
Records the design-decidable decisions for the Phase 2 segment format (DEC-01..10) with rationale, a Phase 3 forward-compatibility audit, and decision->enforcement traceability. Human-confirmed key calls: - DEC-01 segment offsets: u64 (no size cap; removes the only Phase 3 format-migration risk) - DEC-10 integrity: single footer checksum, verified in Full validation mode - DEC-06 block-aware API: public dedicated BlockCursor trait (Phase 3 WAND consumes it without a format/API break) - DEC-05 header: fixed-layout little-endian POD, absolute u64 section offsets, magic + version + format_flags, reserved stored-fields/columnar slots Decision-documentation ACs of STORY-0078/0081-0084/0090/0043-0047 are satisfied here (decided:ITER-0001); their code-enforcement ACs are deferred to ITER-0003/0004. Forward constraint recorded for ITER-0005: block-metadata schema must carry per-block max_score + doc-range for Phase 3 WAND/MaxScore.
…ORY-0112 AC-2) ITER-0001 audit corrective: SCENARIO-0005 now also exercises try_from_bytes/ try_cast_slice (Ok on well-formed, Err on malformed) per AC-2's validated-read obligation.
…elta) [ITER-0002] Codec layer for ITER-0002. A Codec trait with two implementations over a stable v1 block format, plus the layout decisions (DEC-11 fixed 128-doc blocks, DEC-12 layout) and a new TermFreq segment-resident type. - DeltaVarint (CodecId 0) + BlockDelta (CodecId 1, 128-doc independently-decodable blocks with validated first/last-doc header range). - Hand-rolled LEB128 varint into a type-enforced [u8;5]; no_std + alloc; no new deps. - API speaks named segment-resident types SegmentLocalDocId + TermFreq (no anonymous u32 drift); EntityId stays the in-memory abstraction, lowered at the segment boundary. - Decode into caller-provided &mut Vec<..> — scratch-ownership-agnostic (TODO(ITER-0003) / STORY-0079). Doc-sorted precondition enforced via checked_sub (deterministic panic). - CodecId marker per list; segment-format reservation deferred:ITER-0004. Stories: STORY-0002/0003/0004/0005(AC1-2)/0009 done; STORY-0087/0088 decided. Proof: SCENARIO-0006 (36 leit_postings tests). PAR spec + quality reviewed. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ER-0002 T6-T7] SCENARIO-0070 (process-level): Criterion benchmark comparing DeltaVarint vs BlockDelta over the deterministic wind-tunnel corpus (1K/10K, multi-field, Zipfian). Measures encode time, decode time, and compressed size vs the 8-byte/posting baseline, with a lossless sanity gate. Baseline: DeltaVarint ~25%, BlockDelta ~26-27% of uncompressed; DeltaVarint decode ~4-11% faster. - crates/leit_wind_tunnel_index/benches/codec_compare.rs (+ [[bench]], leit_postings/ leit_core dev-deps). Criterion stays out of all primary crates (SCENARIO-0061/0069 pass). - leit_index: PostingEntry made public + InMemoryIndex::postings_by_term() accessor, the minimal surface needed to extract doc-sorted (SegmentLocalDocId, TermFreq) postings (lowering stands in for the ITER-0004 segment-write boundary). - docs/2026-05-30-codec-tradeoffs.md — STORY-0006 AC-3 decode-cost vs memory guidance. Stories: STORY-0006 (benchmark + guidance). Proof: SCENARIO-0070. PAR reviewed. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ons [ITER-0003 T1] DEC-13: workspace-borrowed DecodeScratch (resolves TODO at codec.rs:153). DEC-14: layered cursor capabilities (DocCursor/TfCursor/BlockCursor; positions deferred). STORY-0079/0080/0089 decision ACs.
leit_postings cursor module over the ITER-0002 codec: - CursorStatus, DecodeScratch (workspace-borrowed, DEC-13), BlockSummary, PostingsView (borrowed view; decoupled from segment BlockMeta, TODO(ITER-0005) for sidecar lowering) - Layered DocCursor(current_doc/advance/advance_to)/TfCursor/BlockCursor (DEC-14) - CompressedCursor over decode_any; advance_to via binary search, never backward - CursorFactory (codec-agnostic) + BlockDecoder (real per-block decode for BlockDelta) - ScoreBound; block-aware API surface only (STORY-0024 AC-2 execution deferred Phase3; STORY-0081 AC-2 boundary) - 11 cursor tests (SCENARIO-0034/0035/0036/0038/0039/0041/0042/0043 + block API contract 0002/0009) - clippy clean (host + no_std aarch64-unknown-none), fmt clean
…iliation [ITER-0003 T7-T8] T7: allocation-evidence tests — scratch_reuse_no_realloc (SCENARIO-0039/0019/0024), hot_path_capacity_stable_and_cursor_small (SCENARIO-0040), and the empty-summaries conservative-default contract test (PAR B finding). T8: forward-extensibility module doc (STORY-0010); reconciled the legacy generic in-memory cursor traits with the canonical cursor:: API — InMemoryCursor methods are now inherent, the three colliding generic traits removed, canonical cursor traits re-exported at the crate root. Updated property_invariants.rs + phase1_readiness.rs consumers. clippy clean (host + no_std); workspace tests green.
…rsor [ITER-0003B T1] Add leit_index -> leit_postings dependency, record DEC-15 (dual cursor sources behind one trait-based executor: zero-copy in-memory cursor for the default path, CompressedCursor for the equivalence proof), and implement MemPostingsCursor — a zero-copy DocCursor+TfCursor over &[PostingEntry], semantically interchangeable with CompressedCursor. 11 cursor unit tests.
…0003B T2] Refactor InMemoryIndex term scoring into a single TfCursor-generic helper (score_via_cursor) driven by MemPostingsCursor on the default in-memory path, replacing direct Vec<PostingEntry> iteration in eval_term and collect_term. Block-level pruning, scoring math, and execution stats are byte-identical; the helper is generic over TfCursor so T3 reuses it with CompressedCursor. All leit_index + leit_integration_tests stay green (non-regression).
…6 [ITER-0003B T3] Thread a CursorSource selector through evaluate_plan_with_source -> evaluate_node_with_source -> eval_term_with_source so the compressed path (PostingsView + DecodeScratch + CompressedCursor over DeltaVarint/BlockDelta encoded postings) is a real execution path; existing callers default to InMemory (non-regression). SCENARIO-0026 integration test proves byte-identical ordered top-k across in-memory, DeltaVarint, and BlockDelta sources over single-term/AND/fielded queries, incl. a >128-posting term (multi-block decode). Closes STORY-0008 umbrella + STORY-0088 AC-2.
…TER-0003B T4] Add SCENARIO-0010 (STORY-0005 AC-3): a BlockDecoder::decode_block test proving partial postings retrieval decodes only the target block of a multi-block BlockDelta list (not the full list, no docs from earlier blocks). Lazy cursor-driven skip-during-decode is Phase 3 (CompressedCursor decodes eagerly). Iteration wrap-up: SCENARIO-0001/0015 mapped to the SCENARIO-0026 harness, STORY-0001 AC-2 to the existing BlockCursor API; EPIC-001 19/19.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
ITER-0003B — Index wiring & ranking equivalence
The cross-crate integration the cursor architecture exists for: routes
leit_indexquery execution through the ITER-0003leit_postingscursor API and proves the compressed-postings path ranks identically to the uncompressed path.Delivers:
leit_index → leit_postingsdependencyleit_postings::cursor::TfCursor(score_via_cursor+score_doc_tf);eval_term/collect_termnow traverse via a cursor instead of iteratingVec<PostingEntry>directlyMemPostingsCursor(no encode/decode, non-regressing), while aCursorSource::Compressedpath threadsPostingsView+DecodeScratch+CompressedCursorthroughevaluate_plan_with_sourceas a real, runnable execution source. This keeps the in-memory path off any decode-per-query regression; ITER-0004 will feed segment bytes into the samePostingsViewsource without rework.Evidence:
(doc_id, score)top-k across the in-memory, DeltaVarint, and BlockDelta sources over single-term / AND / fielded queries.BlockDecoderselective block decode (partial retrieval decodes only the relevant block).leit_index+leit_integration_testssuites stay green. clippy clean (host all-targets), fmt/copyright clean,leit_postingsno_std build OK.Closes the STORY-0008 codec umbrella and the STORY-0088 API-stability claim; EPIC-001 is now 19/19.
Lineage-stacked PR — based on
main; diff is cumulative over #10–#13 and #(ITER-0003) until ancestors merge. The ITER-0003B-specific work is theleit_indexcursor wiring + the SCENARIO-0026 equivalence test.