Skip to content

Harden embedding: atomic model switch, consistent vectors, downloads - #204

Merged
ppXD merged 1 commit into
mainfrom
fix/embed-stability
Jun 9, 2026
Merged

ppXD merged 1 commit into
mainfrom
fix/embed-stability

Conversation

@ppXD

@ppXD ppXD commented Jun 9, 2026

Copy link
Copy Markdown
Owner

Summary

A stability review of the local notes-embedding feature surfaced several ways it could silently degrade. This hardens them:

  • Atomic model switch. reindex_all now clears + rebuilds chunks in a single transaction — the DELETE FROM chunk previously committed before embedding, so a mid-embed failure wiped the index for good. New set_embedder_and_reindex reverts to the previous embedder on any failure, and apply_embedding_model surfaces the error instead of swallowing it. A failed switch now leaves the previous model + index exactly as they were, rather than a new embedder pointed at stale-dimension vectors or a silently-emptied index.
  • Consistent vectors. Embed passages one at a time. A quantized model's per-batch scales made a batched passage drift from the same text embedded alone (verified cos 0.965), so a stored vector wouldn't match a single-text query and two notes indexed the same sentence differently. One-at-a-time keeps every vector identical regardless of its batch.
  • Download integrity. Validate the body length against Content-Length, so a truncated transfer errors + removes its .part instead of renaming a short file into place (which then fails to load on every retry, since the present short file is skipped).
  • Fail loudly on a zero-length tokenizer encoding instead of emitting an all-zero "embedding".

Test plan

  • wisp-library (CI-gated): new regression test a_failed_model_switch_keeps_the_old_index_and_embedder proves a failing embedder neither wipes the corpus nor activates — the previous embedder + chunks survive. Full suite 38/38.
  • wisp-embed (--ignored, real models): new qwen3_passage_embedding_is_independent_of_neighbours proves a passage embeds identically alone vs. alongside others on real Qwen3 (was cos 0.965 batched, now > 0.999); encoder (BGE-M3, GTE) + decoder ranking smoke tests still pass. 20 unit tests pass.
  • cargo clippy -D warnings clean on wisp-embed, wisp-library, and the app; tauri dev rebuilds + runs.

A stability review of the local-embedding feature surfaced several ways
it could silently degrade. Fix them:

- Atomic model switch: reindex_all clears + rebuilds chunks in one
  transaction (the DELETE used to commit before embedding, so a mid-embed
  failure wiped the index for good), and set_embedder_and_reindex reverts
  to the previous model on any failure. apply_embedding_model surfaces the
  error instead of swallowing it, so a failed switch never leaves a new
  embedder pointed at stale-dimension vectors or a silently-empty index.
- Consistent vectors: embed passages one at a time. A quantized model's
  per-batch scales made a batched passage drift from the same text
  embedded alone (verified cos 0.965), so stored vectors did not match
  single-text queries; one-at-a-time keeps every vector identical.
- Download integrity: validate the body length against Content-Length, so
  a truncated transfer errors and cleans up instead of renaming a short
  file into place (which then fails to load on every retry).
- Fail loudly on a zero-length tokenizer encoding instead of emitting an
  all-zero embedding.
@ppXD
ppXD force-pushed the fix/embed-stability branch from 49196a5 to 28f9768 Compare June 9, 2026 07:29
@ppXD
ppXD merged commit 9328767 into main Jun 9, 2026
6 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant