From 2d2aa7ba9bbd47e92132a5a38f8a2aea6bea0753 Mon Sep 17 00:00:00 2001 From: jochen Date: Thu, 29 Oct 2026 22:21:12 +0100 Subject: [PATCH] =?UTF-8?q?Carry=20the=20catalogue's=20predefined=20list?= =?UTF-8?q?=20on=20the=20bridge's=20merged=20message,=20so=20the=20indexer?= =?UTF-8?q?=20keeps=20it=20without=20the=20controller's=20mirror=20(issue?= =?UTF-8?q?=201953=20L5-D1,=20ADR=200565=20=C2=A72)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- go/delivery/forge_inputs_test.go | 19 +++++++++++++++++++ go/delivery/source.go | 28 ++++++++++++++++++++++++++++ 2 files changed, 47 insertions(+) diff --git a/go/delivery/forge_inputs_test.go b/go/delivery/forge_inputs_test.go index 5238339..4b76ee1 100644 --- a/go/delivery/forge_inputs_test.go +++ b/go/delivery/forge_inputs_test.go @@ -33,6 +33,22 @@ func TestForgeMergedCarriesManifestsAndLocks(t *testing.T) { if got.Manifests["a"] != oddManifest || !SameForge(got, withV(f)) { t.Errorf("the message changed on the way: %q", got.Manifests["a"]) } + // ADR 0565 §2 (issue 1953 D1): a merged message carries the predefined list exact, or says the merge holds none; a + // pull message carries neither. + f.Predefined = []byte(`{"domain":{"type":"string"}}`) + if data, err := EncodeForge(f); err != nil { + t.Fatal(err) + } else if got, err := DecodeForge(data); err != nil || string(got.Predefined) != `{"domain":{"type":"string"}}` { + t.Errorf("the predefined list read back as %s, %v", got.Predefined, err) + } + f.Predefined, f.PredefinedRead = nil, true + if _, err := EncodeForge(f); err != nil { + t.Errorf("a merge holding no predefined list: %v", err) + } + pull := Forge{Kind: ForgePull, Repository: "novox/mesh-sdk", Number: 1, Head: "h", Action: PullOpened, PredefinedRead: true} + if _, err := EncodeForge(pull); err == nil || !strings.Contains(err.Error(), "only a merged message") { + t.Errorf("a pull message carrying the predefined list: %v", err) + } } func withV(f Forge) Forge { f.V = Version; return f } @@ -50,6 +66,9 @@ func TestForgeMergedRefusesBadInputs(t *testing.T) { // No repository holds placement (ADR 0567 §11): a message carrying placement files is refused, on a merge or a pull. "placement files": {func(f *Forge) { f.RetiredPlacements = []byte(`{"anchor":"{}"}`) }, "mesh-placement"}, "placements read": {func(f *Forge) { f.RetiredRead = true }, "mesh-placement"}, + // ADR 0565 §2 (issue 1953 D1): the predefined list is one JSON object, said present or absent, never both. + "predefined not an object": {func(f *Forge) { f.Predefined = []byte(`["domain"]`) }, "one JSON object"}, + "predefined both": {func(f *Forge) { f.Predefined = []byte(`{}`); f.PredefinedRead = true }, "says the merge holds none"}, } { f := mergedWithInputs() tc.mut(&f) diff --git a/go/delivery/source.go b/go/delivery/source.go index 6b0d25c..3c09503 100644 --- a/go/delivery/source.go +++ b/go/delivery/source.go @@ -542,6 +542,31 @@ type Forge struct { // refused, loudly, rather than read with them dropped. RetiredPlacements json.RawMessage `json:"placements,omitempty"` RetiredRead bool `json:"placements-read,omitempty"` + // Predefined is the catalogue's predefined.json, exact, at the merge commit of a merged message (novox/hq ADR 0565 + // §2): what the indexer keeps as its state `predefined`. PredefinedRead says the bridge read the merge and it holds + // no predefined.json. Carried on a merged message only; an older bridge sends neither, and the indexer keeps what it + // held. + Predefined json.RawMessage `json:"predefined,omitempty"` + PredefinedRead bool `json:"predefined-read,omitempty"` +} + +// checkPredefined refuses the predefined list on anything but a merged message, a list that is not one JSON object, and +// a list said both present and absent. +func (f Forge) checkPredefined() error { + if len(f.Predefined) == 0 && !f.PredefinedRead { + return nil + } + if f.Kind != ForgeMerged { + return fmt.Errorf("delivery: only a merged message carries the predefined list, not a %s message", f.Kind) + } + if len(f.Predefined) > 0 && f.PredefinedRead { + return fmt.Errorf("delivery: a merged message carries the predefined list and says the merge holds none (predefined-read)") + } + var list map[string]json.RawMessage + if len(f.Predefined) > 0 && json.Unmarshal(f.Predefined, &list) != nil { + return fmt.Errorf("delivery: the predefined list a merged message carries is not one JSON object") + } + return nil } func (f Forge) check() error { @@ -558,6 +583,9 @@ func (f Forge) check() error { return fmt.Errorf("delivery: a forge message carries placement files, which no repository holds since ADR 0567: " + "placement is the seat mesh-placement's state") } + if err := f.checkPredefined(); err != nil { + return err + } if err := checkRepository(f.Repository); err != nil { return err }