Repository navigation
v5.4.0-alpha.2
Pre-release
Pre-release
·
77 commits
to main
since this release
Second alpha of Harper 5.4. Changes since v5.4.0-alpha.1.
Behavior changes to check on upgrade
- Relationship reads enforce related-table permissions. REST (GET and QUERY), GraphQL and NoSQL operation searches that read through an
@relationshipnow requirereadon the related table and on each related attribute used. Before, conditions, sorts,*/default selects, property paths andget_attributescould return related data the role could not read directly. A denied condition or sort returns 403, and default selects are narrowed. Super users and full-access roles see no change. SQL and subscription deliveries are not covered yet. (#3316) - Read requests now get admission control. GET, HEAD and OPTIONS return 503 when the current event-loop turn has already run longer than
http.readRequestQueueLimit(default 5000 ms). Reads are rejected, never queued. Set it tofalseto turn this off. (#3234) - Local-trust requests run as a fixed
localsuper user. LoopbackauthorizeLocal, the operations domain socket and loopback MQTT no longer look up a stored super user on every request (about 7 µs saved per REST GET), and they work on an instance with no users.add_userrefuses the namelocal. (#3755) drop_attributerefuses a table's primary key instead of stripping it from stored records. (#3574)search_by_value/search_by_hashvalidation failures return 400 instead of 500, and a nullsearch_valueis handled. (#3654)
New
- PR previews managed by the cluster.
enable_previews,disable_previewsandget_preview_policyoperations, per-app limits (maxPreviews,maxTtlDays), andharper preview setup|deploy|teardownCLI commands, so Studio and the CLI share one setup path. (#3617) - RocksDB memory settings:
storage.rocks.arenaBlockSizeandstorage.rocks.writeBufferManagerFlushPolicy. rocksdb-js is updated to 2.13.0, whose automatic arena size fixes a flush storm on small instances. (#3712, #3826) - Node's compile cache can be turned on by default at startup. It is gated on a list of Node releases that currently has no entries, so nothing changes yet.
NODE_DISABLE_COMPILE_CACHE=1opts out. (#3534)
Data correctness
- Concurrent LMDB writes from different threads are no longer dropped as duplicates. All threads now share one transaction clock. (#3657)
- Tracked records: fields that were only read are no longer written back, own properties and pending changes agree on every read/merge/save, conditional REST writes keep their edits on RocksDB, and
addTocomposes within a transaction. (#3586, #3820, #3581, #3732) - Writes over an invalidated never-stored id, and patches that recreate a deleted record, now store a created time and primary key. An older write merging under a newer record keeps the newer expiry. An invalidated record keeps its stub when an older full PUT arrives after patches. (#3653, #3774, #3764)
- Publishing a message no longer rewrites the record's data, expiration, residency or cache-stub state. (#3671)
drop_attributeon a dynamic table keeps every row readable and deleted rows deleted. The data loader keeps user edits on tables with a custom primary key and loads into the named database. (#3655, #3582)- Settling cache-fill record locks and waiting requests when a database closes mid-fill. (#3490)
Queries and relationships
- Relationship queries no longer return wrong rows, unfiltered selects or ignored sorts. Reads of an
@relationshipinto another database work for collections, filters and GraphQL. (#3775, #3619) - Composite primary-key conditions match on the whole key, whichever condition comes first. Sorted
id=in/id=nequeries are fixed, and invalidated cache rows reload in primary-key-filtered and sorted reads. (#3776, #3772) @computedattributes are present on every row of an LMDB collection read. Date chaining is fixed, and validation is kept across table re-declarations. (#3727, #3594)Prefer: countandexplainwork behind an asyncallowRead, and searches are closed behind every discarded read. (#3771)- A collection response whose read snapshot expires mid-row is cut off instead of ending as a complete array with an error item. (#3760)
- Full-text and vector: derived-index coverage publish order and HNSW barrier reset are fixed, a replayed vector's HNSW node is kept while its mapping is pending, full-text readiness polling stays within one deadline, and unused candidate capabilities are no longer required. (#3761, #3678, #3734, #3744)
Cluster record locks
- Locks stay available across a node restart: the dead delegate epoch is retired, short refusals are waited out, and duplicated or stale requests are settled. (#3789)
- A key no longer wedges when a delegate abandons a renewal or an older request arrives late. Writes on a locked record keep the lock's guarantees whichever resource instance stages them. A lock's writes are stamped above the version it was admitted on. (#3821, #3823, #3248)
- Checkpoint admission orders conflicting generations only by the origin's direct route. (#3685)
MQTT
- Durable sessions no longer resend acknowledged messages or freeze their position once the storage engine issues checkpoints. A durable subscription's position stays below every local write still in flight. (#3778, #3635)
- Durable SUBSCRIBE/UNSUBSCRIBE are answered from their own save, and refused after the session ends. (#3721, #3751)
MCP
mcp.<profile>.enabledis honored, including from environment variables. Three error paths are fixed (denied subscribe, CLI fallback, doctor 405). A prompt render with the wrong shape errors.harper+rest://URIs use the request host..optionalrequest-contract bodies are honored. Iterable operation results are collected. (#3539, #3538, #3548, #3547, #3745, #3754)
Security
- The agent's
http_fetchtool is blocked from operations API ports, including ports set by env placeholders. - A request that starts a TLS selector reads the certificate table as the system, so an anonymous request no longer fails TLS setup with "Must login". (#3756)
- The deploy-only role's secret delivery through
deploy_componentcredentials is pinned by tests. Full-text source authorization in the export job and search validation statuses are pinned by tests. A rejected Operations API body is answered once, before authentication runs. (#3742, #3735, #3720)
Performance
Table.get(id)costs less for string and number ids. (#3549)- No WeakMap entry per read transaction: REST reads use 3–5% less CPU and 29% less GC time. (#3740)
- CBOR, msgpack and CSV responses open their read source only when read, and msgpack streams rows that are still loading. (#3822)
Deploy, components and operations
- Branch removals no longer delete a fork the main thread serves, retry when a worker lets go, and are retried when
drop_componentcould not finish. A peer's deploy payload read that stalls before any content arrives is retried. (#3763, #3600, #3737) - Config reload rebinds every component logger.
get_componentsreports warning/unknown status and keeps plugin-set status after load. Status aggregates scoped component names. Analytics drops pending actions when disabled.RootConfigWatcherno longer loses config writes made under 50 ms apart. (#3444, #3439, #3591, #3435, #3589) - Read-transaction reference counts reset on detach, and LMDB
disregardReadTxnis clamped. (#3611)
Also in this release
Test coverage and benchmarks (#3131, #3530, #3736, #3741, #3793, #3808), design-doc upkeep (#3715, #3792, #3794, #3802), CI: publishing from the latest Node 26, with .node-version moved to 26 (#3791, #3729), and non-major dependency updates (#3551).
Full changelog: v5.4.0-alpha.1...v5.4.0-alpha.2