Name the epoch given back in the lease's delete marker, so only a holder's own release counts as a handover (issue 906, ADR 0558 §3, review round 1)
mesh/delivery merged: source.main moved to novox/mesh-controller@0fbb5ef35991
mesh/check being carried to 8f847318963c on 0fbb5ef35991 | from 2dafbe60e939

A plain delete marker on the lease key is also written by a command's own
lease and by a take given back over the floor; counted as a handover, it
would record a crashed holder's epoch released and say nothing. Release now
writes the marker itself, compare-and-set on the key's revision, with the
header Mesh-Lease-Released naming its epoch, and the next holder ends only
that epoch as released. A takeover whose predecessor cannot be read is now
raised as an expiry, not only printed.
This commit is contained in:
2026-10-27 00:55:30 +01:00
parent fbaa463a38
commit 8f84731896
5 changed files with 74 additions and 34 deletions
+2 -2
View File
@@ -325,8 +325,8 @@ func (a *actor) took(ctx context.Context, l *lease.Lease, inv *inventory.Invento
if err != nil {
fmt.Printf("epoch %d could not be recorded as taken, so a stale refusal from it will not name it: %v\n", epoch, err)
}
if l.GivenBack() {
fmt.Printf("the lease was given back by the controller before this one: taken at once, at epoch %d\n", epoch)
if given := l.GivenBack(); given != 0 {
fmt.Printf("the lease was given back by the controller of epoch %d: taken at once, at epoch %d\n", given, epoch)
}
for _, e := range expired {
fmt.Printf("the controller of epoch %d (%s) stopped renewing the lease without giving it back: it is "+
+11 -1
View File
@@ -722,7 +722,17 @@ func (a *actor) sayTakeover(ctx context.Context, epoch uint64) {
defer cancel()
ended, err := inv.EpochsSince(reading, now.Add(-advisoryQuiet))
if err != nil {
fmt.Printf("how the epoch before %d ended cannot be read, so its takeover is not said: %v\n", epoch, err)
// Failure is loud: S12 no longer observes an epoch below the one held, so an unread takeover is said as
// one that was not a handover — raised, and left for S12 to clear (ADR 0558 §3).
fmt.Printf("how the epoch before %d ended cannot be read, so its takeover is said as an expiry: %v\n", epoch, err)
o := conditions.Observation{Scope: conditions.ScopeCore, ID: "controller.lease", Token: "lost",
Kind: "lease-lost", Severity: conditions.Urgent, Source: "S12",
Summary: fmt.Sprintf("the controller of epoch %d took the lease, and how the controller before it ended "+
"cannot be read: it is said as one that stopped renewing without giving it back", epoch),
Said: err.Error()}
if _, err := keeper.Observe(reading, o); err != nil {
fmt.Printf("the takeover at epoch %d could not be said: %v\n", epoch, err)
}
return
}
sayTakeoverOf(reading, keeper, ended, epoch, now)