GovernedHeddleNode

A Raft-governed HeddleNode: the H4 data-plane surface (reserve/complete/schedule/advertise plus the replicated ledger and liveness) with the H5 control-plane verbs (mint + topology) routed through the consensus log. Returned by heddleGoverned.

The control verbs suspend until their act commits and return a ControlOutcomeApplied when admitted, or Conflict carrying a structured ControlConflict when the log serialized the act as a loser. The data-plane verbs are the exact H4 calls and never coordinate.

The ungoverned lifecycle mutators (HeddleNode.prepare/activate/…) are deliberately not re-exposed here: routing them around the log would recreate the very LedgerConflict.DualActiveInbound fork the control plane serializes away. Only the governed verbs and the read/spend surface are public.

Properties

Link copied to clipboard

Whether this peer may author entitlement yet — the boot gate of docs/heddle-ledger-relocation-design.md §6.5 residual 3 and §13.2. It opens when this peer's own enroll(self) has committed and been applied here, and it closes again on restart.

Link copied to clipboard
val ledger: StateFlow<EntitlementLedger>

The replicated entitlement ledger as converged on this peer (the gossip-merged data-plane view).

Link copied to clipboard

Peer-liveness signals (design §8.1); the node takes no ledger action on either.

Link copied to clipboard

The readIndex()-fenced revocation seam (design §9 #3) — reclaiming a crashed peer's stranded holdings remains specified, not shipped in v1 (part of #1602). The advisory-retire strand is a distinct, log-serialized recovery: see reconcile.

Link copied to clipboard

This peer's replica identity.

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

Peers currently flagged unresponsive or lost by the liveness detectors.

Functions

Link copied to clipboard
suspend fun activate(edge: AttachmentId, timeout: Duration? = null): ControlOutcome

Open delegation across edge, serialized through the log (design §9 #2). The reshape serialization point: if the log-order state already gives edge's child a live inbound generation, this act loses and returns ControlOutcome.Conflict with a ControlConflict.DualInbound.

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

Advertise this peer's per-edge appetite (HeddleNode.advertise).

Link copied to clipboard

The §8.2 bound metrics at parent (HeddleNode.boundMetrics).

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

Cancel reservation id (HeddleNode.cancel).

Link copied to clipboard
suspend fun close(edge: AttachmentId, timeout: Duration? = null): ControlOutcome

Stop new delegation across edge, serialized through the log (EntitlementLedger.close).

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

Complete reservation id, charging actualCost (HeddleNode.complete).

Link copied to clipboard
suspend fun depart(timeout: Duration? = null): ControlOutcome

Remove this peer from the log-known roster, serialized through the log. Idempotent.

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

This peer's outstanding earmark at leaf leaf (HeddleNode.earmarked).

Link copied to clipboard
suspend fun enroll(replica: ReplicaId, timeout: Duration? = null): ControlOutcome

Add replica to the log-known roster, serialized through the log — the set a later barrier quantifies its acknowledgments over (docs/heddle-ledger-relocation-design.md §6.2). Idempotent: enrolling an already-enrolled replica is ControlOutcome.Applied.

Link copied to clipboard

The replicas enrolled as of the control log this peer has applied — the log-order membership fact, not the seam's open, moment-to-moment peer set. Two peers that have applied the same log prefix return the same set.

Link copied to clipboard
suspend fun mint(holder: ReplicaId, amount: Long, timeout: Duration? = null): ControlOutcome

Mint amount root supply to holder, serialized through the log (design §9 #1). Suspends until the act commits; a partitioned minority never returns (it can never reach quorum), so a split can never both mint. Bound with timeout to surface a leader crash instead of hanging — but a timeout only cancels the await, not the proposal: the act may still commit, and a fresh mint call is a new act (a retried mint can double-mint), so resubmit only if a read confirms the first did not land. Returns ControlOutcome.Applied.

Link copied to clipboard

parent's current virtual time on this peer (HeddleNode.parentVirtualTime) — an unfenced read of the gossip-merged view, for diagnostics. A null is not by itself evidence that parent has no children, and nothing needs it to be: seating is the scheduler's Gauge bump, not something a caller carries into a record (issue #1752).

Link copied to clipboard

The replicas edge's barrier is still waiting on — the set enrolled when the barrier committed, minus those that have acked. null if edge has never been quiesced; empty once the fence is complete and a reconcile can proceed.

Link copied to clipboard
suspend fun prepare(record: AttachmentRecord, timeout: Duration? = null): ControlOutcome

Introduce a new attachment generation, serialized through the log (EntitlementLedger.prepare).

Link copied to clipboard
suspend fun quiesce(edge: AttachmentId, timeout: Duration? = null): ControlOutcome

Open the quiesce barrier over edge, serialized through the log: every peer that applies it marks edge locally unwritable and answers with its own final slot values (docs/heddle-ledger-relocation-design.md §6.2). Refused unless edge is RETIRED in log order.

Link copied to clipboard
suspend fun reconcile(child: GroupId, timeout: Duration? = null): ControlOutcome

Reconcile the budget stranded on child's RETIRED inbound edge(s) by re-homing everything they carry — net inflow and already-charged service — onto child's live inbound generation, serialized through the log (design §9 #3, §5.4; issue #1665). It removes the permanent LedgerConflict.PersistentNegativeHoldings / LedgerConflict.PerEdgeSafety / ClosureViolation left by a raced advisory-retire followed by a legal reparent.

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

Earmark up to maximumCost against holdings at leaf leaf (HeddleNode.reserve), or null while the isWritable boot gate is closed — this peer must have enrolled before it may author entitlement.

Link copied to clipboard
suspend fun retire(edge: AttachmentId, timeout: Duration? = null): ControlOutcome

Retire edge, serialized through the log (EntitlementLedger.retire). Refused locally (before proposing, returning a ControlConflict.Refused at index ControlOutcome.NOT_COMMITTED) when the data-plane view shows the edge is not drained (EdgeSummary.outstanding != 0): retiring a non-drained edge would strand its outstanding entitlement, because a RETIRED edge drops off the live lineage the data plane drains through. Once past the local drain check, the committed retire is gated purely on the log-order lifecycle being CLOSING — a deterministic apply.

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

Run allocation rounds at parent, delegating holdings toward demand (HeddleNode.schedule). Returns 0 without delegating while the isWritable boot gate is closed.