From 4922bcbf4413e569fd5216304846f76d5a00b54d Mon Sep 17 00:00:00 2001 From: jochen Date: Thu, 12 Nov 2026 11:39:57 +0100 Subject: [PATCH] A-278: seatlist.Definition is the one seat-definition function AnswerSeat takes The definition of a seat on the list a part follows, read through the part's reader at each call: none until the list is read, none for a seat the list does not hold. Every holder passes it instead of writing its own. Builds: design 47 G A-278, A-186, A-179 Claude-Session: https://claude.ai/code/session_01NcbgfGKaxw984XyAPfLm4h --- go/seatlist/part.go | 17 +++++++++++++++++ go/seatlist/seatlist_test.go | 14 ++++++++++++++ 2 files changed, 31 insertions(+) diff --git a/go/seatlist/part.go b/go/seatlist/part.go index c4a3ad6f..00a4d6ab 100644 --- a/go/seatlist/part.go +++ b/go/seatlist/part.go @@ -6,6 +6,7 @@ import ( stdio "git.novox.be/novox/mesh-sdk/go" "git.novox.be/novox/mesh-sdk/go/catalogue" + "git.novox.be/novox/mesh-sdk/go/seatdef" ) // A part that reads the seat list wires its reader one way (novox/hq ADR 0636 §1, §7): started from the bootstrapped @@ -57,6 +58,22 @@ func (p *Part) Reader() *Reader { return p.reader.Load() } +// Definition is the seat-definition function process.Conn.AnswerSeat takes, written once for every holder (design 47 G +// A-278, A-186): the definition of seat on the list the part follows, read at each call through reader (a Part's +// Reader, or a part's own reader), none until the list is read and none for a seat the list does not hold. +func Definition(reader func() *Reader, seat string) func() (seatdef.Definition, bool) { + return func() (seatdef.Definition, bool) { + r := reader() + if r == nil || !r.Status().Heard { + return seatdef.Definition{}, false + } + r.mu.Lock() + defer r.mu.Unlock() + d, ok := r.defs[seat] + return d, ok + } +} + // MayAct is the reader's MayAct, false before it is started. func (p *Part) MayAct(seats ...string) bool { r := p.Reader() diff --git a/go/seatlist/seatlist_test.go b/go/seatlist/seatlist_test.go index 2cb73afb..9382bf08 100644 --- a/go/seatlist/seatlist_test.go +++ b/go/seatlist/seatlist_test.go @@ -201,11 +201,25 @@ func TestTheBootstrapIsHeldAndNothingNewIsActedOnUntilTheSeatAnswers(t *testing. t.Fatalf("waiting: MayAct(%v) = %v, want %v", a.seats, got, a.want) } } + // A-278: the seat-definition function AnswerSeat takes answers none until the list is read, and none without a reader. + reader := func() *Reader { return r } + if _, ok := Definition(reader, "node-engine")(); ok { + t.Fatal("Definition answered a bootstrapped definition before the seat list was read") + } + if _, ok := Definition(func() *Reader { return nil }, "node-engine")(); ok { + t.Fatal("Definition answered with no reader") + } owner.down = false owner.table = map[string]string{"node-b": def("node-b", "node", "put")} if err := r.Reload(); err != nil { t.Fatal(err) } + if d, ok := Definition(reader, "node-b")(); !ok || d.Seat != "node-b" { + t.Fatalf("Definition(node-b) after the list was read = %+v, %v, want node-b's", d, ok) + } + if _, ok := Definition(reader, "node-files")(); ok { + t.Fatal("Definition answered a seat the list does not hold") + } if st := r.Status(); !st.Heard || len(st.Waiting) != len(boot) || st.LastError != "" || st.Revision != 7 { t.Fatalf("status after the seat answered %+v: want heard, the bootstrap's seats it does not hold still waiting, no error, revision 7", st) }