Skip to content

v7.77.0

Choose a tag to compare

@github-actions github-actions released this 10 Oct 22:14
· 1910 commits to main since this release
e13b574

Pairs with engine-service-v0.1.159 (REQUIRED_ENGINE_VERSION moves from 0.1.156; v0.1.157 and v0.1.158 were deployed to the managed service and never pinned). Search recall and latency on large collections (RDR-227). A collection of 20,000 rows or more gets a partial HNSW index of its own, the engine searches it through that index, and nx doctor reports the indexes. A cold cloud search makes 9 requests where it made 66. The engine carries no schema change.

Added

  • Collections of 20,000 rows or more get their own HNSW index (RDR-227, nexus-43ulx; engine change, live in the cloud from engine-service-v0.1.158 and locally from this release). The shared index of a tenant's partition holds every collection, and a search filtered to one collection walked it and stopped at the first rows the filter admitted, so a full page could miss the collection's nearest rows (recall 0.925 at k=40 on a 27,893-row collection). The engine now builds one partial HNSW index per collection at or above NX_SEARCH_PCI_BUILD_MIN_ROWS (default 20000), with CREATE INDEX CONCURRENTLY, one at a time, and drops an index whose collection no longer qualifies. A reconciler counts collections and runs builds every NX_SEARCH_PCI_SWEEP_SECONDS (default 600); the first pass runs shortly after the engine starts. NX_SEARCH_PCI=0 turns building off, and NX_SEARCH_PCI_MAX_PER_LEAF (default 16) caps the indexes per tenant partition. Measured with its index, the same 27,893-row collection recalled 0.99 or better at k 40 to 120. A local install builds its indexes on the first engine start after the upgrade: about 13 s for 30,000 rows and 44 s for 60,000 at the bundle's settings. Writes into an indexed collection cost more, because each row enters two graphs: a 128-chunk batch took 1.8 to 1.9 times as long on the test host. See docs/configuration.md for the four settings.
  • nx doctor has a Per-collection indexes row (nexus-43ulx.24). It reads the new per_collection_indexes object on GET /v1/status and reports the valid and invalid index counts, the builder's state (ok, standby, off, auth_failed, no_privilege) and the age of the last build pass. It fails on a builder that cannot authenticate or lacks the privilege, and warns on an invalid index or an overdue pass. Against an engine without the object the row is not applicable.

Changed

  • The engine's exact-search threshold is 20,000 rows, down from 30,000 (nexus-43ulx.35; engine change, live in the cloud since 2026-10-10 and locally from this release). NX_SEARCH_EXACT_MAX_ROWS now defaults to the index build threshold, so a collection leaves the exact scan at the row count where it gets its own index. Measured on the managed service, the two code collections of 27,893 and 29,355 rows moved from exact scans of 0.6 to 0.9 s under fan-out to index searches of 25 to 50 ms, and the slowest statement of a default code search fell from about 800 ms to about 330 ms. A collection above 20,000 rows with no valid index of its own walks the shared index at hnsw.ef_search 1000 (new in engine-service-v0.1.157; it was the request-sized value). That applies between a collection crossing the threshold and the next build pass, and on an engine whose builder cannot run (no admin credentials, or a role without the privilege); it measured recall 0.975 at worst on the 27,893-row collection. NX_SEARCH_EXACT_MAX_ROWS=30000 restores the previous routing.
  • Search's topic grouping reads its labels in one request (nexus-w032x). A default search (the CLI's cluster_by="semantic") looked up every topic in the result window with its own GET /v1/taxonomy/topics/by_id: about 39 requests, 0.54 to 0.98 s on the managed service. New engine route POST /v1/taxonomy/topics/by_ids takes {"ids": [...]} (1 to 300 integers; anything else is a 400) and answers the same topic objects by_id returns, for the ids that exist under the tenant, in one statement; missing ids are omitted. HttpTaxonomyStore.get_labels_for_ids sends one request per 300 ids. Against an engine without the route (404, or the edge refusing the path) it remembers that for ten minutes and uses the pooled per-id path as before; a failing route is remembered for one minute. The route is in engine-service-v0.1.158 and later.
  • A cold nx search overlaps its start-up requests and no longer downloads vectors it discards (nexus-w032x). In cloud mode, when the corpus is given by prefix (the default), the routing listing starts beside the cloud version probe instead of after it (0.24 to 0.34 s each on the managed service). Its rows reach a caller only after the probe has passed, but the authenticated listing request is now sent before the probe has confirmed the endpoint is a nexus service. The display-path catalog lookup runs beside the topic grouping (0.15 to 0.17 s). And a default search asks the per-collection route for stored vectors only when there is no taxonomy to group by: they were up to 300 vectors per group, 1.05 to 1.46 MB on the code group, and unused whenever topic grouping fired. Same query with and without them: 4.89 s against 3.44 s, identical result ids.
  • The MCP search tool asks each collection for 40 candidates, not 60 or 120 (nexus-ann50). A deep page or a single-collection search still asks for what it needs, and a server-reranked page keeps the full pool. On the managed service the 30 nearest rows by raw distance were identical at every pool size from 40 to 300 on 8 queries; the tool's median fell from 2.99 s to 2.41 s. The CLI is unchanged.

Fixed

  • A catalog owner row without name or owner_type is refused with a 400 that names the field (nexus-ecjo8; engine change). It was a 409 carrying only SQLSTATE 23502. The owner upsert, the import and the batch import check both fields before any write, and a refused batch writes nothing. No request that succeeded before changes outcome.

Developer workflow

  • scripts/check_engine_release_floor.py --client-precondition <tag> exits 2 with a CANNOT VERIFY line when the tag is not cut or not fetched, instead of a traceback (nexus-43ulx.32).
  • tests/e2e/local-service-gate.sh and fence_home.sh run under macOS /bin/bash 3.2: the smoke bodies are built by assignment, so brace expansion cannot empty them, and a smoke failure prints the engine log's WARN and ERROR tail before cleanup deletes it (nexus-ecjo8, nexus-43ulx.15). The HOME fence pins uv's managed-Python root to the real home (nexus-t0pke).