Skip to content

v5.4.0-alpha.2

Pre-release
Pre-release

Choose a tag to compare

@github-actions github-actions released this 31 Oct 00:15
· 77 commits to main since this release
39eb2fd

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 @relationship now require read on the related table and on each related attribute used. Before, conditions, sorts, */default selects, property paths and get_attributes could 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 to false to turn this off. (#3234)
  • Local-trust requests run as a fixed local super user. Loopback authorizeLocal, 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_user refuses the name local. (#3755)
  • drop_attribute refuses a table's primary key instead of stripping it from stored records. (#3574)
  • search_by_value / search_by_hash validation failures return 400 instead of 500, and a null search_value is handled. (#3654)

New

  • PR previews managed by the cluster. enable_previews, disable_previews and get_preview_policy operations, per-app limits (maxPreviews, maxTtlDays), and harper preview setup|deploy|teardown CLI commands, so Studio and the CLI share one setup path. (#3617)
  • RocksDB memory settings: storage.rocks.arenaBlockSize and storage.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=1 opts 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 addTo composes 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_attribute on 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 @relationship into 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=ne queries are fixed, and invalidated cache rows reload in primary-key-filtered and sorted reads. (#3776, #3772)
  • @computed attributes 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: count and explain work behind an async allowRead, 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>.enabled is 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. .optional request-contract bodies are honored. Iterable operation results are collected. (#3539, #3538, #3548, #3547, #3745, #3754)

Security

  • The agent's http_fetch tool 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_component credentials 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_component could 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_components reports warning/unknown status and keeps plugin-set status after load. Status aggregates scoped component names. Analytics drops pending actions when disabled. RootConfigWatcher no longer loses config writes made under 50 ms apart. (#3444, #3439, #3591, #3435, #3589)
  • Read-transaction reference counts reset on detach, and LMDB disregardReadTxn is 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