diff --git a/internal/selfcompose/selfcompose.go b/internal/selfcompose/selfcompose.go index 109ef20..302f142 100644 --- a/internal/selfcompose/selfcompose.go +++ b/internal/selfcompose/selfcompose.go @@ -1769,10 +1769,14 @@ func mapValues(m map[string]delivery.Composed) []delivery.Composed { // WaitsForTheSeatList is why a module is held while the node has not read the seat list. const WaitsForTheSeatList = "the node has not read the seat list, so it composes nothing new of this module and keeps what runs of it (novox/hq ADR 0636 §1)" +// WaitsForTheSeatListOwn is why the node's own composition is held: it folds modules and accounts whose seats the node +// cannot judge before the list was read, so only the last applied one runs (ADR 0636 §1). +const WaitsForTheSeatListOwn = "the node has not read the seat list, so it composes nothing new of itself and keeps what runs (novox/hq ADR 0636 §1)" + // holdUntilListed takes out of compositions every module's composition that is new (no running composition has its // digest) while the reader may not act on its seats, and names the module in held: it keeps running what it runs, and -// the pass after the list was read hands it. The node's own composition and a module whose composition runs already are -// left as they are. +// the pass after the list was read hands it. The node's own composition is held the same way, whatever it folds, under +// the scope agent.NodeModule; a composition that runs already is left as it is. func (c *Composer) holdUntilListed(ctx context.Context, r reader, compositions map[string]delivery.Composed, held map[string]string, running []delivery.Composed) map[string]string { if c.env.SeatList == nil { return held @@ -1784,21 +1788,24 @@ func (c *Composer) holdUntilListed(ctx context.Context, r reader, compositions m } } for key, comp := range compositions { - if comp.Module == "" { - continue - } if dig, err := delivery.ComposedDigestOf(comp); err == nil && ran[comp.Module+"/"+dig] { continue } - if c.env.SeatList.MayAct(c.seatsOf(ctx, r, comp.Module)...) { + module, why := comp.Module, WaitsForTheSeatList + if module == "" { // the node's own: no seat to judge, so while the list is unread it waits whole + if c.env.SeatList.MayAct() { + continue + } + module, why = agent.NodeModule, WaitsForTheSeatListOwn + } else if c.env.SeatList.MayAct(c.seatsOf(ctx, r, module)...) { continue } delete(compositions, key) if held == nil { held = map[string]string{} } - if _, already := held[comp.Module]; !already { - held[comp.Module] = WaitsForTheSeatList + if _, already := held[module]; !already { + held[module] = why } } return held diff --git a/internal/selfcompose/selfcompose_test.go b/internal/selfcompose/selfcompose_test.go index dfb90a8..a33a7e5 100644 --- a/internal/selfcompose/selfcompose_test.go +++ b/internal/selfcompose/selfcompose_test.go @@ -1812,17 +1812,25 @@ func TestAnUnreadSeatListHoldsWhatIsNewAndHandsItAtTheRead(t *testing.T) { t.Errorf("the node handed %s before it read the seat list", k) } } - if !handed["n1.node"] { - t.Errorf("the node's own composition was held with the module: %v", handed) + // The node's own composition folds modules and accounts it cannot judge before the read: held whole (the ruling of + // ADR 0636 §1), under the scope agent.NodeModule. + mu.Lock() + ownWhy := heldBy[agent.NodeModule] + mu.Unlock() + if ownWhy != WaitsForTheSeatListOwn || handed["n1.node"] { + t.Errorf("the node's own composition is held with %q and handed=%v, want %q and not handed: %v", ownWhy, handed["n1.node"], WaitsForTheSeatListOwn, handed) } - // The reader reads the list and says so: the module is handed, with no timer. + // The reader reads the list and says so: the module and the node's own are handed, with no timer. g.open.Store(true) changed <- struct{}{} - for { + seen := map[string]bool{} + for !(seen["lemurs"] && seen["node"]) { u := next(t, out) - if strings.Contains(u.Key, "lemurs") && !u.Deleted { - break + if u.Deleted { + continue } + seen["lemurs"] = seen["lemurs"] || strings.Contains(u.Key, "lemurs") + seen["node"] = seen["node"] || u.Key == "n1.node" } mu.Lock() still := heldBy["lemurs"]