---
title: "Release 2026-08-17 - Changelog"
url: "https://nsta1.github.io/Orleans.Lattice/changelog/2026-08-17.html"
source: "https://github.com/NSTA1/Orleans.Lattice/blob/release/9.9/CHANGELOG.md?plain=1#L1632-L1644"
documents: "Orleans.Lattice 9.9.0 (release line 9.9)"
built: "2026-10-04"
all-pages: "https://nsta1.github.io/Orleans.Lattice/llms.txt"
---
# Release 2026-08-17

Part of the [changelog](../CHANGELOG.md).

A per-package patch advances `Orleans.Lattice` to `9.0.4` (see Added and Changed); all other packages remain at their `9.0.x`/`9.0.0` versions.

## Added

- **Activation-time cold WAL replay is now resumable, bounding WAL retention for a leaf with a large un-snapshotted prefix.** A leaf rebuilds its projection cache from the WAL on every activation, but the persisted `ProjectionCheckpointOffset` was previously advanced only by the post-pass-2 reconciliation at the end of the replay. A leaf whose un-snapshotted prefix could not be drained inside one activation window (a large WAL relative to Orleans' ~30s `RuntimeRequested` deactivation budget) therefore made no durable progress: a mid-replay deactivation discarded every applied entry, the next activation restarted from the same offset, and because the coverage-gated WAL GC (correctly) refuses to trim an un-snapshotted prefix, the retained WAL grew without bound while the leaf never converged. The replay now flushes the checkpoint incrementally at each slice boundary over the strictly contiguous, fully-applied prefix, which also drives the existing periodic snapshot capture. The advance is clamped below any deferred saga terminal / `DeleteRange` and below any unresolved saga prepare in the partition, so it can never license a checkpoint (or the materialiser pin) past a not-yet-durably-applied offset. A teardown then loses at most one flush interval, and the next activation rehydrates from the incremental snapshot and resumes from the last durable offset instead of replaying from zero; the now-covered prefix becomes trimmable, bounding retention. Steady-state activations are unaffected - a single-slice replay with no deferred terminals still flushes exactly once at the end of pass 1. (`Orleans.Lattice` 9.0.4, [#1513](https://github.com/NSTA1/Orleans.Lattice/issues/1513))

## Changed

- **`GSet.Add` commits a new element with a single hash probe.** The grow-only-set insert (and the fold behind `GSet.MergeDelta`) previously probed the element's base64 key twice on a genuine insert - a `Contains` miss followed by an `Add` - and now commits through the span alternate-lookup's `Add` in one probe, still materialising the key string only when the element is new. Behaviour, iteration order, and wire format are unchanged and allocation is identical; a new `GSet_Add` microbenchmark shows the fresh-insert fold about 11% faster (3.87 us to 3.44 us for 64 inserts, N=100, non-overlapping 99.9% confidence intervals). (`Orleans.Lattice` 9.0.4, [#1508](https://github.com/NSTA1/Orleans.Lattice/pull/1508))
- **A completed atomic-write saga now releases its staged batch payload on the terminal checkpoint, bounding the store footprint of a bulk re-projection.** A finished `AtomicWriteGrain` saga previously retained its full staged batch - `Entries`, `PreValues`, and the optional per-entry delta/delete channels - in persistent state for the entire `AtomicWriteRetention` window (default 48h), until the retention reminder cleared the record. For a single guarded write this is negligible, but across a high-cardinality bulk re-projection (one saga per touched key) the retained value bytes dominated the grain-store footprint and stayed pinned in process memory long after the saga finished using them. The terminal `Completed` checkpoint now releases those heavy byte-array fields and keeps only the lightweight outcome a completed saga needs (`Phase`, `FailureMessage`, `KeyFingerprint`, `TransactionId`), so idempotent re-entry and reminder-driven reactivation still resolve correctly. The release is crash-safe - the fields are snapshotted and restored verbatim if the terminal persist throws, matching the existing `Phase` rollback guarantee at that site - and the `AtomicWriteBatchSize` histogram still captures the entry count before the release. The `PreconditionFailed` path is left untouched. (`Orleans.Lattice` 9.0.4, [#1511](https://github.com/NSTA1/Orleans.Lattice/pull/1511))

Newer release: [Release 2026-08-18](../changelog/2026-08-18.md). Older release: [Release 2026-08-16](../changelog/2026-08-16.md). Contents: [Changelog](../CHANGELOG.md).
