HeddleNode

One peer's live view of a weighted fair-share session over a Seam — the join point of the fair-share layer (design §15 Phase 4). It bonds four coordination-free pieces onto one fabric:

  • The replicated ledger (ledger) — an EntitlementLedger driven over the seam by a Quilter: delta-exchange while connected, anti-entropy reconciliation on heal. Every peer converges to one agreed tally by the lattice laws, no referee.

  • The demand board — each peer advertises, into its own slot of an EphemeralMap, how much service each child edge could usefully take (advertise); a peer's demand ages out by local receive time if it stops refreshing, so a crashed peer's stale appetite cannot keep steering entitlement (design §6). Demand is advisory; it can never authorize a spend.

  • The reservation table — leaf work reserves against holdings (reserve), runs, then completes (complete) charging the ledger exactly once; a second complete for the same ReservationId is a no-op, so delivering a completion N times raises history once (design §4.4).

  • Liveness — one HeartbeatPartitionDetector per peer distinguishes a partition (recoverable) from a crash; partitionEvents surfaces the signal. v1 ships no automatic reclamation: a crashed peer's holdings and earmarks stay stranded, because a wrong reclaim is an overspend — the one unforgivable failure (design §8.1).

Scheduling is an explicit, pure, bounded call (schedule) — a consumer drives its own cadence — so the node owns no re-arming allocation loop; the only owned loops are the replicator's anti-entropy, the demand collector, and the liveness detectors.

Thread-safety

The node is correct under a genuinely multi-threaded dispatcher. Its local mutable state — the reservation table, per-leaf earmarks, the self demand slot, and the demand clock — is guarded by one reentrantLock (no suspend call is made while it is held; the Quilter mutators it calls under the lock are synchronous). The replicated ledger and the demand tracker each carry their own synchronization. There is no limitedParallelism(1) confinement.

Construct via heddleStatic (design §9); the constructor is internal.

Samples

val root = GroupId("root")
val leaf = GroupId("leaf")
val self = ReplicaId(seam.selfId.value)
val e = AttachmentRecord(AttachmentId("root→leaf"), root, leaf, Weight.ONE)

val node = heddleStatic(
    seam = seam,
    self = self,
    root = root,
    mint = mapOf(self to 100L),        // this peer starts holding 100 units at the root
    topology = listOf(e),              // root → leaf, prepared and active at bootstrap
    clock = { Instant.fromEpochMilliseconds(0L) },
    config = HeddleConfig(policy = PolicyConfig(quantum = 10L), maxHoldingsPerPeer = 1_000L),
    epoch = 1L,                        // a persisted monotonic boot counter — bumped every restart
)

// The leaf wants work; one scheduling round delegates entitlement down toward it.
node.advertise(e.id, Demand(targetOutstanding = 100L, maximumUsefulGrant = 100L))
node.schedule(root)

// Leaf work reserves a slice, runs, then completes — completing twice charges once.
val reservation = node.reserve(leaf, maximumCost = 10L)
if (reservation != null) {
    node.complete(reservation, actualCost = 7L)
    node.complete(reservation, actualCost = 7L) // idempotent no-op
}

Types

Link copied to clipboard
object Companion

Properties

Link copied to clipboard
val ledger: StateFlow<EntitlementLedger>

The replicated entitlement ledger as it has converged on this peer. Read holdings / activeChildren / validate off the latest value; collect the flow to observe convergence.

Link copied to clipboard

Peer-liveness signals as they are detected (design §8.1). A PartitionEvent.PeerUnresponsive is a recoverable partition; a PartitionEvent.PeerLost is a crash. The node takes no ledger action on either — stranding a crashed peer's holdings is the safe choice (a wrong reclaim is an overspend); recovery is an explicit later feature (design §9).

Link copied to clipboard

This peer's replica identity (design §9); matches its Seam.selfId by string value.

Link copied to clipboard
val unreachable: StateFlow<Set<ReplicaId>>

Peers currently flagged unresponsive or lost by the liveness detectors.

Functions

Link copied to clipboard

Open delegation across edge (EntitlementLedger.activate); returns whether it applied.

Link copied to clipboard
fun advertise(edge: AttachmentId, demand: Demand)

Advertise that this peer could usefully take demand more service down child edge edge. Updates this peer's own demand slot, folds it into the local tracker, and broadcasts it best-effort over the demand channel. Advisory only — it can never authorize a spend (design §6). Re-advertise periodically to keep the slot live; a slot that stops refreshing ages out after HeddleConfig.demandTtl.

Link copied to clipboard

The current §8.2 bound metrics at parent, from the merged ledger, the roster (live peers plus currently-unreachable ones, since a partitioned peer is exactly the divergence source the bound must count), and the set of children with live demand.

Link copied to clipboard
open override fun cancel(id: ReservationId)

Cancel reservation id — a completion charging zero service (design §4.4).

Link copied to clipboard

Stop new delegation across edge (EntitlementLedger.close); returns whether it applied.

Link copied to clipboard
open override fun complete(id: ReservationId, actualCost: Long)

Complete reservation id, charging actualCost service (0 ≤ actualCost ≤ the reserved maximum) against the path captured at reserve and releasing the earmark. Idempotent by local single-writer discipline (design §4.4): the first call charges once and removes the reservation; any later call for the same id finds nothing and is a no-op, so delivering a completion N times raises history exactly once. An unknown id is silently ignored.

Link copied to clipboard
open override fun earmarked(leaf: GroupId): Long

This peer's total outstanding earmark at leaf leaf — reserved-but-not-yet-completed service. Local state (design §4.4): it is not replicated and does not appear in any other peer's ledger; the reserved units simply stay outstanding on the leaf edge. The spendable-now amount is holdings(leaf, self) − earmarked(leaf).

Link copied to clipboard

parent's current virtual time V on this peer (design §7.2; issue #1688) — a diagnostic read of this view's front. null when parent has no active children in this peer's view and there is therefore no front to take.

Link copied to clipboard

Introduce a new generation (EntitlementLedger.prepare); returns whether it applied.

Link copied to clipboard
open override fun reserve(leaf: GroupId, maximumCost: Long): ReservationId?

Earmark up to maximumCost service units against this peer's holdings at leaf leaf, returning a ReservationId to complete against, or null if the peer's available holdings (holdings minus outstanding earmarks) at leaf cannot cover it. The earmark is local state, not replicated (design §4.4): the reserved units simply stay outstanding on the leaf edge until spent, which the accounting already charges. A crashed peer strands its earmarks (design §8.1).

Link copied to clipboard

Retire a drained edge (EntitlementLedger.retire); returns whether it applied.

Link copied to clipboard
fun schedule(parent: GroupId): Int

Run allocation rounds at parent until nothing more can be delegated: build the policy input from the active children, their EdgeSummarys, and the folded live demand, then apply each HeddlePolicy.pick grant to the ledger before the next round (design §7.3). A bad local decision only misplaces entitlement — it can never create any, so partitioned peers may schedule divergently and still converge on heal.