From d4abb82b0727384bc217348afd205d4baffff643 Mon Sep 17 00:00:00 2001 From: jochen Date: Thu, 5 Nov 2026 15:46:23 +0100 Subject: [PATCH] =?UTF-8?q?artifact-store-tools=20reads=20the=20builder's?= =?UTF-8?q?=20builds=20through=20its=20published=20package,=20the=20wants,?= =?UTF-8?q?=20haves=20and=20manifests=20through=20the=20seats'=20types=20a?= =?UTF-8?q?nd=20clients;=20the=20sweep=20seat's=20two=20bodies=20are=20the?= =?UTF-8?q?=20holder's=20own=20(B5f;=20ADR=200634=20=C2=A71,=20=C2=A74;=20?= =?UTF-8?q?issue=201966)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Claude-Session: https://claude.ai/code/session_01NcbgfFSnn24M3GcqttoU7i --- .../cmd/artifact-store-tools/gone.go | 50 +++++++++++++ .../cmd/artifact-store-tools/holder.go | 75 ++++++++++--------- .../cmd/artifact-store-tools/holder_test.go | 30 ++++---- .../cmd/artifact-store-tools/main.go | 9 +-- .../artifact-store-tools/templates_test.go | 7 +- modules/artifact-store-tools/go.mod | 6 ++ modules/artifact-store-tools/module.json | 3 + 7 files changed, 126 insertions(+), 54 deletions(-) create mode 100644 modules/artifact-store-tools/cmd/artifact-store-tools/gone.go diff --git a/modules/artifact-store-tools/cmd/artifact-store-tools/gone.go b/modules/artifact-store-tools/cmd/artifact-store-tools/gone.go new file mode 100644 index 000000000..e9804f483 --- /dev/null +++ b/modules/artifact-store-tools/cmd/artifact-store-tools/gone.go @@ -0,0 +1,50 @@ +package main + +import ( + "encoding/json" + "fmt" + "sort" + "time" +) + +// The holders whose states this module reads, one constant each (a reader names its holder once; ADR 0634 §4). +const ( + assignerModule = "mesh-delivery-assigner" + indexerModule = "mesh-delivery-indexer" +) + +// ArtifactsGoneEvent is the event the seat mesh-artifact-sweep says when the store does not hold an artifact a +// builder's key names. The seat is a seat-list seat, which has no generated types, so its two bodies are the holder's +// own: this module is the one that says the event and answers the verb held. +const ArtifactsGoneEvent = "artifacts-gone" + +// HeldAnswer is the answer of the seat's verb held: the references the store holds, and those it answered 404 for. A +// reference the store could not be asked about is in neither, and named in Unknown with why. +type HeldAnswer struct { + Store string `json:"store,omitempty"` + Held []string `json:"held"` + Gone []string `json:"gone"` + Unknown map[string]string `json:"unknown,omitempty"` +} + +// ArtifactsGone is the body of ArtifactsGoneEvent: the module whose builder's key names a gone artifact, the key and +// its fingerprint, and every reference of it the store does not hold. +type ArtifactsGone struct { + Event string `json:"event"` + Module string `json:"module"` + Key string `json:"key"` + Fingerprint string `json:"fingerprint"` + Gone []string `json:"gone"` + At time.Time `json:"at"` +} + +// EncodeArtifactsGone is the event's body, the references sorted. +func EncodeArtifactsGone(e ArtifactsGone) ([]byte, error) { + e.Event = ArtifactsGoneEvent + e.Gone = append([]string(nil), e.Gone...) + sort.Strings(e.Gone) + if e.Module == "" || e.Fingerprint == "" || len(e.Gone) == 0 { + return nil, fmt.Errorf("%s names a module, a fingerprint and at least one gone reference", ArtifactsGoneEvent) + } + return json.Marshal(e) +} diff --git a/modules/artifact-store-tools/cmd/artifact-store-tools/holder.go b/modules/artifact-store-tools/cmd/artifact-store-tools/holder.go index c34488e51..1d46218cc 100644 --- a/modules/artifact-store-tools/cmd/artifact-store-tools/holder.go +++ b/modules/artifact-store-tools/cmd/artifact-store-tools/holder.go @@ -18,6 +18,12 @@ import ( "encoding/json" "errors" "fmt" + engineclient "git.novox.be/novox/mesh-contracts/go/clients/nodeengineclient" + nodeengine "git.novox.be/novox/mesh-contracts/go/seats/nodeengine" + meshwants "git.novox.be/novox/mesh-contracts/placement/go/seats/meshwants" + catalogclient "git.novox.be/novox/mesh-delivery/contracts/go/clients/meshcatalogclient" + catalog "git.novox.be/novox/mesh-delivery/contracts/go/seats/meshcatalog" + builds "git.novox.be/novox/mesh-delivery/modules/mesh-delivery-builder/builds" "sort" "strings" "sync" @@ -28,24 +34,23 @@ import ( meshconditions "git.novox.be/novox/mesh-contracts/health-and-repair/go/seats/meshconditions" stdio "git.novox.be/novox/mesh-sdk/go" "git.novox.be/novox/mesh-sdk/go/catalogue" - "git.novox.be/novox/mesh-sdk/go/delivery" "git.novox.be/novox/mesh-sdk/go/views" ) // What the holder reads and keeps. const ( - WantsRead = delivery.AssignerModule + ".wants" - BuildsRead = delivery.BuilderModule + ".builds" + WantsRead = assignerModule + ".wants" + BuildsRead = builds.BuilderModule + ".builds" HavesRead = "node-engine.have" // ManifestsRead is the indexer's manifests: the images a manifest pins by itself. - ManifestsRead = delivery.IndexerModule + ".manifests" + ManifestsRead = indexerModule + "." + catalog.StateManifests // FindingsState is the holder's own findings (meshconditions.StateFindings): image-missing. FindingsState = meshconditions.StateFindings // Module is this module, the observer its findings name. Module = "artifact-store-tools" // GoneSubject is where the seat says artifacts-gone. - GoneSubject = "mesh.seat." + catalogue.ArtifactSweepSeat + ".event." + delivery.ArtifactsGoneEvent + GoneSubject = "mesh.seat." + catalogue.ArtifactSweepSeat + ".event." + ArtifactsGoneEvent ) // The sweep's bounds, the controller's (cmd/mesh-controller/collect.go mostPerSweep, sweepBudget). @@ -99,7 +104,7 @@ type Holder struct { type Build struct { Module, FP, Key string At time.Time - Artifacts []delivery.BuiltArtifact + Artifacts []builds.BuiltArtifact // Manifest is the digest of the manifest it built, in the indexer's `manifests`. Manifest string } @@ -112,7 +117,7 @@ func (h *Holder) Builds() ([]Build, error) { } var out []Build for _, k := range keys { - module, fp, err := delivery.ParseBuilderBuildKey(k) + module, fp, err := builds.ParseBuilderBuildKey(k) if err != nil { continue } @@ -123,8 +128,8 @@ func (h *Holder) Builds() ([]Build, error) { if !found { continue } - b, err := delivery.DecodeBuilderBuild(raw) - if err != nil || b.State != delivery.BuildDone { + b, err := builds.DecodeBuilderBuild(raw) + if err != nil || b.State != builds.BuildDone { continue } at, err := h.endOf(k) @@ -149,7 +154,7 @@ func (h *Holder) endOf(key string) (time.Time, error) { return time.Time{}, fmt.Errorf("the history of the builder's build %s: %w", key, err) } for _, r := range revs { - if b, err := delivery.DecodeBuilderBuild(r.Value); err == nil && b.State == delivery.BuildDone && r.At.After(at) { + if b, err := builds.DecodeBuilderBuild(r.Value); err == nil && b.State == builds.BuildDone && r.At.After(at) { at = r.At } } @@ -181,11 +186,11 @@ func (h *Holder) Wants() ([]Want, error) { if err != nil { return nil, fmt.Errorf("the want %s: %w", k, err) } - var w delivery.Want - if !found || json.Unmarshal(raw, &w) != nil || w.Removed || w.FP == "" { + var w meshwants.WantsByWantNodeModuleValue + if !found || json.Unmarshal(raw, &w) != nil || w.Removed || w.Fp == "" { continue } - out = append(out, Want{Node: node, Module: module, FP: w.FP}) + out = append(out, Want{Node: node, Module: module, FP: w.Fp}) } return out, nil } @@ -352,17 +357,17 @@ func (h *Holder) judge(ctx context.Context) (*judged, error) { // against is what each build the builder's log says ended stood on, by build key: the bases' references. func (h *Holder) against() (map[string][]string, error) { - entries, err := h.Bus.LogSince(delivery.BuildLogRead, h.now().Add(-delivery.BuilderLogDays*24*time.Hour)) + entries, err := h.Bus.LogSince(builds.BuildLogRead, h.now().Add(-builds.BuilderLogDays*24*time.Hour)) if err != nil { return nil, err } out := map[string][]string{} for _, raw := range entries { - e, err := delivery.DecodeBuildLogEntry(raw.Value) - if err != nil || e.Event != delivery.BuildEndedEvent { + e, err := builds.DecodeBuildLogEntry(raw.Value) + if err != nil || e.Event != builds.BuildEndedEvent { continue } - key, err := delivery.BuilderBuildKey(e.Module, e.FP) + key, err := builds.BuilderBuildKey(e.Module, e.FP) if err != nil { continue } @@ -613,7 +618,7 @@ func (h *Holder) Sweep(ctx context.Context, s Sweeping) (*CollectAnswer, error) // sayGone says artifacts-gone for each build that named one of refs: the builder builds a key again whose artifact is gone. func (h *Holder) sayGone(j *judged, refs []string, how string) { - byKey := map[string]*delivery.ArtifactsGone{} + byKey := map[string]*ArtifactsGone{} var keys []string for _, r := range refs { ref := j.refs[r] @@ -623,7 +628,7 @@ func (h *Holder) sayGone(j *judged, refs []string, how string) { for _, b := range ref.Builds { g := byKey[b.Key] if g == nil { - g = &delivery.ArtifactsGone{Module: b.Module, Key: b.Key, Fingerprint: b.FP, At: h.now().UTC()} + g = &ArtifactsGone{Module: b.Module, Key: b.Key, Fingerprint: b.FP, At: h.now().UTC()} byKey[b.Key] = g keys = append(keys, b.Key) } @@ -632,7 +637,7 @@ func (h *Holder) sayGone(j *judged, refs []string, how string) { } sort.Strings(keys) for _, k := range keys { - raw, err := delivery.EncodeArtifactsGone(*byKey[k]) + raw, err := EncodeArtifactsGone(*byKey[k]) if err == nil { err = h.Bus.Publish(GoneSubject, json.RawMessage(raw)) } @@ -666,25 +671,25 @@ func (h *Holder) AfterBuild(key string) { } // Held is the seat's `held`: each reference, held, gone or unknown with why. Holds and writes nothing. -func (h *Holder) Held(refs []string) (delivery.HeldAnswer, error) { +func (h *Holder) Held(refs []string) (HeldAnswer, error) { if len(refs) == 0 { - return delivery.HeldAnswer{}, errors.New("held judges the references given, and none was") + return HeldAnswer{}, errors.New("held judges the references given, and none was") } if len(refs) > 64 { - return delivery.HeldAnswer{}, fmt.Errorf("held judges at most 64 references at once, and %d were given", len(refs)) + return HeldAnswer{}, fmt.Errorf("held judges at most 64 references at once, and %d were given", len(refs)) } for _, r := range refs { if _, ours := catalogue.InArtifactStore(r); !ours { - return delivery.HeldAnswer{}, fmt.Errorf("%s is not a reference into the mesh's artifact store (artifact-store://...): nothing was asked", r) + return HeldAnswer{}, fmt.Errorf("%s is not a reference into the mesh's artifact store (artifact-store://...): nothing was asked", r) } } door, err := h.Door() if err != nil { - return delivery.HeldAnswer{}, err + return HeldAnswer{}, err } asking, stop := context.WithTimeout(context.Background(), 20*time.Second) defer stop() - a := delivery.HeldAnswer{Store: door.Address(), Held: []string{}, Gone: []string{}} + a := HeldAnswer{Store: door.Address(), Held: []string{}, Gone: []string{}} for _, r := range refs { switch err := door.Holds(asking, canonical(r)); { case err == nil: @@ -725,7 +730,7 @@ func (h *Holder) ImagesOf(node string, address string) (Images, error) { } byImage := map[string]*Image{} add := func(module, fp, in string) error { - key, err := delivery.BuilderBuildKey(module, fp) + key, err := builds.BuilderBuildKey(module, fp) if err != nil { return nil } @@ -733,7 +738,7 @@ func (h *Holder) ImagesOf(node string, address string) (Images, error) { if err != nil || !found { return err } - b, err := delivery.DecodeBuilderBuild(raw) + b, err := builds.DecodeBuilderBuild(raw) if err != nil { return nil } @@ -774,7 +779,7 @@ func (h *Holder) ImagesOf(node string, address string) (Images, error) { return out, fmt.Errorf("the haves: %w", err) } for _, k := range keys { - n, module, isNode, err := delivery.ParseHaveKey(k) + n, module, isNode, err := engineclient.ParseHaveKey(k) if err != nil || isNode || n != node { continue } @@ -782,12 +787,12 @@ func (h *Holder) ImagesOf(node string, address string) (Images, error) { if err != nil { return out, err } - var have delivery.Have - if !found || json.Unmarshal(raw, &have) != nil || have.FP == "" { + var have nodeengine.HaveByNodeModuleValue + if !found || json.Unmarshal(raw, &have) != nil || have.Fp == "" { continue } out.SentKnown = true - if err := add(module, have.FP, "sent"); err != nil { + if err := add(module, have.Fp, "sent"); err != nil { return out, err } } @@ -806,7 +811,7 @@ func (h *Holder) Pinned(manifest string) ([]string, error) { if manifest == "" { return nil, nil } - key, err := delivery.ManifestsKey(manifest) + key, err := catalogclient.ManifestsKey(manifest) if err != nil { return nil, nil } @@ -814,14 +819,14 @@ func (h *Holder) Pinned(manifest string) ([]string, error) { if err != nil || !found { return nil, err } - m, err := delivery.DecodeManifest(raw) + m, err := catalogclient.DecodeManifest(raw) if err != nil { return nil, nil } var parsed struct { Resources []map[string]any `json:"resources"` } - if json.Unmarshal([]byte(m.JSON), &parsed) != nil { + if json.Unmarshal([]byte(m.Manifest), &parsed) != nil { return nil, nil } var out []string diff --git a/modules/artifact-store-tools/cmd/artifact-store-tools/holder_test.go b/modules/artifact-store-tools/cmd/artifact-store-tools/holder_test.go index 3305ac30f..dae24779c 100644 --- a/modules/artifact-store-tools/cmd/artifact-store-tools/holder_test.go +++ b/modules/artifact-store-tools/cmd/artifact-store-tools/holder_test.go @@ -5,6 +5,11 @@ import ( "encoding/json" "errors" "fmt" + nodeengine "git.novox.be/novox/mesh-contracts/go/seats/nodeengine" + meshwants "git.novox.be/novox/mesh-contracts/placement/go/seats/meshwants" + catalogclient "git.novox.be/novox/mesh-delivery/contracts/go/clients/meshcatalogclient" + catalog "git.novox.be/novox/mesh-delivery/contracts/go/seats/meshcatalog" + builds "git.novox.be/novox/mesh-delivery/modules/mesh-delivery-builder/builds" "slices" "sort" "strings" @@ -16,7 +21,6 @@ import ( "git.novox.be/novox/mesh-contracts/health-and-repair/go/clients/meshhandactsclient" meshconditions "git.novox.be/novox/mesh-contracts/health-and-repair/go/seats/meshconditions" stdio "git.novox.be/novox/mesh-sdk/go" - "git.novox.be/novox/mesh-sdk/go/delivery" "git.novox.be/novox/mesh-sdk/go/catalogue" ) @@ -33,7 +37,7 @@ type memBus struct { func (b *memBus) LogSince(read string, at time.Time) ([]stdio.LogEntry, error) { var out []stdio.LogEntry for _, e := range b.log { - if read == delivery.BuildLogRead && !e.At.Before(at) { + if read == builds.BuildLogRead && !e.At.Before(at) { out = append(out, e) } } @@ -175,8 +179,8 @@ func aMesh(t *testing.T) (*Holder, *memBus, *memDoor, *[]string) { door := &memDoor{holds: map[string]bool{}, indexes: map[string]bool{}} listing := &Listing{Blobs: map[string]int64{}, Repos: map[string]*Repo{}} for n := 1; n <= 7; n++ { - key, _ := delivery.BuilderBuildKey("letta", fp(n)) - raw, err := delivery.EncodeBuilderBuild(delivery.BuilderBuild{State: delivery.BuildDone, Manifest: strings.Repeat("d", 64), Artifacts: []delivery.BuiltArtifact{ + key, _ := builds.BuilderBuildKey("letta", fp(n)) + raw, err := builds.EncodeBuilderBuild(builds.BuilderBuild{State: builds.BuildDone, Manifest: strings.Repeat("d", 64), Artifacts: []builds.BuiltArtifact{ {Name: "image", Kind: "image", Digest: digestOf(imageRef("letta", n)), Reference: imageRef("letta", n)}, {Name: "files", Kind: "archive", Digest: digestOf(archiveRef("letta", n)), Reference: archiveRef("letta", n)}, {Name: "pkg", Kind: "package", Digest: "sha256:" + strings.Repeat("f", 64), Reference: "letta@1.0." + fmt.Sprint(n)}}}) @@ -204,7 +208,7 @@ func aMesh(t *testing.T) (*Holder, *memBus, *memDoor, *[]string) { door.holds[mirror(n)] = true } for n := 1; n <= 7; n++ { - e := delivery.BuildLogEntry{Event: delivery.BuildEndedEvent, Module: "letta", FP: fp(n), Repository: "novox/x", Commit: "c", + e := builds.BuildLogEntry{Event: builds.BuildEndedEvent, Module: "letta", FP: fp(n), Repository: "novox/x", Commit: "c", Node: "ace", At: day.Add(time.Duration(n) * time.Hour), Outcome: "done"} switch n { case 2: @@ -212,15 +216,15 @@ func aMesh(t *testing.T) (*Holder, *memBus, *memDoor, *[]string) { case 7: e.Against = []string{mirror(2)} } - raw, _ := delivery.EncodeBuildLogEntry(e) + raw, _ := builds.EncodeBuildLogEntry(e) b.log = append(b.log, stdio.LogEntry{Sequence: uint64(n), Key: "letta", Value: raw, At: e.At}) } - manifest, _ := delivery.EncodeManifest(delivery.Manifest{Module: "letta", - JSON: `{"module":"letta","resources":[{"id":"app","type":"container","image":"` + pinnedImage + `"},` + + manifest, _ := catalogclient.EncodeManifest(catalog.ManifestsByDigestValue{Module: "letta", + Manifest: `{"module":"letta","resources":[{"id":"app","type":"container","image":"` + pinnedImage + `"},` + `{"id":"built","type":"container","image":"${artifact:image}"}]}`}) - mk, _ := delivery.ManifestsKey(strings.Repeat("d", 64)) + mk, _ := catalogclient.ManifestsKey(strings.Repeat("d", 64)) _ = b.Put(ManifestsRead, mk, json.RawMessage(manifest)) - want, _ := json.Marshal(delivery.Want{V: delivery.Version, FP: fp(1), Self: true}) + want, _ := json.Marshal(meshwants.WantsByWantNodeModuleValue{V: 1, Fp: fp(1), Self: true}) _ = b.Put(WantsRead, "want.ace.letta", json.RawMessage(want)) var acts []string h := &Holder{Bus: b, Door: func() (Door, error) { return door, nil }, Seats: door.seat, @@ -302,8 +306,8 @@ func TestTheSeatKeepsTheFiveNewestAndTheWantedAndSweepsWithNoLease(t *testing.T) } if c.seatForm { for _, n := range []int{2, 3} { - key, _ := delivery.BuilderBuildKey("letta", fp(n)) - raw, _ := delivery.EncodeBuilderBuild(delivery.BuilderBuild{State: delivery.BuildDone, Manifest: strings.Repeat("d", 64), Artifacts: []delivery.BuiltArtifact{ + key, _ := builds.BuilderBuildKey("letta", fp(n)) + raw, _ := builds.EncodeBuilderBuild(builds.BuilderBuild{State: builds.BuildDone, Manifest: strings.Repeat("d", 64), Artifacts: []builds.BuiltArtifact{ {Name: "image", Kind: "image", Digest: digestOf(imageRef("letta", n)), Reference: catalogue.SeatReference("container-image-registry", "letta", "image", digestOf(imageRef("letta", n)))}, {Name: "files", Kind: "archive", Digest: digestOf(archiveRef("letta", n)), Reference: catalogue.SeatReference("oci-artifact-registry", "letta", "files", digestOf(archiveRef("letta", n)))}}}) _ = b.Put(BuildsRead, key, json.RawMessage(raw)) @@ -426,7 +430,7 @@ func TestAWantedImageTheStoreLacksIsAFindingAndImagesNamesWantsAndHaves(t *testi t.Fatalf("the pinnedImage image missing is %s", raw) } - have, _ := json.Marshal(delivery.Have{V: delivery.Version, FP: fp(7), Phase: "running"}) + have, _ := json.Marshal(nodeengine.HaveByNodeModuleValue{V: 1, Fp: fp(7), Phase: "running"}) _ = b.Put(HavesRead, "ace.letta", json.RawMessage(have)) images, err := h.ImagesOf("ace", "10.0.0.5:5000") if err != nil || len(images.Images) != 3 || !images.SentKnown || images.Images[0].Image != "10.0.0.5:5000/letta/image@sha256:"+strings.Repeat("1", 64) || diff --git a/modules/artifact-store-tools/cmd/artifact-store-tools/main.go b/modules/artifact-store-tools/cmd/artifact-store-tools/main.go index 20ac59163..3af7eacc5 100644 --- a/modules/artifact-store-tools/cmd/artifact-store-tools/main.go +++ b/modules/artifact-store-tools/cmd/artifact-store-tools/main.go @@ -16,7 +16,6 @@ import ( "git.novox.be/novox/mesh-contracts/health-and-repair/go/clients/meshconditionsclient" "git.novox.be/novox/mesh-contracts/health-and-repair/go/clients/meshhandactsclient" stdio "git.novox.be/novox/mesh-sdk/go" - "git.novox.be/novox/mesh-sdk/go/delivery" "git.novox.be/novox/mesh-sdk/go/views" ) @@ -26,8 +25,8 @@ func logf(format string, a ...any) { fmt.Fprintf(os.Stderr, format+"\n", a...) } func main() { s := &Store{Ask: stdio.Ask} v := &views.Reader{Module: "artifact-store-tools", Logf: logf, Findings: meshconditionsclient.FindingWriter{State: stdio.State("findings")}, Acts: meshhandactsclient.Recorder{Ask: stdio.Ask}} - v.Follow(delivery.AssignerModule, "wants", WantsTool) - v.Follow(delivery.IndexerModule, "manifests", ManifestsTool) + v.Follow(assignerModule, "wants", WantsTool) + v.Follow(indexerModule, "manifests", ManifestsTool) h := &Holder{Bus: runtimeBus{views: v}, Door: DoorAt(os.Getenv("MESH_ARTIFACT_STORE_ADDRESS_FILE"), s), Listed: s.View, Seats: stdio.Ask, Now: time.Now, Logf: logf} h.Acts = meshhandactsclient.Recorder{Ask: stdio.Ask} @@ -42,6 +41,6 @@ func main() { // The owners' read tools of the states the holder follows, which the manifest invokes (ADR 0615). const ( - WantsTool = delivery.AssignerModule + ".assigner_read_wants" - ManifestsTool = delivery.IndexerModule + ".indexer_read_manifests" + WantsTool = assignerModule + ".assigner_read_wants" + ManifestsTool = indexerModule + ".indexer_read_manifests" ) diff --git a/modules/artifact-store-tools/cmd/artifact-store-tools/templates_test.go b/modules/artifact-store-tools/cmd/artifact-store-tools/templates_test.go index 7d0718b57..f429f1ed9 100644 --- a/modules/artifact-store-tools/cmd/artifact-store-tools/templates_test.go +++ b/modules/artifact-store-tools/cmd/artifact-store-tools/templates_test.go @@ -33,7 +33,8 @@ func TestEveryFileTakesItsTextFromATemplate(t *testing.T) { t.Fatal(err) } var m struct { - Resources []map[string]any `json:"resources"` + Resources []map[string]any `json:"resources"` + Packages map[string]string `json:"packages"` Build struct { Artifacts []map[string]any `json:"artifacts"` } `json:"build"` @@ -41,6 +42,10 @@ func TestEveryFileTakesItsTextFromATemplate(t *testing.T) { if err := json.Unmarshal(raw, &m); err != nil { t.Fatal(err) } + // The builder's keys are read through its published package, taken by its series (ADR 0634 §1). + if m.Packages["builds"] != "0.1" { + t.Errorf("packages %v: want builds of series 0.1", m.Packages) + } for _, r := range m.Resources { if _, inline := r["content"]; inline { t.Errorf("resource %v keeps its text inline: keep it in files/ and name it as the template", r["id"]) diff --git a/modules/artifact-store-tools/go.mod b/modules/artifact-store-tools/go.mod index 6fd90d5cd..66c3b9f23 100644 --- a/modules/artifact-store-tools/go.mod +++ b/modules/artifact-store-tools/go.mod @@ -3,6 +3,12 @@ module artifactstoretools go 1.26.0 require ( + git.novox.be/novox/mesh-contracts/placement/go/seats/meshwants v0.0.0-00010101000000-000000000000 + git.novox.be/novox/mesh-contracts/go/seats/nodeengine v0.0.0-00010101000000-000000000000 + git.novox.be/novox/mesh-contracts/go/clients/nodeengineclient v0.0.0-00010101000000-000000000000 + git.novox.be/novox/mesh-delivery/contracts/go/clients/meshcatalogclient v0.0.0-00010101000000-000000000000 + git.novox.be/novox/mesh-delivery/contracts/go/seats/meshcatalog v0.0.0-00010101000000-000000000000 + git.novox.be/novox/mesh-delivery/modules/mesh-delivery-builder/builds v0.0.0-00010101000000-000000000000 git.novox.be/novox/mesh-contracts/health-and-repair/go/seats/meshconditions v0.0.0-00010101000000-000000000000 git.novox.be/novox/mesh-contracts/health-and-repair/go/clients/meshconditionsclient v0.0.0-00010101000000-000000000000 git.novox.be/novox/mesh-contracts/health-and-repair/go/clients/meshhandactsclient v0.0.0-00010101000000-000000000000 diff --git a/modules/artifact-store-tools/module.json b/modules/artifact-store-tools/module.json index 5abdca6c5..b1b4b1c6c 100644 --- a/modules/artifact-store-tools/module.json +++ b/modules/artifact-store-tools/module.json @@ -1,6 +1,9 @@ { "module": "artifact-store-tools", "version": "1", + "packages": { + "builds": "0.1" + }, "claims": [ { "name": "mesh-artifact-sweep",