Repository navigation
fix(kb): stop marking every embedded row null in the vector column - #13
Merged
Merged
Conversation
`build_embedding_array` fed `entry.is_none()` into Arrow's validity bitmap, but that bitmap is `true` = VALID. The mapping was inverted, so every successfully embedded row was stored behind a null mask and every unembedded row was marked valid. Nothing surfaced the fault: `kb build` reported the full `embedded` count, the schema carried `fixed_size_list<float>[dim]`, and `embedding_model` was stamped correctly -- while `kb query` returned `cosine: null` on every hit, because `row_vector` reads through the mask, finds nothing at row 0, and skips embedding the query entirely. The result was a silent permanent fall back to lexical ranking on a collection that had embedded cleanly. Also pad the values buffer for null slots. A FixedSizeListArray indexes its values by position, so a partially embedded collection previously shifted every row after the first gap. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
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.
The bug
build_embedding_arrayinsrc/kb.rsfedentry.is_none()into Arrow'svalidity bitmap. That bitmap is
true= VALID, so the mapping wasinverted: every successfully embedded row was stored behind a null mask, and
every unembedded row was marked valid.
This is pre-existing and independent of #12, which touched
embed.rs,config.rs,node_rows.rsandexport.rsbut neversrc/kb.rs. #12 did notintroduce it; it is simply what you hit next once the encoder width became
configurable and
kb buildactually produced vectors.Why it never surfaced
Every observable signal said the collection was embedded:
kb buildreported the full count —embedded: 67of 67 rowslexical_only: falsefixed_size_list<item: float>[768]with the right widthembedding_modelwas stamped correctly on every row...while
kb queryreturned"cosine": nullon every hit. Anyone reading thebuild output would conclude vector search was working.
row_vectorreadsthrough the null mask, finds nothing at row 0, and the
if row_vector(&batch, 0).is_some()guard then skips embedding the queryentirely — so the encoder was never even contacted at query time.
The result is a silent, permanent fall back to lexical ranking on a collection
that embedded cleanly. That invisibility is the main argument for the
regression test added here. Confirmed by reading the stored IPC stream
directly:
This is write-side only, so a binary with the fix reads an old store fine, but
re-running
kb buildon an unfixed binary reproduces the null vectors.The fix
entry.is_some()into the validity bitmap.dimzeros for null slots. AFixedSizeListArrayindexes its values by position, so a partially embeddedcollection previously shifted every row after the first gap.
Before / after
Same collection, same query —
"how are silver models tested"— against alocal
google/embeddinggemma-2encoder at 768-d.Before (vectors present but masked null, so lexical only):
nulldbt/STYLE_GUIDE.mdnulldocs/ADF_DEPLOY_DESIGN.md > Known gapsnulldbt/STYLE_GUIDE.md > Layersnulldbt/STYLE_GUIDE.md > Project configurationAfter:
lean/README.md— EdpMedallionProofsdbt/STYLE_GUIDE.md > Project configurationdbt/STYLE_GUIDE.mddbt/STYLE_GUIDE.md > **Silver layer**Lexical matched on "models"/"style" and returned three slices of the same
style guide, none of them about testing. The vector arm surfaces the Silver
layer section — the highest cosine of the four — and the Lean medallion
proofs, neither of which lexical ranked at all.
Verification
Regression test
kb::embedding_array_marks_embedded_rows_validcovers bothhalves: the validity of embedded vs unembedded rows, and that a null slot does
not shift the row after it. It fails on the previous implementation.
Full suite green (555 lib tests + all integration targets),
cargo fmt --checkandcargo clippy --all-targetsclean.Post-fix store:
Related but not fixed here, worth its own issue:
kb buildstampsembedding_modelinto the collection meta even whenembedded == 0, whichmakes a lexical-only collection look embedded.
🤖 Generated with Claude Code