BoundedCounter

@Serializable
class BoundedCounter : Quilted<BoundedCounter>

A bounded / escrow counter: a shared budget pre-divided into per-replica quotas, with the invariant quota(r) >= 0 enforced locally and the derived global invariant "total spent <= total received" held by construction. No coordination is required for the local check — only for redistributing quota via transfer.

Internally, three per-replica state components — every one a join-semilattice, so piece is just the per-component merge:

  • initial[r]r's seed quota (set by init, immutable after).

  • transfers[s].count(r) — total quota s has ever transferred to r; each (s, r) slot is owned exclusively by s, so concurrent transfers from different donors to the same receiver compose without collision.

  • spent[r] — total r has ever consumed. Transfers out do NOT bump spent — they move through transfers instead — so totalSpent reads as pure consumption.

Derived:

  • quota(r) = initial[r] + Σ_s transfers[s].count(r) − Σ_t transfers[r].count(t) − spent[r]

  • totalBudget = sum(initial) − sum(spent) (transfers conserved)

  • totalSpent = sum(spent)

Rung 5a scope: the data type and local-decrement safety. The transfer-request protocol — how a low replica asks a peer to invoke transfer over a Seam, and rebalancing policy — is deferred to Rung 5b once the Seam replicator (Rung 12) exists.

Samples

val a = ReplicaId("A")
val b = ReplicaId("B")

var counter = BoundedCounter.init(mapOf(a to 5L, b to 3L))

// A spends 2 from its own quota.
val spendPatch = counter.trySpend(a, 2L) ?: error("quota sufficient")
counter = counter.piece(spendPatch)
check(counter.quota(a) == 3L)

// B transfers 1 unit to A.
val transferPatch = counter.transfer(from = b, to = a, amount = 1L) ?: error("quota sufficient")
counter = counter.piece(transferPatch)
check(counter.quota(a) == 4L)
check(counter.quota(b) == 2L)

Types

Link copied to clipboard
object Companion

Properties

Link copied to clipboard

The total budget remaining across the whole system.

Link copied to clipboard

Total consumed across the whole system (does not include transfers).

Functions

Link copied to clipboard
open fun causalDots(): Set<Dot>

The causal Dots this state has delivered — (author, author-seq) per op.

Link copied to clipboard
open operator override fun equals(other: Any?): Boolean
Link copied to clipboard
open override fun hashCode(): Int
Link copied to clipboard
open override fun piece(other: BoundedCounter): BoundedCounter

Per-component join — every component is a join-semilattice.

Link copied to clipboard
fun quota(replica: ReplicaId): Long

replica's remaining quota — what it may still spend locally.

Link copied to clipboard
open override fun toString(): String
Link copied to clipboard
fun transfer(from: ReplicaId, to: ReplicaId, amount: Long): Patch<BoundedCounter>?

Move amount of quota from from to to by appending to from's own row of the transfers matrix. Returns a Patch when from has quota to release; null otherwise. The caller's state is unchanged either way. amount must be positive and from must differ from to.

Link copied to clipboard
fun trySpend(replica: ReplicaId, amount: Long = 1): Patch<BoundedCounter>?

Try to spend amount on behalf of replica. Returns a Patch when the spend is within replica's current quota; null otherwise. The caller's state is unchanged in either case — apply the patch with piece to commit. amount must be positive.