Table of Contents

Release 2026-09-30

This page is part of the documentation for Orleans.Lattice 9.9.0 (release line 9.9), built 2026-10-04. It is also published as markdown, with every table and list, at 2026-09-30.md, and llms.txt lists every page.

Part of the changelog.

Patch release from the release/9.8 line: Orleans.Lattice and Orleans.Lattice.Dashboards advance to 9.8.2, and Orleans.Lattice.Tenancy and Orleans.Lattice.Auth to 9.8.1. Every other package stays where the 9.8.1 wave left it. Packages that depend on a patched package still require its earlier version, so reference a patched package directly to pick up its fixes.

Upgrading from 9.8.1. A rolling upgrade is supported: no wire format or persisted state layout changes, and the public surface grows only additively: a new LatticeTenancyOptions.PolicySnapshotLeaseDuration option, and an ITenantGateEnforcer.EnforceAsync whose default implementation delegates to Enforce, so an existing enforcer is unaffected. The headline fix closes a durability hole in which a failed checkpoint persist left a leaf advertising a WAL trim entitlement it had never written, so the garbage collector could trim a prefix no snapshot covered and the next replay latched stale. A leaf already latched stale still needs an operator rebuild; this patch prevents new occurrences rather than repairing existing ones. Expected replay-permit refusals now log one summary warning a minute per silo instead of a stack trace each, so an alert matching that stack no longer fires. The tenancy and auth patches close four multi-silo authorization gaps: a registry write refreshed the policy, residency and placement views only on the committing silo, and the gate trusted a stale policy snapshot while a rebuild was pending, so a silo could keep admitting revoked grants and removed or suspended members. Both now confirm against the registry and fail closed.

Added

  • Leaf - Deactivation barriers are timed. orleans.lattice.leaf.deactivation.barrier.duration times each graceful-deactivation barrier whatever its outcome, so a drain's cost splits across checkpoint flush, snapshot capture, frontier pin and digest publish, charted on CommitPath. (#3628) (Orleans.Lattice, Orleans.Lattice.Dashboards)

  • Config - Tenant snapshot lease. LatticeTenancyOptions.PolicySnapshotLeaseDuration (default 10 s) bounds how long a silo trusts its tenant snapshots without renewing its cluster-epoch lease; a longer lease delays a write that must wait out an unreachable silo. (#4030) (Orleans.Lattice.Tenancy)

Changed

  • Performance - Aggregation contribution slots. A numeric contribution touches at most two accumulator slots, yet accumulated them in a dictionary and then walked it back out to rebuild the same keys for cleanup. Two locals now carry both, removing 44% of the flip's allocation. (#3910) (Orleans.Lattice)

  • Performance - Aggregation shard slot derivation. A re-grouping contribution derived its shard slot once per accumulator key, transcoding the source key to UTF-8 and hashing it twice for an answer that cannot differ. It is derived once, making the pair 39% faster. (#3910) (Orleans.Lattice)

  • Performance - Leaf frame state-bytes walk. The row walker that sums a frame's state bytes is now pinned as an inline root, so the JIT inlines its per-row parser into the walk instead of inlining the walk into its callers. The walk is 68% faster over a 4096-row frame. (#3898) (Orleans.Lattice)

  • Performance - Compacted OR-set decode. Decoding a compacted OR-set overflowed its presized buffer and let list doubling widen it. It now widens once to the provable ceiling, cutting 29% of the decode's allocation and 31% of its time. (#3898) (Orleans.Lattice)

  • Performance - Event publish fan-out. A multi-key set, conditional set or CRDT delta apply published its per-key stream events one await at a time. They now go out in bounded concurrent windows of 32, so a 500-key request costs 16 grain-call rounds instead of 500. (#3898) (Orleans.Lattice)

  • Performance - Leaf frame structural row walk. The frame codec's row parser took its materialise-or-skip mode as a runtime flag, so the skipping walk behind frame validation still ran every branch of the materialising one. The mode is now a type argument the JIT specialises away, halving the walk. (#3910) (Orleans.Lattice)

Fixed

  • WAL - Trim could outrun a leaf's durable checkpoint. A checkpoint persist that failed left the leaf advertising an advance it never wrote, so the GC could trim a prefix no snapshot covered and the next replay latched stale. The advance is now rolled back and retried. (#4017) (Orleans.Lattice)

  • Replay - Admission refusals logged a stack trace each. An expected replay-permit refusal no longer logs its exception. Refusals are counted into at most one summary warning a minute per silo, which names the arm that fired and its remedy. (#3906) (Orleans.Lattice)

  • Config - Core timeouts above the timer ceiling. A WAL, shard, digest, scan or fan-out timeout, budget or cadence longer than a timer can wait (about 49.7 days), such as TimeSpan.MaxValue, passed validation and then failed every operation that armed it. Validation now rejects it. (#4012) (Orleans.Lattice)

  • Config - Tenant usage metering above the timer ceiling. A MeterInterval longer than a timer can wait (about 49.7 days) ended metering on its first cycle, leaving quotas unenforced, and a reload to zero re-metered with no pause. The interval now clamps, and a non-positive reload stops the loop. (#4042) (Orleans.Lattice.Tenancy)

Security

  • Security - Tenant changes lagged on other silos. A tenant-registry write refreshed the policy, residency and placement views only on the committing silo, so other silos kept admitting revoked access and placing trees by stale rules. Every silo now tracks a leased cluster epoch and fails closed. (#4030, #4051, #4052) (Orleans.Lattice.Tenancy)

  • Security - Stale tenant decisions during a snapshot rebuild. A registry change only schedules a policy-snapshot rebuild, and the gate trusted the stale snapshot meanwhile, admitting revoked grants and removed or suspended members. It now confirms against the registry, or denies. (#4001, #4053) (Orleans.Lattice.Tenancy, Orleans.Lattice.Auth)