v5.2.3
Blob durability — dangling references and in-flight readers
Two related fixes close windows where a committed record could point at blob bytes that were no longer on disk.
- A transient replication save could leave a record referencing a missing,
PENDING, or incomplete blob file. When the same record is later re-delivered by a base copy, Harper now repairs that existing file in place rather than writing a new orphan the duplicate-skipped record would never reference. The repair is fail-atomic — it holds the blob lock, writes and verifies a sibling temp file, flushes, and renames over the target — so a failed repair leaves the referenced file byte-for-byte unchanged. The orphan sweeper respects active repair locks. Adds the shared blob-header classifier and thereplication.blobGapReconnectMsconfig key consumed by harper-pro (#2177). - Superseded blob files were unlinked on a fixed 500 ms timer with nothing checking whether a reader still needed the bytes. Because a blob file is opened lazily by path at
stream()/bytes()time, a reader that resolved a record just before a concurrent write could open a file that was already gone — on the HTTP path thatENOENTlands after response headers are committed, reaching the client as a truncated body while every signal reports success. The delay is now configurable viastorage.blobRetentionand defaults to 2s, and reclamation is reference-aware so an in-flight reader can take a retention hold (#2145).
Deploy — by reference, with a durable credential
harper deploy gains two opt-ins that together let an app be deployed from its git repository instead of an uploaded payload:
by_ref=true(orref=<committish>) resolves the app's GitHubowner/repoand commit from the local working copy (or from GitHub Actions env) and deploysgit+https://github.com/<owner>/<repo>.git#<sha>. Everything that could move is resolved client-side to a SHA — including an explicitref=, locally first and then viagit ls-remote— so cluster peers, which resolve the package independently, cannot diverge on a moved tag. An unpinnable ref fails closed rather than being sent as a name the cluster would resolve for itself, and an attached credential is pinned to the package host (#1850).setup=trueis a guided, client-side credential provisioning flow — whatharper loginis for auth, but for deploy tokens. It fetches the cluster's public key, sources a token (a fine-grained PAT, yourghsession, or an npm token), seals it locally into anenc:v1:envelope, and stores only ciphertext in the component-scoped secret tier. The plaintext never leaves the machine; the cluster decrypts in memory only at deploy/rollback time (#1851).
package_component streams instead of base64
package_component returned the whole component tarball as a base64 string inside the JSON envelope, peaking at roughly 4.7× the archive size resident in a shared (on Fabric, multi-tenant) Harper process, and hard-failing with ERR_STRING_TOO_LONG once the base64 result exceeded V8's string cap. The operation now streams the archive; project-resolution failures other than ENOENT are rethrown instead of being swallowed (#2152, #2150).
Dependency pinning for load-bearing modules
A caret range does not bind the version that reaches a running node: harper-pro, a rebuilt container, or a plain npm install of published harper could resolve a newer native or encoder dependency with no Harper PR and no human merge. The load-bearing ranges — rocksdb-js, the encoder/iterator modules whose object identity crosses its boundary, structon, and the optional native addons — are now pinned to the versions the lockfile already resolved. No installed dependency moves; only the allowed resolution narrows. Docker smoke additionally requires the root msgpackr and @harperfast/extended-iterable specs to be byte-equal to rocksdb-js's requirements and rejects a nested copy (#2179). A follow-up aligned the structon pin with the lockfile after it broke npm ci on main (#2196).
Also in this release
A report-mode review-coverage CI check that surfaces cross-model review counts and a stale Human-Review-Need: footer without blocking (#2183); an integration-test helper refactor (#1904); and non-major dependency updates (#2131, #2189, #2190).
Full Changelog: v5.2.2...v5.2.3