Skip to content

v7.73.0

Choose a tag to compare

@github-actions github-actions released this 07 Oct 18:16
· 2183 commits to main since this release
aa35ca6

Pairs with engine-service-v0.1.150 (tagged 2026-10-07 on c857a33; REQUIRED_ENGINE_VERSION moves from 0.1.149 to 0.1.150), the RDR-225 engine. All seven wire-ledger entries are [additive] (an old client against the new engine is safe), so the engine deploys to the cloud before this client tag. This release carries a one-way data migration. On a local install, the first engine start after the upgrade rewrites every vector into new tables (vectors-030-1), and that is IRREVERSIBLE: installing an older engine afterwards fails on the new layout. The abort criteria and what stands in for a rollback are in docs/runbooks/rdr-225-cloud-deploy.md § 8 (local installs) and § 6 (cloud). Before you upgrade, make sure the disk holding the Postgres data directory has free space of at least 2.2 times the size of the vector tables, and reindex or delete any collection whose chunk vectors do not match its embedding model's width: the walk fails on one, and no legacy shape is supported.

What proves it, and at what scale. The pre-tag --package-upgrade run is toy scale: it upgrades a container install holding one T1 scratch row and no chunks, so vectors-030-1 ran over an empty estate (new_changesets=3 reexecuted_changesets=12 pending_at_start=15, as predicted). The at-scale proof is conexus's point-in-time-recovery (PITR) fork walk of the production estate on 2026-10-07 (T2 nexus_rdr/225-rehearsal-2026-10-07): 434,617 chunks, 804 centroids, 4 tenants and 4 embedding models. The walk completed in 449 s (vectors-030-1 435.7 s), reconciled exactly per (embedding model, tenant) for chunks and centroids, left every referencing table unchanged and produced 32 leaves as predicted. No local install was walked at a measured scale: a local estate is far smaller, and the walk is exercised for it at fixture scale and by the disk preflight.

Added

  • Vector storage is partitioned by embedding model, then by tenant, so a search reads one leaf (nexus-3wh8d, RDR-225). nexus.chunks and nexus.taxonomy_centroids become LIST-partitioned tables: one partition per registered embedding model, one leaf per tenant under each. Every search family and the cardinality router's probe carry the collection's model and the session's tenant as explicit predicates, so the planner reaches one (model, tenant) leaf when it plans the statement, and planning cost no longer grows with the tenant count (the unpruned prototype took 47 ms at 302 tenants; the pinned tests read under 5 ms at 300). voyage-code-3 and voyage-context-3 are both 1024-dimensional and no longer share an HNSW index. Tenant isolation is a property of the partition tree as well as of row-level security, and the engine refuses to start when a model partition or leaf does not mirror its parent's policy. A new tenant's leaves are created when its first token is issued. It ships with engine-service-v0.1.150, the first tag that carries the vectors-030-1 and vectors-031 changesets (vectors-030-1 was held out of every earlier tag by scripts/check_release_holds.py), and this release moves REQUIRED_ENGINE_VERSION to it, so a local install receives the migration through the pin. At engine boot the schema migrator also re-mirrors partition access drift as the schema owner and logs a warning naming the relations (nexus-3wh8d.16).
  • nx doctor checks the partition layout (nexus-3wh8d.16). The RLS canary covers every model partition and leaf of both tables. Three new rows: Tenant partitions (a tenant that has a token but no leaf under a model partition, with the recovery SQL), Model partitions (a registered embedding model without a partition) and Partition leaves (the count). The rows read the database through local admin credentials, so they run on a local install and report "not applicable" on a managed one and on a box with no service yet; the cloud's equivalent is a read-only query in the deploy runbook.
  • Operator runbooks for the new layout (nexus-3wh8d.21, .26). docs/runbooks/rdr-225-cloud-deploy.md carries the pre-walk census, the predicted schema_migration_complete counts, the abort and rollback decision (read from the database, never from the absence of a log line), the post-boot VACUUM (ANALYZE) and the failure points after the walk commits. docs/runbooks/rdr-225-tenant-removal.md removes one tenant's leaves, referencing rows and tokens with nexus.drop_tenant_partitions, as the schema owner.

Changed

  • A local install's first start on an engine with vectors-030-1 migrates its vectors in one transaction, and there is no way back (nexus-3wh8d.8, .9). The walk rewrites every chunk and centroid into the partitioned tables and keeps the old tables as chunks_retired_225 and taxonomy_centroids_retired_225 as the only copy of the old layout; no changeset drops them yet, and the plan is a later engine that drops them after 14 days. A failed walk leaves the old layout and a stopped engine; a committed walk cannot be undone by installing an older engine, which fails on the new layout. Before the walk the engine checks free disk against 2.2 times the vector tables (an inferred figure, not a measured one) and refuses to start the walk, naming the shortfall. A chunk whose vector width disagrees with its collection's embedding model fails the walk, and no legacy data shape is supported: reindex or delete the collection first. The walk's progress lines (rdr225 ...) reach the engine log.
  • The engine refuses writes it cannot file under a model, and a combined search over two models (nexus-3wh8d.13, .15). A manifest write for a collection with no registry row answers 422 unregistered_collection where it used to answer 409 on a foreign-key failure; POST /v1/catalog/collections/rehome and /v1/chash/rename_collection answer 409 collection_model_mismatch for a cross-model move; a token insert whose leaf creation waits on a lock answers 503 tenant_creation_busy with Retry-After. POST /v1/vectors/search and /hybrid-search over collections whose registry models differ answer 400 instead of searching with the first collection's embedder. POST /v1/taxonomy/centroids/query with cross_collection matches centroids of the source collection's model only, and answers an empty list for a source with no registry row. Cross-collection projection (assign_from_chashes, cross-preview) likewise matches the chunk's own model. All are additive for the released client and are recorded in docs/wire-contract-pending.md.