From 45fb352cbfe7a12a2524d8c4aa44c4a4a2067bf9 Mon Sep 17 00:00:00 2001 From: jochen Date: Fri, 13 Nov 2026 11:37:24 +0100 Subject: [PATCH] S4 sdk-seat-read: SeatRead splits a read of a seat holder's state Builds: design 47 G A-116, A-128 (A-343, A-344) Claude-Session: https://claude.ai/code/session_01NcbgfGKaxw984XyAPfLm4h --- go/catalogue/state.go | 19 +++++++++++++++++++ go/catalogue/state_test.go | 23 +++++++++++++++++++++++ 2 files changed, 42 insertions(+) diff --git a/go/catalogue/state.go b/go/catalogue/state.go index 6e53af5a..1fa7c2fc 100644 --- a/go/catalogue/state.go +++ b/go/catalogue/state.go @@ -78,6 +78,25 @@ func (s StateDeclaration) MarshalJSON() ([]byte, error) { return json.Marshal(plain(s)) } +// SeatReadPrefix opens a read of the state a seat's holder keeps: `seat:.` (design 47 G A-116, A-128). +const SeatReadPrefix = "seat:" + +// SeatRead splits a read of a seat holder's state, `seat:.`, into the seat and the local name; ok is false for a +// read that is not of this kind (a module's `.`, which ReadState splits), and err says why a `seat:` read is +// malformed. The holder is not in it: it is resolved where the read is made, so a new holder is read with no change of the +// manifest. +func SeatRead(read string) (seat, local string, ok bool, err error) { + rest, isSeat := strings.CutPrefix(read, SeatReadPrefix) + if !isSeat { + return "", "", false, nil + } + at := strings.LastIndex(rest, ".") + if at <= 0 || at == len(rest)-1 || !stateName.MatchString(rest[:at]) || !stateName.MatchString(rest[at+1:]) { + return "", "", true, fmt.Errorf("%q does not name a seat and its state: a read of a seat holder's state is seat:.", read) + } + return rest[:at], rest[at+1:], true, nil +} + // SeatViewPrefix opens a consumed view of a seat, `seat:.views.` (design 47 G ยง616). const SeatViewPrefix = "seat:" diff --git a/go/catalogue/state_test.go b/go/catalogue/state_test.go index 0da094f7..9a242e4c 100644 --- a/go/catalogue/state_test.go +++ b/go/catalogue/state_test.go @@ -51,3 +51,26 @@ func TestAStateMayHaveKeysThatExpireOneByOne(t *testing.T) { t.Fatalf("read-only given twice: %v", err) } } + +// A read of a seat holder's state is its own kind, `seat:.`, kept apart from a module's read (design 47 G A-128). +func TestSeatRead(t *testing.T) { + for _, row := range []struct { + read, seat, local string + ok, bad bool + }{ + {"seat:mesh-provisioner.plans", "mesh-provisioner", "plans", true, false}, + {"mesh-provisioner.plans", "", "", false, false}, + {"seat:mesh-provisioner", "", "", true, true}, + {"seat:.plans", "", "", true, true}, + {"seat:Mesh.plans", "", "", true, true}, + } { + seat, local, ok, err := SeatRead(row.read) + if seat != row.seat || local != row.local || ok != row.ok || (err != nil) != row.bad { + t.Errorf("SeatRead(%q) = %q, %q, %v, %v", row.read, seat, local, ok, err) + } + } + // A module's read reads as today. + if module, local, err := ReadState("mesh-provisioner.plans"); module != "mesh-provisioner" || local != "plans" || err != nil { + t.Errorf("a module's read = %q, %q, %v", module, local, err) + } +}