Release Notes¶
Release notes for the open source Lore project. Releases before v0.8.4 predate this file; see the GitHub releases page for the published record.
Nightly¶
Breaking changes¶
- C API:
LoreGlobalArgs.no_atimeis removed. Nothing set it and nothing read it — the accessor it gated was never wired to the store settings, so the flag named a behavior that did not exist. Rebuild against the newlore.h; a caller that zero-initializes the struct needs no other change lore-server:connection_message_limitunder[server.quic]/[server.quic_internal]is renamedstream_message_limitand applies per stream rather than per connection, so withmax_bidi_streams = 8a value of 500 allows 4000 requests in flight per connection instead of 500
Features¶
lore commit --stats/lore push --statsreport what the operation cost: files by the action each was staged with, and fragments by what became of them — already stored, compressed, written to the local store, duplicated as an association by the peer or uploaded. Reported once when the operation finishes, on the path that fails as on the one that succeeds, through theRevisionCommitStatsandBranchPushStatsevents;--stats=2adds the per-fragmentFragmentWritestream.--event-interval <milliseconds>paces the progress eventslore-storage: the local store records when an entry was last read, so eviction and compaction rank by what commands actually read rather than by when content was written. An entry is serialized inside its whole bucket, so the read stamp marks a bucket for rewrite only once the time it holds moves by an hour or more: a burst of reads costs at most one index write per bucket instead of one per read, a smaller move rides to disk with whatever writes the bucket next, and marking never schedules a flush of its ownlore-server: request admission is per QUIC stream rather than per connection, so a saturated stream no longer stalls the others, and a connection-wide ceiling sheds immediately once requests in handling — including those waiting for a stream permit — reachconnection_inflight_limit. The wait for a permit is bounded bypermit_timeout_ms(default 100ms) rather than by the request deadline, and the two refusal paths report separateAdmissionLimitandPermitTimeoutmetric labelslore:lore_storage_get_file_resolved/lore_storage_put_file_resolvedare the file-backed pair oflore_storage_get_resolved/lore_storage_put_resolved— a foreign key resolved straight into a file, and a file published under one, so an application never loads the content to write it and never buffers it to read it back. Lore streams both directions a fragment at a time, writing a fragment tree into the target at each leaf's own offset, so peak memory follows the fragment rather than the content. Publishing still costs one round trip whatever the size: content that fits a single fragment carries its key on that fragment's upload, and content that fragments carries it on the fragment list root's — the last fragment written, by which time every leaf's placement is known, so a tree that did not reach the remote whole still leaves its key unpublished.lore_storage_put_resolvedgets that second saving too.offset/lengthselect a range as they do forlore_storage_get_file- A child directory holding its own
.lore/is a nested working copy and bounds every walk of the parent's working tree:status,diffandstagestop at it rather than indexing its contents. Naming one onlore stage, or a file inside one, is refused. A directory the current revision holds stays tracked, since untracking committed content is an explicit user action
Fixes & Improvements¶
lore:lore_storage_get_fileno longer replaces the destination whenoffsetstarts past the end of the content. The range resolved to nothing, but the file was still created, truncated and renamed into place before the call reportedINVALID_ARGUMENTS, so a rejected request destroyed a destination that was already there. The target is now left alone, which is what the C API documented; a start exactly at the end is still a legitimate empty read and writes the empty filelore:lore_storage_put_fileandlore_storage_put_file_resolvedreject a missing or non-regularpathasINVALID_ARGUMENTSon the first open, rather than after the ten-second transient-failure back-off. A directory can no longer retract a published key by reporting zero size. The check moved onto the handle's own stat, costing one fewerstatxper itemlore-storage: a write that waits on another task already storing the same address reports the placement the store settled at rather than the one it read before waiting, so content whose fragment tree repeats a leaf — a file of identical blocks — is no longer reported as partly absent from the remote, and a key naming it is published instead of withheldlore-storage: a stopped garbage collection pass gives up within one packfile instead of after a whole compaction step, so process exit waits at most one packfile rewrite; the stop at the end of every repository command is gone, so background eviction and compaction continue across commands- Fix a directory staged as an add and then removed before any commit being reported as a delete no command could clear; a scan now discards the entry with its whole subtree, as it already did for a reverted single-file add
- Fix
stage --scankeeping an entrystatus --scandiscards, which left the two walks with different trees lore branch merge,branch merge intoandrevision cherry-pickcarry nothing from the source revision's metadata unless--inherit-metadata <KEY>(repeatable) names it, somerged-by,reviewed-byandchange-requestrecord whoever performed the merge rather than whoever produced the branch; actor and provenance keys stay reserved even under*- Fix
lore branch mergerefusing files that carry no local changes: the working file is measured against the node the current revision holds rather than against the base of the three-way diff, a comparison is answered by the chunking the content was stored under, and one file is read and hashed at most once however many revisions it is measured against
v0.9.0 (Aug 28th 2026) [#782]¶
Breaking changes¶
lore-credential: auth tokens move totokenstore.tomlunder atokenstore_encryption_keykey, with nothing migrated fromtokens.toml; old and new clients keep entirely separate credentials, so expect onelore loginper generation. An unmigrated store reads asNot authenticatedand--remotereads answer empty rather than failing, so scripts gating onlore statusshould check the exit codelore-server(AWS store): the fragment describing a payload now travels on the S3 object as anx-amz-meta-lore-fragmentheader instead of in a DynamoDB record, and the fragment metadata table is replaced by a fragment state table holding lifecycle state alone (a row's presence means the hash exists). Existing objects are not rewritten — they are read through a fallback to the old table, which must stay configured for them to remain readable. Under[plugins.aws.immutable_store]:- Existing deployment: set
dynamodb_fragment_state_table(required, no alias — start fails without it; normally the table that held fragment metadata, since the key schema is unchanged and the two row shapes coexist) anddynamodb_fragment_metadata_table(enables the fallback read, normally the same value; accepts the olderdynamodb_metadata_tablespelling). Roll out as a full stop followed by a full start — old and new servers must never run at the same time. To move the data across and retire the old table, seecontrib/aws-migrate-0.9.0/README.md - New deployment: set
dynamodb_fragment_state_tableonly. Leavingdynamodb_fragment_metadata_tableunset declares that no object predating the change exists, so no fallback read is ever issued and an object without its own metadata is reported as damaged lore.model.v1andlore.thin_client.v1:Repository.created,Branch.createdandRevision.timestampnow carry Unix epoch milliseconds instead of seconds- C API:
LoreMetadataTypediscriminants are now stable integers shared betweenlore.hand the on-disk metadata buffer, andlore_revision_tree_metadata_settakes typed(key, LoreMetadata)batches instead of text plus a format tag; callers using the enum names need a recompile, and callers hard-coding the old numeric values must update them lore-server(replication protocol):ExistsBatchis replaced by a batchQuery, andGet/GetMetadataresponses carry the fullStoreGetDataincluding the partition. Retired opcodes are reserved rather than reassigned, so a peer on the previous protocol is rejected instead of misreading a response — roll replicas and their upstream together- C API: failures that previously reported
-1(internal) now carry the specific code where one applies, because an error crossing an internal boundary keeps its variant instead of collapsing.lore_revision_tree_metadata_setand its file equivalent can now returnSlowDown(5),NotAuthorized(7),Maintenance(11),NotAuthenticated(12),NoRemote(14),NotConnected(17) andNotSupported(18); remote store reads and writes addDisconnected(6); and connecting with no stored credential reportsNotAuthenticatedrather than an internal fault. A caller treating every non-zero status alike is unaffected; one that branches on-1, or reads-1asretrying will not help, now sees retryable and re-authenticable codes on paths that previously only ever produced-1, and should handle them before upgrading
Features¶
lore-io: new runtime-independent asynchronous file I/O engine backing Lore's file access — positional owned-buffer operations on a bounded, idle-reaped syscall pool, upgraded automatically toio_uringon Linux and overlapped I/O on Windows, with vectored scatter/gather reads and writes.LORE_IO_BACKENDoverrides the choice; internals indocs/developing/internals/file-io-engine.mdlore:lore_revision_tree_commitfreezes a handle's in-memory tree into a revision and advances the branch tip by compare-and-swap, taking the branch from the handle'sbranchmetadata key. Commit is exclusive and all-or-nothing — a failure leaves the handle where it was with every edit still staged — so services can publish revisions with no working tree on disklore:lore_revision_tree_delete,_modifyand_movejoinaddas batch verbs, each validating the whole batch before any node changes and emitting a*_COMPLETEper entry plus oneBATCH_COMPLETE. A node from the loaded revision is staged for deletion and reversible, one added through the handle is discarded outright, andstaged_actionon the child and node-info events reports what is pending. Moving into a linked repository is not supported yetlore: batchedlore_revision_tree_metadata_set/_get/_clear, withLoreMetadata,LoreMetadataTypeandLoreBinaryreworked into owning, self-describing types so binary metadata can cross event callbacks and both wire formats (see Breaking changes)lore: a revision tree handle holds its own store reference, so closing the parent storage handle leaves it usable; orphaned handles are closed when an IPC connection drops, andlore::shutdowndrains tree handles firstlore:lore_storage_get/lore_storage_get_filetakeoffsetandlengthper item to read only a slice of the content, pruning the fragment tree so the work is proportional to the range rather than the content size (a zeroed pair still reads the whole content; a start past the end is rejected withINVALID_ARGUMENTS)lore:lore_storage_get_resolved/lore_storage_put_resolved, also over QUIC and gRPC, resolve a key belonging to another system — an asset id, a build id — and act on the content it names in one request instead of two. A read resolves local-first and caches the mapping it learns, verifying the root fragment against the resolved hash; a write stores content before publishing the key and is last-writer-wins. Design:docs/proposals/2026-08-02-resolved-storage-operations.mdlore branch archive --include-layers/--layer <path>archives the branch in every configured layer, or in the layer at one mount path; the default still touches only the repository it ran in, since archiving deletes and a layer owns its own branch lifecyclelore --identity-token <token>/--access-token <token>(and the matchingLoreGlobalArgsfields) use caller-supplied tokens instead of the credential store, for CI runs and stateless services. Tokens are ephemeral and never stored, the identity is read from the token, and both conflict with--identity; given only an access token, an operation needing an identity token fails rather than falling back to a stored oneLoreRepositoryCreateArgs/LoreRepositoryCloneArgs:use_shared_storeis replaced by aLoreSharedStoreModeenum (Inherit= 0,Enabled,Disabled), so a caller can explicitly refuse shared-store backing on a machine whereuse_shared_store_automaticallyis set (a zero-initialized struct still follows the machine setting)ImmutableStore:exist/exist_batchare unified into a batchqueryanswering with the best match level found, andget/get_metadatadrop their match-level parameter for oneStoreGetDatacarrying the fragment, the level and an optional payload. The contract — never over-report, obliterated never matches, reads agree with each other and name where a match was found — is written into the trait and enforced by a conformance battery every store runslore-server: fragments arriving Oodle-compressed onputare transcoded to Zstd as the first step of retiring Oodle, gated behind theoodlefeature and opt-out at runtime withLORE_DISABLE_CONVERT_OODLE_ON_PUT; the address is unchanged, since identity is over uncompressed contentlore-aws:MetadataMigratorandrun_migratordrain legacy DynamoDB fragment-metadata rows into the new S3-object-metadata plus state-row model, by segmented parallel scan across a pool of consumers. An accurate non-Oodle codec is re-uploaded as-is to set its S3 headers, Oodle and mismatched codecs recompress to Zstd, and a run is idempotent and resumable. Packaged as a standalone tool undercontrib/aws-migrate-0.9.0lore link add/remove/update/reset/listnow work on a nested link — one mounted inside another link's subtree — mutating the innermost repository's registry and propagating outward, andlore commit --link <nested path>commits each intermediate link as a real revision before repinning. Nested-link merge is not covered yetlore-server: the legacyurc.rpc.RevisionServicediff and tree gainlink_partitionandtrackingfields, so a consumer can tell which repository a changed path resolves under and whether a link follows its parent branch or is pinned (both additive on messages already marked deprecated)lore-server:presigned_url_extra_content_typesandpresigned_url_denied_content_typesunder[server.http]adjust whichContent-Typevalues a redeemed presigned URL may carry. They extend rather than replace the built-in safe set, a type in both lists is denied, and browser-executable types can never be added — the server refuses to start instead of failing openlore-proto: thin-clientTreePathexposes file size and mode, so aThinClientService.RevisionTreecaller gets both without a second requestlore: self-signed certificates installed in the OS trust store are now honored (reqwest'srustls-tls-native-roots), which local development against a self-signed server needslore link info <path>reports one link's mount and source paths, its branch and whether that branch is followed or pinned, the pinned and remote-latest revisions, the link flags, and the staged state and staged file count inside it; the remote revision is omitted when offline
Fixes & Improvements¶
- Thread model: the network transport moves onto its own runtime, the rayon compute pool is gone with compression, hashing and chunking now inline on the core workers, and the blocking pool shrinks to two threads.
LORE_MAX_THREADis now an absolute cap. Clone throughput 1.4 → 2.5 Gbps, large-commit peak memory 6 → 4 GiB lore-storage,lore-revision: the store buckets, packstore, fragment chunker and remainingtokio::fs/std::fscalls all run throughlore-io, so a common-case bucket load completes in one dispatch and a flush gathers header, index and entries in one vectored write; filesystem locks back off asynchronously instead of parking a threadlore-storage: fix a file shorter than its measured size being taken as an early end, producing a chunk list covering fewer bytes than its root fragment recorded; the read now fails- Windows: no handle the I/O driver opens permits a second writer, while a read-only open still shares reads and deletion so replace-by-rename works.
ERROR_SHARING_VIOLATIONis now transient and retried, so materializing a file being hashed waits rather than fails - Fix
lore branch mergeunder a sparse view dropping changes outside the view, leaving the branch divergent from the one it recorded as merged; nodes now merge regardless of the view, which gates only on-disk work, and an out-of-view conflict adopts theirs asStagedMergeTheirs(adopting untouched excluded subtrees whole made it 34% faster on 110,000 files) - Fix a link added, removed or repinned on one branch not surviving the merge that brought it over, where
link listreported nothing andlore stagefailed withLink not found; the registry now follows any link node a change set stages or deletes, and a row both sides moved refuses the merge - Fix a revision moving a link's pin producing an empty diff when the subtree was byte-identical, and entries from a linked repository naming no repository so content could not be fetched from the right partition; a new
link_readpolicy gives a caller authorized only for the parent one change for the mount path - Fix
lore branch createfailing withBranch <name> already existswhen a linked repository held the requested branch id under another name; the cascade adopts it and reports aLinkBranchCreateevent with areusedflag - Fix concurrent link edits overwriting one another:
link add,updateandremovereleased the runtime lock between reading and storing the registry, and now hold one write lock across it - Fix
lore pushon a repository with links reporting the parent's revision against a branch that exists only in a linked repository; push events now carry the repository and branch they report (repository state was always correct) - Fix
lore stage . --scanpinning a staged revision for unchanged layers, which aborted the nextcommitwithNothing stagedand madebranch switchrefuse withLayer has uncommitted staged changes; a layer is pinned only when the walk left its state dirty - Fix
lore syncleaving a layer's staged state on the revision it moved away from, so the next commit refused it as a stale parent or under--forcereverted what the sync brought in; sync now refuses when a layer holds staged work and otherwise rebases onto the new pin - Fix
lore layer removediscarding a layer's staged work silently and leaving staged adds on disk; removal now counts staged files and refuses without--force - Fix an unreadable
.lore/config.tomlorlayer.tomlpresenting as a repository with no remote or no layers, which the next save made permanent; both now default only forNotFoundand save through a renamed.tmpsibling - Content the peer already holds is no longer re-uploaded: where a query reports the hash under another context or partition, the client asks the peer to duplicate the association instead of sending the payload, on
lore pushand direct writes alike lore-revision: the composite store caches metadata resolved byquery, not onlyget_metadatahits, so aquery-heavy workload stops hopping to the durable store; capped bycache_metadata_semaphore_sizeand limited to durable-sourced results, andshould_cache_query_resultsis renamedcache_metadatalore-server:get_metadatanow fans the durable store out in parallel with read replicas and sends a dedicated QUIC command, instead of falling back to a localquerythat reports only the durably-stored flag; edge replicas answered incorrectly and always paid a cross-region triplore-server: the JWK service picks up key rotation without a restart; a verification failure only a key could explain triggers one refresh, so material replaced behind an unchangedkidno longer rejects every tokenlore-server: JWK fetches are bounded by timeouts, a pooled client, single-flight collapsing of concurrent misses and a minimum interval, with an empty cache never throttled so start-up always proceeds. The document is capped at 1 MiBlore-server: a JWK set is validated key by key — an unusable key is skipped rather than failing the fetch, a key whosealgfamily does not match itsktyis refused, and an empty result errors. RS256 is inferred for an RSA key omittingalg, which previously failed start-up against Microsoft Entra IDlore-server: why a JWT verification failed no longer reaches the caller —bad signature,expiredandno such key idare an oracle for someone unauthenticated; the reason goes to a debug loglore-server: fix a stored-XSS vector on presigned-URL redeems, where bytes could be served from the Lore origin under a caller-chosenContent-Typesuch astext/html; a deny-by-default allowlist rejects at mint, coerces on redeem, and every response carriesnosniffand adefault-src 'none'; sandboxCSPlore-server:binary/octet-streamis allowed in the presign allowlist and served verbatim — S3 assigns it to objects uploaded without an explicitContent-Type, so callers forwarding S3 metadata had theirs coercedlore-server:RepositoryMetadataGetandRepositoryMetadataSetnow perform the real-time authorization check the other repository handlers do, so a client cannot read or write metadata on a repository it has no access tolore-transport: fix a per-item failure on the streaming storage RPCs being reported as a stream trailer, which killed the HTTP/2 stream and every request multiplexed onto it; outcomes now travel in-band, and field numbers are preserved so get responses stay wire-compatiblelore-transport: fix gRPC reconnect not re-reading the epoch per attempt, and storage streaming having no working reconnect at all; a dead stream now rotates once across concurrent callers and replays outstanding requests- Fix
lorecommands taking about 30 seconds when a hostname resolved first to an address family the server was not listening on, commonlylocalhoston::1; the QUIC client now follows Happy Eyeballs (RFC 8305), 30.05 s to 0.38 s on the reproduction lore-transport: fix the per-stream in-flight counter never being decremented on error or cancellation, which degraded priority routing and left the selector round-robining; also fixadd_streamstoring a count one short of the streams it openedlore-aws:queryis backward compatible with fragments described by the legacy metadata table, soBranchPushno longer reports content as missing when it is stored but described by the old rowlore-aws: the mutable store's zero-expected compare-and-swap matches the local store now — a row holding a zero value is treated as absent — so an empty branch pointer cannot make a swap report success without the write landinglore-storage: a corrupt mutable-store bucket is no longer reset to empty on an authoritative store, where it silently dropped branch heads, metadata and instance registrations with no upstream to refill from;authoritative: truemakes it a hard errorlore-credential: fix the credential store rewriting its keyring entry on every stored token, which on macOS prompted for keychain access from every application linking Lore and again after each rebuild; each seal now draws a random nonce instead of persisting a counterlore-credential: fix any keyring error being read asno key, so one denied prompt regenerated the key and wiped the token store for every Lore process on the machine; onlyNoEntrycounts as absent- Fix a notification subscription that had stopped on its own still counting as live, so every later subscribe returned success without subscribing; liveness is now checked by cancellation token and task state
- Fix
lore history --branch <name>returning an empty listing for a branch that exists only on the remote; the local branch is preferred and the remote head used when there is no local history - Fix an infinite loop walking revision history for a deleted file, where a zero parent hash was handed to
State::deserializerepeatedly; a three-way diff base no longer resolves to the zero revision lore-revision: the diff and merge base search no longer errors asDivergentwhen it cannot prove divergence — branch points sharing no revision fall back to the older one, and two points with the same revision number short-circuit instead of spending a full search budget- Fix
lore reset <path> --revision <revision>failing when the path is currently a directory but was a file in that revision - Fix
lore syncundoing a change from a file to a directory; where an add and a delete carry the same node name, the delete now takes thefromnode - Fix a clone failing with
Failed to create directorywhen the parent already existed but was not created by that call — a bind-mounted clone root or a drive root - Fix
lore stage --targets <file>hanging on a large list, wherededup_to_supersetsrescanned every kept path per candidate and timed out around 900,000 paths; sorting in subtree order takes the collapse from quadratic to O(n log n) lore stageno longer grows memory in proportion to the work ahead of it; in-flight tasks are capped at 1000 and drained as they complete, and directory fan-out is bounded by a semaphore, processing a child inline when no permit is freelore-revision: node allocation during staging no longer holds a single-permit mutex across its whole scan, andnode_addskips the 65 KB zero allocation it issued when clearing a recycled slot whose metadata block was never writtenlore-revision: the per-node stage log lines drop from debug to trace; they fired once per file and made--debugunusable during a large stagelore-base: fixHash,Context,PartitionandAddressbeing unreadable under non-self-describing formats such asbitcode, which made any record carrying one fail to decode; a truncated address is also refused rather than becoming the zero addresslore-server: pushing a revision hash that does not exist in the immutable store returnsNotFoundinstead of a genericInternalstatuslore-server:LORE_SERVER_MAINTENANCE=1stops the internal QUIC server serving its port while the internal gRPC server keeps a stub listening, so health checks getunavailablerather than a closed portlore-telemetry:size_histogramgains explicit power-of-two boundaries from 64 B to the 256 KiBFRAGMENT_SIZE_THRESHOLD, soputandgetdistributions are no longer cut off at the OpenTelemetry defaultslore-error-set: newchain_err_fromchains a discrete error onto an error-set enum without destructuring aTraced<E>; call sites that discarded the originating trace now preserve itlore-revision:LoreRevisionDiffFileEventDatagainsfrom_path, so a receiver ofLORE_EVENT_REVISION_DIFF_FILEcan reconstruct where a moved or copied file came fromlore: the batch verbs' id fields are named apart —entry_idper entry,batch_idon the batch args andBatchComplete— andparent_entrybecomesparent_entry_index- SWFS groundwork: the stale commented-out integration is replaced by a real interface whose types are always available while its methods compile only under the
swfsfeature;InstanceOperationImpllets an operation in a linked or layered repository be finalized alongside the main one - New
iterationCargo profile inheritsreleasewith LTO off, cutting link time when rebuilding frequently lore-revision: reject directory traversal and dot-prefixed segments in repository path componentslore-aws: guard against maliciously large S3 payloadslore-storage: fix data loss in the lazy fan-out redistribute path, where buckets left unmarked after a fan-out could be overwritten from the stale on-disk layout by a reader racing the flushlore-storage: decide the legacy bucket layout per group rather than per store, so one written group no longer pins every other group at the maximum bucket count on the next openlore-storage: file modification detection no longer downloads content —file_matchestransfers the stored header and, when fragmented, its fragment lists, then compares chunks against the file's own byteslore-storage: fix a dropped consumer on a streaming read being reported as an error instead of draining gracefullylore-storage: build zstd compression and decompression contexts in workspaces this crate owns, with the pool holding at most 32 and further concurrency building one per calllore-storage: removeallow_partial_fragmentfrom the local store, so alore-serverlocal store can cacheget_metadataresultslore-storage: obliterate a fragment tree without holding a lock across it, and drop an unreachable sink path from the defragment pipeline dispatchlore-storage: key file modification times by the lowercase path string, unifying them with node-name matchinglore-server:ReplicatedImmutableStoreimplements theCopymessage and returns theContexta query matched under, instead of leaving clients to assume the defaultlore-transport: a persistent connection updates the authn and authz tokens it presents, and authz exchange results for caller-supplied identity tokens are no longer written to the token storelore-auth: a missing token reportsNotAuthenticatedinstead of a generic internal error- Fix clone not applying view filtering inside linked and layered repositories, where
clone_nodewas called with a path relative to the linked repository rather than the mount point lore-revision: refuse alink removethat would destroy local editslore-revision: fix non-ASCII lowercase handling when building relative paths- Fix the originating trace being lost through
::internaland::internal_with_context lore-revision: staging does less work per path — targets resolve concurrently, each walks from its pre-created ancestor rather than the root, a directory's children are read once and matched by binary search, a shared directory's case resolves once, and paths are neither re-stat'd nor rebuilt through extra string allocationslore-revision,lore-storage,lore-base: allocation and locking trimmed on the hot paths — the dirty tree walks from an explicit stack and names into one buffer, node blocks serialize from the lock without a copy and deserialize once rather than once per waiter, merkle tree blocks come from their own heap, short ASCII names fold to lowercase on the stack, the log level reads from an atomic, and successful operations no longer allocate error stringslore-transport,lore-revision: reuse the lazyStorageSessionwrapper across fragment writes instead of rebuilding it per writelore-io,lore-revision: verify a path's case by asking the filesystem for the name instead of listing its directorylore-aws: box SDK error payloads to shrink thelore-awserror types
v0.8.6 (Jul 29th 2026)¶
Breaking changes¶
lore-client: logging CLI arguments are now strictly mutually exclusive; a command line passing conflicting logging flags is rejected instead of silently accepted- Auth
login/infonow returnNotSupported(code 18) when the server has no auth endpoint configured, and surfaceNotAuthenticated/Disconnectedinstead of a generic internal error (code -1); scripts branching on these exit/FFI codes must be updated - Presigned URL vending (
POST /v1/repository/{id}/content/{address}/presign) is now restricted to service accounts; normal user tokens can no longer mint presigned URLs
Features¶
lore-server: forwardBranchListandRepositoryCreateto a remote Lore server when configured (extending the existingBranchCreate/BranchDelete/BranchGetforwarding)lore: add a batch node-add verb (lore_revision_tree_add) to the low-level revision API, landing a whole subtree atomicallylore: run the service process (lore service run) on Linux and macOS, not just Windowslore: validate that all strings passed to the C API are valid UTF-8, rejecting invalid input up front with a named fieldlore-server: support file:// JWKS endpoints in the JWK servicelore-revision: optionaldurable_delayon the composite store so read replicas can answer before the durable tier is queriedlore-storage: self-heal corrupt (torn-write / zero-filled) mutable store buckets instead of failing to open the storelore-server: addCache-Controlheaders to the presigned-URL redeem endpoint for immutable content- Add a self-contained Terraform example for an AWS primary + edge deployment under
contrib/aws/
Fixes & Improvements¶
lore-storage:read_intonow respects the requested byte range for single-fragment reads (partial reads of files ≤ 256 KiB no longer fail)lore-server: fix JWK refresh cache check so a missing/rotated key triggers a fetch, allowing key rotation without a restartlore-credential: require a DNS label boundary when matching a dotless JWTaud, and allow exact apex-domain matches, closing an audience-suffix leaklore-revision: preserve dirty move status throughstatus --scaninstead of degrading it to delete + addlore-revision: bound commit read memory with a travelling fragment permit, and cap directory recursion fan-out during commitlore-revision: drain staging tasks on all error paths so failures propagate cleanlylore-storage: batch FastCDC chunking to cut per-chunk overhead on medium/large writes- Add transport connect timeouts so local reads no longer stall on an unreachable remote
lore: use the calling process's working directory for absolute-path resolution in the service process- Fix
lore_branch_switchandlore_branch_resetto restore the branch name→id mapping (so the branch appears in the local list), with a--forceoverride lore-revision: fixrestorefailing withDirty node remain after nodes were committedlore-base: update vendoredrpmallocto 2.0.1
v0.8.5 (Jul 15th 2026)¶
Features¶
- Implement the low-level revision-tree read verbs on the C API:
tree_load/tree_close,resolve_path,list_children, revision & nodeinfo, andnode_path - Forward
BranchCreate,BranchDelete, andBranchGetto a remote Lore server, opt-in per-RPC under[server.grpc_public_services.forwarded_requests] - Add
repository info --localto read repository metadata from the local store without contacting the remote
Fixes & Improvements¶
- Fix a corrupt-tree race in concurrent
node_addwhere a half-initialized node could be observed on the child chain - Protect non-durable local-only fragments from being orphaned by store GC eviction/compaction
- Fix dirty-add reclassifying remaining files when committing multiple added files individually
- Parallelize staging of multiple explicit paths instead of a serialized per-path loop
- Make CLI paths relative to the current working directory across all path-printing commands
- Bump
anyhow,crossbeam, andmemmap2for security advisories
v0.8.4 (Jun 25th 2026)¶
Features¶
- Add
--dry-runtorevision commitandlock acquire/release - Run incremental store GC by default; replace
--gcwith--no-gcto disable - Expose the mutable store through the low-level storage C API
- Add
ForwardedRevisionServicegRPC endpoint to forwardBranchCreateto a remote server - Carry structured error detail and FFI codes on the
Completeevent - Show staged renames as moves in diff output
lore statusprints paths relative to the current working directory
Fixes & Improvements¶
- Fix use-after-free in
write_fragmentedwhen the chunker future is cancelled - Fix
LoreArray<T>dealloc layout mismatch in Drop - Fix
commit --statspanic and report real fragment stats - Fix link contents surfacing as parent adds in file diff
- Fix clone not materializing view-filtered directories with all-excluded children
- Reject malformed
metadata setargs instead of panicking; default branch metadata to current branch - Reset staged add/remove/update for link nodes
- Propagate dirty to committed ancestor directories on dirty add
- Make dirty add idempotent so a repeat dirty doesn't duplicate the node
- Stage empty dirty-added directories by their own path
- Honor
--dry-runon branch push - Rename
[server.replication]config to[server.grpc_internal](not backwards-compatible) - Map GRPC storage errors correctly and stop classifying
Unknown/EOFerrors as server errors - Handle thin-client
RevisionDiff/RevisionTreeRPCs with a zeroed revision - Tag linked-repo
RevisionDiffchanges with an indexed partition table - Standardise HTTP tracing and log levels
- Seed QUIC clients with an initial CWND on regeneration
- Remove redundant
dry_runfield from lock events - Rename shared store config file to
shared_store.tomlwith auto-migration - Change
statsflag tou8for C ABI consistency