CortexDB 0.9.12
Two things a pilot asked for by name: you can see what the pipeline costs, and you can change embedding model on a corpus you already have.
Before you upgrade
Nothing here changes a contract. If you are on v0.9.11 there are no new upgrade notes. If you are further back, read the v0.9.10 notes first — scope types are validated when a scope is created, and an explicitly configured embedding endpoint with no credential is a boot refusal rather than a silent fallback to meaningless vectors.
Durable token and cost accounting
GET /v1/admin/usage reports tokens and dollars per pipeline role — embeddings,
entity extraction, enrichment, recall, answer, verifier and the background
maintenance lanes — and the numbers SURVIVE A RESTART. One bucket per UTC day,
role, tenant and model, so summing a range answers month-to-date or
since-pilot-start. ?format=csv exports the same buckets flat.
The counter that existed before this release reset to zero on every restart, because it had only ever been process memory. There was no record to lose. Historical spend from before you upgrade cannot be reconstructed, and no estimate here will pretend otherwise.
Read by_role_model, not just the totals. It carries exact token counts beside
the model name, which is what lets you recompute dollars at a corrected rate, or
at your own rate if you bring your own model, without re-running anything. Cost
is a view over the durable record; the tokens are the durable record.
Three fields exist so the report cannot flatter itself:
unpriced_calls: this build has no rate for that model. The tokens are exact, the dollars are zero, and zero here means unmeasured rather than free. Set CORTEX_MODEL_PRICES to give it a rate.tokens_unsplit: a provider that reported one combined number instead of an input/output split. Kept separate on purpose: pricing it at an output rate overstates that lane several-fold.incomplete_calls: while non-zero, the token fields are a floor.
Two roles are declared uninstrumented rather than quietly read as zero: four calls inside the answer path discard their usage before it can be recorded, and the reranker's interface carries no token or cost data at all (its provider also bills per search unit rather than per token). Both say so in the payload.
Pricing itself was wrong before this release and is worth re-reading if you quoted it. The enrichment lane billed every model at the cheapest model's rate — roughly seventeen times understated if you run gpt-4o there — and anything whose name contained "opus" was billed at the 4.0 rate, roughly three times overstated for claude-opus-4-6. An unrecognised model silently took sonnet's price. One price book now serves every lane, and an unknown model is reported rather than guessed.
In-place embedding migration
Changing embedding dimensions on an existing data directory used to be a hard
boot refusal with no way forward except exporting and re-importing into a fresh
store. CORTEX_EMBEDDING_REBUILD_VECTORS=1 now authorizes exactly one
drop-and-rebuild: the vector indexes whose width no longer matches are dropped
and recreated empty at the new width, and the store reports itself incomplete
until refilled.
Read docs/EMBEDDING_MIGRATION_RUNBOOK.md before using it. The honest cost:
vector recall returns nothing between the drop and the refill, BM25 only, for as
long as your corpus takes.
The safety properties, stated because this destroys data on purpose:
- It is never automatic. An unattended dimension mismatch — a config typo, a model renamed upstream — still refuses to boot, exactly as before.
- It takes two deliberate flags. The repin flag and the rebuild flag are separate, and the destructive one cannot act without the other.
- It is spent after one use. A flag left in a unit file authorizes nothing on the next boot.
- It will not drop a real corpus for mock embeddings. That is what a lost embedding credential looks like, and it is refused with the data untouched.
- A refused boot now leaves the data directory byte-identical. Previously a failed attempt rewrote the pin first, so the store could no longer boot on its own correct configuration without a second override.
The index audit reports all four vector families on every call, not just chunks. It can no longer answer "clean" over a store whose entity or derived vector spaces are empty. It also states plainly that its repair rebuilds EVENT chunks only: enrichment writes fact, triple and summary vectors into the same index and the audit does not re-derive those, so a clean chunk audit means "every event has its chunk vector", not "this index is whole".
Also
The reranker can point at an endpoint you control (CORTEX_RERANKER_URL).
Clients
Unchanged from v0.9.11: cortexdbai 0.11.2 on PyPI and 0.9.3 on npm, cortexdb-connectors 0.2.21, cortexdb-mcp 0.7.5, cortexdb-cli 0.5.4.
Notes
Single-node remains the only supported topology.
POST /v1/experience?wait=settled is still accepted but cannot succeed and
returns 503 SETTLEMENT_UNAVAILABLE. Use wait=indexed.
The online re-embed job — a route pair with a dry-run cost estimate, dual-embed of writes landing during the job, and an atomic swap with no offline window — is designed and not built. This release is the offline path.