Table of Contents

RW-Flag (Remove-Wins Flag, disable-wins)

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 rwflag.md, and llms.txt lists every page.

tree.RwFlag(key) -> RwFlagAccessor, merge mode LatticeMergeMode.RwFlag.

Semantics

An RW-Flag is the mirror image of the OR-Flag: a single boolean presence bit that converges disable-wins. When an enable and a disable race, the disable wins and the flag stays off.

It carries three dot sets: enables, disables, and tombstones that cancel disables. The flag is on only when at least one enable dot exists and no disable dot survives. A Disable an enable has not observed survives the merge and keeps the flag off, so a revoke is never silently resurrected by a concurrent re-add.

Both Enable and Disable take a replicaId (each side stamps its own dots).

Use it for: revocation lists, blocklists, "banned" / "deleted" markers, kill switches - any presence bit where a removal must be the safe, winning outcome.

Behaviour

A concurrent RW-Flag enable and disable: disable wins. An order diagram shaped like a diamond. At the bottom the flag is off, with no dots. Cluster A enables it with dot A1, which reads on. Cluster B, at the same time, disables it with dot B1, having observed no enable. Neither state is above the other. Merging keeps both dots, and because no enable has observed and cancelled B1, the join reads off: disable wins.

Both clusters hold enable A1 and disable B1: DISABLED. A surviving disable dot keeps the flag off, so a revoke is never resurrected by a concurrent enable.

The flag is on only while an enable dot exists and no disable dot survives, so the disable wins the race.

sequenceDiagram
    participant A as Cluster A
    participant B as Cluster B
    A->>A: Enable (dot A1)
    B->>B: Disable (dot B1, observed: none)
    A-->>B: merge ships enable A1
    B-->>A: merge ships disable B1
    Note over A,B: B1 was not observed/cancelled by any enable
    Note over A,B: converged = DISABLED (disable-wins)

Example

var access = tree.RwFlag("user:88:access");

// Cluster A grants access; cluster B concurrently revokes it.
await access.EnableAsync("cluster-A", cancellationToken);
await access.DisableAsync("cluster-B", cancellationToken);

// The revoke was not observed by the grant, so it survives the merge and the
// flag converges DISABLED - a revocation is never lost to a concurrent grant.
bool granted = await access.IsEnabledAsync(cancellationToken);

See also: its enable-wins mirror OR-Flag and the CRDT overview.