From cb5e62dfacd9d4b628b0f14198d09bdd77ee93f4 Mon Sep 17 00:00:00 2001 From: jochen Date: Thu, 12 Nov 2026 20:32:16 +0100 Subject: [PATCH] views.ProcessReader.HolderBucket names the holder's real bucket of a seat's view FollowSeat follows MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A part that follows a seat's view names its picture in the seat form, but where another part names the holder's own bucket (the watchman's stuck key of the assigner's wants) the name must be the holder's: HolderBucket answers `_` of the holder followed now, "" while none, read at each use so a moved holder is named as it moves. Builds: design 47 G ยง717, A-303 (corrected) Claude-Session: https://claude.ai/code/session_01NcbgfGKaxw984XyAPfLm4h --- go/views/follow_seat.go | 18 ++++++++++++++++++ go/views/views_test.go | 9 +++++++++ 2 files changed, 27 insertions(+) diff --git a/go/views/follow_seat.go b/go/views/follow_seat.go index 974eee90..a3ca3159 100644 --- a/go/views/follow_seat.go +++ b/go/views/follow_seat.go @@ -273,6 +273,24 @@ func (r *ProcessReader) hand(sw *seatFollow, inner *Picture) { } } +// HolderBucket is the bus name `_` of the holder whose state FollowSeat follows now for seat, "" while it +// follows none (design 47 G A-303): the name a part uses where another part names the holder's real bucket (a key the +// watchman writes, a name kept in an entry), read at each use, so a moved holder is named as it moves. +func (r *ProcessReader) HolderBucket(seat, state string) string { + r.mu.Lock() + sw := r.seats[seat+"_"+state] + r.mu.Unlock() + if sw == nil { + return "" + } + sw.mu.Lock() + defer sw.mu.Unlock() + if sw.holder == "" { + return "" + } + return sw.holder + "_" + state +} + // seatPicture is the picture of a seat's view by its bus name, nil when none. func (r *ProcessReader) seatPicture(bucket string) *Picture { r.mu.Lock() diff --git a/go/views/views_test.go b/go/views/views_test.go index 806f67c4..bd4ef33e 100644 --- a/go/views/views_test.go +++ b/go/views/views_test.go @@ -1023,6 +1023,9 @@ func subViews(t *testing.T) { if _, err := p.Get(context.Background(), "hold.a"); err == nil { t.Errorf("a seat's view with no holder reads as held") } + if b := r.HolderBucket("mesh-wants", "asks"); b != "" { + t.Errorf("with no holder the holder's bucket is %q", b) + } ctx, cancel := context.WithCancel(context.Background()) defer cancel() r.Ask(ctx, nil) @@ -1054,6 +1057,9 @@ func subViews(t *testing.T) { sh.Follower().Apply(Event{V: Version, Owner: "assigner", State: "seat-holders", Key: "mesh-wants", Revision: 2, Created: made, Value: json.RawMessage(`{"holders":[{"module":"h1"}]}`)}) ready(`{"n":1}`) + if b := r.HolderBucket("mesh-wants", "asks"); b != "h1_asks" { // A-303: the holder's real bucket, at run time + t.Errorf("the holder's bucket is %q, want h1_asks", b) + } if len(fs.m) != 0 { t.Errorf("the holder's first view left the findings %v", fs.m) } @@ -1069,6 +1075,9 @@ func subViews(t *testing.T) { sh.Follower().Apply(Event{V: Version, Owner: "assigner", State: "seat-holders", Key: "mesh-wants", Revision: 3, Created: made, Value: json.RawMessage(`{"holders":[{"module":"h2"}]}`)}) ready(`{"n":3}`) + if b := r.HolderBucket("mesh-wants", "asks"); b != "h2_asks" { + t.Errorf("after the move the holder's bucket is %q, want h2_asks", b) + } if keys, _ := p.Keys(ctx); strings.Join(keys, ",") != "hold.a" || r.Picture("h1_asks") != nil { t.Errorf("after the move the picture holds %v, h1 followed %v", keys, r.Picture("h1_asks") != nil) }