From cf5812101b0bccd9811e79ac51a4810e2d989fdb Mon Sep 17 00:00:00 2001 From: jochen Date: Tue, 3 Nov 2026 16:51:54 +0100 Subject: [PATCH] The seat mesh-catalog's verbs' answers are its contract: CatalogModules, CatalogOne, CatalogProvides and CatalogDependents, with the field names of the catalog module's tools they replace; the module graph is no part of mesh-sdk (the operator, 2026-11-03: only contracts) --- go/catalogue/catalog_seat.go | 57 ++++++++++++++++++++++++++++++++++-- go/catalogue/verbs_test.go | 19 ++++++++++++ 2 files changed, 73 insertions(+), 3 deletions(-) diff --git a/go/catalogue/catalog_seat.go b/go/catalogue/catalog_seat.go index 63b380b..09db316 100644 --- a/go/catalogue/catalog_seat.go +++ b/go/catalogue/catalog_seat.go @@ -1,10 +1,13 @@ package catalogue +import "encoding/json" + // CatalogSeat is the seat of the catalog: what the mesh holds of every module (novox/hq ADR 0604 ยง1). Its states are // its holder's: the modules the trunk holds, their manifests by digest and the module graph (the indexer's states -// `modules`, `manifests` and `graph`, delivery.ModulesBucket, ManifestsBucket and GraphBucket), announced with who may -// read them; a reader that only watches reads them and calls no verb. It names no event. What must be built again is -// no verb: a module whose fingerprint differs from its newest build, which the delivery view derives. +// `modules`, `manifests` and `graph`), announced with who may read them; a reader that only watches reads them and calls +// no verb. It names no event. What must be built again is no verb: a module whose fingerprint differs from its newest +// build, which the delivery view derives. The verbs' answers are CatalogModules, CatalogOne, CatalogProvides and +// CatalogDependents, whose field names are those of the catalog module's tools they replace. const CatalogSeat = "mesh-catalog" // catalogVerbs are the seat's four verbs, each read from its holder's states. Each is optional until the holder that @@ -28,3 +31,51 @@ func catalogVerbs() []Verb { Input: schema(map[string]string{"module": "the module's name"}, []string{"module"})}, } } + +// CatalogEntry is one module of the catalog: its repository, its directory there ("." for the root), the merge commit it +// was last changed at, and its new-form fingerprint or why it has none. +type CatalogEntry struct { + Module string `json:"module"` + Repository string `json:"repository"` + Path string `json:"path"` + Commit string `json:"commit"` + FP string `json:"fp,omitempty"` + None string `json:"none,omitempty"` +} + +// CatalogModule is one module whole: its entry and its manifest as the trunk holds it. +type CatalogModule struct { + CatalogEntry + Manifest json.RawMessage `json:"manifest"` +} + +// CatalogEnd is a module that provides, requires or depends on something, with its commit; Scope is a provider's scope +// (a module provides its own name at node scope). +type CatalogEnd struct { + Module string `json:"module"` + Commit string `json:"commit"` + Scope string `json:"scope,omitempty"` +} + +// CatalogModules is the answer of the verb modules: every module the trunk holds, sorted by name. +type CatalogModules struct { + Modules []CatalogEntry `json:"modules"` +} + +// CatalogOne is the answer of the verb module. +type CatalogOne struct { + Module CatalogModule `json:"module"` +} + +// CatalogProvides is the answer of the verb provides: the modules that provide the provision and those that require it. +type CatalogProvides struct { + Provision string `json:"provision"` + Provides []CatalogEnd `json:"provides"` + Requires []CatalogEnd `json:"requires"` +} + +// CatalogDependents is the answer of the verb dependents: the modules whose build edges reach the module. +type CatalogDependents struct { + Module string `json:"module"` + Dependents []CatalogEnd `json:"dependents"` +} diff --git a/go/catalogue/verbs_test.go b/go/catalogue/verbs_test.go index af45955..7e7f4c7 100644 --- a/go/catalogue/verbs_test.go +++ b/go/catalogue/verbs_test.go @@ -1,6 +1,7 @@ package catalogue import ( + "encoding/json" "slices" "strings" "testing" @@ -61,6 +62,24 @@ func TestHoldingAMeshSeatRequiresServingItsVerbs(t *testing.T) { t.Errorf("mesh-catalog's verb %d is %+v, want %s, optional, with its input", i, v, four[i]) } } + // The answers keep the field names of the catalog module's tools they replace (catalog_modules, catalog_module, + // catalog_provides, catalog_dependents, as mesh_call answered them on 2026-11-03). + for _, c := range []struct { + answer any + want []string + }{ + {CatalogModules{Modules: []CatalogEntry{{}}}, []string{`"modules":[{"module":`, `"repository":`, `"path":`, `"commit":`}}, + {CatalogOne{Module: CatalogModule{Manifest: json.RawMessage(`{}`)}}, []string{`"module":{"module":`, `"manifest":{}`}}, + {CatalogProvides{Provides: []CatalogEnd{{Scope: "mesh"}}, Requires: []CatalogEnd{{}}}, []string{`"provides":[{"module":"","commit":"","scope":"mesh"}]`, `"requires":[{"module":"","commit":""}]`}}, + {CatalogDependents{Module: "m", Dependents: []CatalogEnd{}}, []string{`"module":"m"`, `"dependents":[]`}}, + } { + raw, _ := json.Marshal(c.answer) + for _, w := range c.want { + if !strings.Contains(string(raw), w) { + t.Errorf("the answer %s does not hold %s", raw, w) + } + } + } cataloguer := func(serves ...string) Manifest { return Manifest{Module: "a-catalog", Tools: serves, Claims: []Claim{{Name: CatalogSeat, Scope: ScopeMesh, Serves: serves}}} }