An embedding model defines a space. Every point in that space is a vector, and nearness in the space is supposed to mean similarity of meaning.
Change the model and you have a different space. Change the revision, the quantisation, the pooling strategy, the normalisation, the instruction prefixes or the dimension, and you have a different space too. The vectors may still have the same length; they no longer mean the same thing.
This is a quiet failure mode, and it is worth understanding why.
The failure does not raise
If you store vectors from model A and query with model B, cosine similarity returns a number. It will be between -1 and 1. It will look completely normal. It will be meaningless.
Nothing crashes. No test fails, because nothing in the code is wrong by the standards of the code: the arithmetic is correct, the query runs, the results come back ranked. They are ranked by a comparison across two unrelated coordinate systems.
The usual defences are procedural. Add a column recording which model produced each vector. Write a check that filters by it. Remember to run the check. Migrate the whole library when the model changes, and hope no notebook was missed.
Procedural defences are exactly the kind that erode, especially in a tool that has to work correctly on a machine nobody is watching.
The structural fix
KnowNote derives an identity for the embedding configuration from the backend, model, revision, dtype, pooling, normalisation, prefixes and dimensions. Each notebook gets its own vector table, carrying that table’s own width.
The consequence is that there is nowhere for a cross-space comparison to happen. Two notebooks with different embedding configurations do not share a table, so a query cannot reach across them. The comparison is not prevented by a check; it is prevented by the absence of a place to do it.
The width part matters separately. Vector columns have a fixed dimension, so a set of tables with different widths is not an inconvenience — it is the schema telling you that these are different kinds of thing.
Why per notebook rather than one table everywhere
Because a notebook is already the unit of context. Retrieval never ranges outside it, so per-notebook tables add no complexity to the query path and give a natural boundary for the embedding identity.
It also means a model upgrade can be incremental. Rebuild one notebook, leave the others alone, and the library does not need a migration window.
The general lesson
When two pieces of data are only meaningful together, prefer a schema that makes them inseparable over a rule that keeps them in step. Rules are remembered by people, and people are not always there. The design of a personal, local tool has to assume that nobody is watching, because that is the entire premise.