Repository navigation
v5.3.0-beta.2
Pre-releaseThis release covers changes since v5.3.0-beta.1. For everything in the 5.3 line since the last stable release, read the beta.1 notes as well. The core changes carried by this release are inlined below.
Certificates
add_certificatefinds a private key that is already on the node. Installing a non-CA certificate failed withA suitable private key was not found for this certificatewhenever the matching key existed on disk but not in the in-memory key map — the normal state after Harper auto-generates a CA key it writes asprivateKey<uuid>.pemand no config names. The operation now reads the key files that certificate records name, the waysignCertificateandcreateCsralready did, so it succeeds without the caller resubmitting the key. (#860)
Also in this release
Core pointer syncs bringing the Harper changes listed below (#870, #872, #873, #877, #880, #892); and two integration-test fixes — the directional-flow fixture is seeded before the core node exists (#875) and the unit-test root is removed only after its databases are closed (#893).
Full changelog: v5.3.0-beta.1...v5.3.0-beta.2
Harper (core) v5.3.0-beta.2
Released at HarperFast/harper v5.3.0-beta.2. Core changelog: v5.3.0-beta.1...v5.3.0-beta.2.
Security
- SSH private keys no longer reach the logs. A private key passed to
add_ssh_keyorupdate_ssh_keywas written verbatim to the core operations log and to the MCP audit log. Both redactors now apply an operation- and tool-scoped field policy, so the key is removed for those operations without hiding the same field name where it carries no secret (for example an environment variable's name). (#2741) - A rejected cookie or mTLS session is now a decision, not a raw error. A
server.getUseroverride that rejected a cookie session escaped the authentication middleware as a stringified error. Those branches now behave like theAuthorizationbranch: a failed principal resolution becomes a negotiated 401, or a deferred credential rejection the route owner settles, and a component can tell a rejected credential apart from an internal fault. (#2717, fixes #2703)
Replication and clustering
- An out-of-order write below the audit-retention floor no longer stalls replication. Such a write entered the reconciliation walk, and the walk's head lookup fanned out across every per-origin transaction log. On a 16-node cluster this left two replication legs with zero commits for over 24 hours, with one HTTP worker per receiver pinned at 100% CPU and progress of roughly one record every few minutes. Below the floor a write now contributes only its commutative operations. (#2684)
- A record key beginning with
/no longer hangs the subscription broadcaster.notifyFromTransactionDatawalked/to/forever, pegging every HTTP worker that held a subscription on that table at 100% CPU with nothing in the log. The walk now stops when the computed parent equals the current key, and a subscriber on the root key is still notified once. The bug was present in 5.1.x and 5.2.x as well. (#2689) - An exhausted cluster lock wait reports what a home actually answered. A contended
lock()with a short wait returned 423 or 503LOCK_UNAVAILABLEat random, which matters because 423 means "held, retry" while 503 means cluster lock coordination is broken. A wait's terminal status is now taken from the last reply a home completed, bound to the route and generation that produced it; a deadline this node imposed on its own probe never classifies the wait. The loop also stops before issuing a probe that cannot complete within the remaining budget. (#2685)
Storage and recovery
- The restoring marker is now published atomically.
beginRestore()opened the marker withopenSync(path, 'w'), truncating it before the database name was written, andscanBlockedRestores()skips a marker whose first line is empty. A crash inside that window left a half-purged database that loaded as healthy on the next boot. The marker is now written temp file, fsync, rename, parent fsync, and an intact marker is reused rather than rewritten. (#2644) - Blob paths stay stable for aliased databases. A shared physical store kept being restamped by later logical aliases, so blob-root resolution moved across reconciles. The identity assigned first in
initStores()now wins. Compatibility note: a deployment with file-backed blobs stored under an alias that previously happened to load last will now resolve to the first-assigned identity; no persisted identity or blob migration ships with this change. (#2683) - rocksdb-js updated to 2.10.0. (#2720)
Analytics
- Aggregation resumes from the last raw record it rolled up. The resume marker was stamped with the cycle's own end-of-run
Date.now(), so every raw report that arrived between the end of the rolled-up window and the end of the cycle was skipped permanently: the remainder of a backlog left by a late tick, and anything a worker reported while the cycle ran.get_analyticsunder-counted by whatever fell in that gap and the samples never came back. The resume point is now a cursor that moves only to a record a cycle actually read, and stays put when a cycle reads nothing. (#2692)
Vector search
- Native HNSW planes use about half the layer-0 memory. The layer-0 neighbour array reserved 128
u32slots per node, derived from valuesnativePlanepins, so no index declaration could change it — while a live 7.7M-node plane carries a mean layer-0 degree of 29. The new per-indexnativePlaneLayer0Capoption defaults to 64, which holds recall@10 within about 0.5 points of cap 128 at every ef ≥ 128 measured at 1M and 4M vectors, at the same latency. (#2701) @harperfast/hnswupdated to 0.4.0, which brings a 32x cut in visited-set memory, kernel-level prefetch of non-resident slots, and a parallel batch build not yet consumed here. The on-disk plane format is unchanged, so existing installations need no reindex. (#2722)
Full-text search (groundwork, not yet reachable)
- A native full-text derived-index backend converts committed record changes into
@harperfast/fulltextmutation batches and publishes the Harper replay cursor with the Tantivy commit. Harper records and audit logs stay authoritative; the Tantivy files are rebuildable derived state. This is the backend slice only — schema activation, reader attachment,Table.search, REST exposure and status reporting are follow-up work, so nothing about it is reachable by an application yet. (#2569, part of #2510)
Also in this release
logger.closeLogFile now stays bound to the current file after a path reassignment, a latent hazard on public API surface whose only callers today are test fixtures (#2724); CI now requires a planning receipt on changes to core-shared storage paths (#2594) and the derived-index runtime is back under that policy (#2745); DESIGN.md is partitioned into per-directory design notes indexed from the root (#2728); test stabilisation for the analytics aggregation cycle (#2699), HNSW distance inversions (#2702) and unit-test database teardown (#2720); dependency updates for alasql 4.19.1 (#2698) and mocha 12 (#2700); and a refresh of the AI review prompt pin (#2610).