retire

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.

The local drain check is advisory, and a missed race strands entitlement. If a peer's in-flight delegate has not yet merged into this proposer's view, the check reads outstanding == 0, the retire is admitted, and on the converged state the edge is RETIRED with entitlement still outstanding: a LedgerConflict.ClosureViolation, and the budget is stranded on a generation no longer on the live lineage (release refuses a retired edge). Worse, once the raced child is legally reparented onto a fresh inbound edge, holdings at the child derive persistently negative — a permanent LedgerConflict.PersistentNegativeHoldings / LedgerConflict.PerEdgeSafety with zero real overspend (issue #1665). The strand does not self-heal. reconcile re-homes it onto the child's live lineage through the log — net inflow and any service already spent through the stranded edge — restoring conservation and clearing the conflicts. Only a transfer-tangled strand stays carved out. Until reconciled it is the same safe stranding class as a crashed peer's holdings (§8.1).