From 092260870b58f676b19d68ecc4ef8e24feb9c237 Mon Sep 17 00:00:00 2001 From: jochen Date: Tue, 3 Nov 2026 15:12:19 +0100 Subject: [PATCH] A ledger's binding carries its types (issue 1966 S3) The grants part copies them from the manifest-accepted entry, so the tool runner checks an operation against its type without reading another part's state (ADR 0596; the lead's ruling on issue 1966 B1). --- go/membership/membership.go | 5 +++++ go/membership/membership_test.go | 8 ++++++-- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/go/membership/membership.go b/go/membership/membership.go index 5430239..4f957cb 100644 --- a/go/membership/membership.go +++ b/go/membership/membership.go @@ -7,6 +7,8 @@ package membership import ( "encoding/json" "strings" + + "git.novox.be/novox/mesh-sdk/go/catalogue" ) // AssignmentsStream holds every assignment's membership, the newest per subject. @@ -84,6 +86,9 @@ type BusBinding struct { State string `json:"state,omitempty"` Indexes map[string]string `json:"indexes,omitempty"` Snapshot string `json:"snapshot,omitempty"` + // Types are a ledger's types, copied by the grants part from the entry the manifest-accepted event carries, so the + // tool runner checks an operation against its type without reading another part's state (ADR 0596, ADR 0597 ยง1). + Types []catalogue.LedgerType `json:"types,omitempty"` } // Served is one address a tool is answered on. diff --git a/go/membership/membership_test.go b/go/membership/membership_test.go index 6ea76db..e80d346 100644 --- a/go/membership/membership_test.go +++ b/go/membership/membership_test.go @@ -4,6 +4,8 @@ import ( "encoding/json" "reflect" "testing" + + "git.novox.be/novox/mesh-sdk/go/catalogue" ) // A credential is read out of a bus address, and the bare address carries no credential and a scheme. @@ -57,11 +59,13 @@ func TestAMembershipRoundTripsAsIssued(t *testing.T) { if !reflect.DeepEqual(in, out) { t.Fatalf("round trip changed it:\n%+v\n%+v", in, out) } - // 1966/AC4: a membership with a ledger binding round-trips; one without bindings encodes as before, byte for byte. + // 1966/AC4: a membership with a ledger binding, its types among it, round-trips; one without bindings encodes as before, byte for byte. bound := in bound.Bindings = []BusBinding{{Local: "records", Storage: "ledger", Template: "ledger", History: "forge_records", Subject: "forge_records.>", State: "forge_records_state", Indexes: map[string]string{"search": "forge_records_search"}, - Snapshot: "forge_records_snapshot.>"}} + Snapshot: "forge_records_snapshot.>", + Types: []catalogue.LedgerType{{Name: "decision", Schema: map[string]catalogue.LedgerField{"title": {Type: "text"}}, + Operations: []catalogue.LedgerOperation{{Name: "propose", Effect: catalogue.EffectSetFields, Fields: []string{"title"}}}}}}} boundRaw, err := json.Marshal(bound) if err != nil { t.Fatal(err)