From bb7bd8dac3388f0ece4dd976104e528851afb2e8 Mon Sep 17 00:00:00 2001 From: jochen Date: Wed, 11 Nov 2026 22:21:38 +0100 Subject: [PATCH] Fix the kind: the seat set a host gives (catalogue.UseSeats) is held atomically, so a reload never races a lookup MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Builds: design 47 G §419 --- go/catalogue/seats.go | 24 +++++++++++++++++------- 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/go/catalogue/seats.go b/go/catalogue/seats.go index 17a21e15..aa225667 100644 --- a/go/catalogue/seats.go +++ b/go/catalogue/seats.go @@ -3,6 +3,7 @@ package catalogue import ( "fmt" "strings" + "sync/atomic" ) // Seat is one role the mesh defines. @@ -87,7 +88,15 @@ type Receivable struct { // seat list and imports no contracts module (novox/hq ADR 0635 §1). A host reads the list from the bus // (mesh-sdk go/seatlist, which holds the foundation's bootstrapped definitions until the indexer is heard) and gives // its seats here at start and at each change. -var seats []Seat +var seats atomic.Pointer[[]Seat] + +// working is the set in force, none before a host gives one. +func working() []Seat { + if p := seats.Load(); p != nil { + return *p + } + return nil +} // UseSeats replaces the working set with the seat list a host read (seatlist.Reader.Seats, via SeatsFromDefinitions). // @@ -98,7 +107,8 @@ func UseSeats(s []Seat) { if len(s) == 0 { return } - seats = append([]Seat(nil), s...) + set := append([]Seat(nil), s...) + seats.Store(&set) } // aliases maps a seat's former names to its current canonical name (novox/hq ADR 0122). Loaded from @@ -108,20 +118,20 @@ var aliases = map[string]string{} // Seats is every seat the mesh defines, in reading order. func Seats() []Seat { - return append([]Seat(nil), seats...) + return append([]Seat(nil), working()...) } // SeatNamed is the seat a name refers to, whether that is its current name or one it used to have // (novox/hq ADR 0122). A former name resolves to the seat's canonical row, so a rename breaks no // reference to the old name. func SeatNamed(name string) (Seat, bool) { - for _, s := range seats { + for _, s := range working() { if s.Name == name { return s, true } } if canonical, aliased := aliases[name]; aliased { - for _, s := range seats { + for _, s := range working() { if s.Name == canonical { return s, true } @@ -135,7 +145,7 @@ func SeatDelivering(provision string) (Seat, bool) { if provision == "" { return Seat{}, false } - for _, s := range seats { + for _, s := range working() { if s.Delivers == provision { return s, true } @@ -208,7 +218,7 @@ func providesAt(m Manifest, provision, scope string) bool { // nothing on the bus and needs no queue. func SeatsWithAProtocol() []Seat { var out []Seat - for _, s := range seats { + for _, s := range working() { if len(s.Accepts) > 0 || len(s.Emits) > 0 || len(s.Serves) > 0 { out = append(out, s) }