From ea1b2ab395215ad1a0e920be1dc4c862c936ae4b Mon Sep 17 00:00:00 2001 From: mesh-tools Date: Wed, 21 Oct 2026 09:04:43 +0000 Subject: [PATCH 1/2] Give delivery.Module a path and BuildRecord the artifacts a build made, so the builder can find a module and compare digests (issue 1588) --- go/delivery/buildrecord.go | 10 +++++++ go/delivery/buildrecord_test.go | 26 +++++++++++++++++++ go/delivery/source.go | 3 +++ go/delivery/source_test.go | 23 ++++++++++++++++ .../testdata/build-record-build-agent.json | 2 +- 5 files changed, 63 insertions(+), 1 deletion(-) diff --git a/go/delivery/buildrecord.go b/go/delivery/buildrecord.go index 86bd87b..d3f9fb9 100644 --- a/go/delivery/buildrecord.go +++ b/go/delivery/buildrecord.go @@ -20,6 +20,16 @@ type BuildRecord struct { At time.Time `json:"at,omitzero"` SourceFingerprint string `json:"source-fingerprint,omitempty"` SourceInputs *SourceInputs `json:"source-inputs,omitempty"` + // Made is what the build made (Build.Made, records.go:110); the digest is the tail of an artifact's Reference. + Made []Artifact `json:"made,omitempty"` +} + +// Artifact is one thing a build made: mesh-controller internal/chain/records.go Artifact, json keys name, kind and +// reference, nothing else (novox/hq ADR 0478 clause 7). +type Artifact struct { + Name string `json:"name"` + Kind string `json:"kind"` + Reference string `json:"reference"` } // BuildsBucket is the bucket the builds are kept in: mesh-controller internal/broker/controller_buckets.go:101, diff --git a/go/delivery/buildrecord_test.go b/go/delivery/buildrecord_test.go index 7f9b08a..2a1d4f0 100644 --- a/go/delivery/buildrecord_test.go +++ b/go/delivery/buildrecord_test.go @@ -127,3 +127,29 @@ func TestBuildKeys(t *testing.T) { // 1223/AC3 t.Errorf("NewestKey = %q", got) } } + +// The fixture's made artifacts are the controller's Artifact (mesh-controller internal/chain/records.go, json tags name, +// kind, reference; the controller writes no digest key, the digest is the tail of the reference). The kinds and references +// are those of the live record mesh-controller.builds printed for build-agent build-1792540091397811913 (2026-10-21 01:49). +func TestBuildRecordMade(t *testing.T) { // 1588/AC2 + var r BuildRecord + if err := json.Unmarshal(loadBuildFixture(t), &r); err != nil { + t.Fatal(err) + } + want := []Artifact{ + {Name: "server", Kind: "image", Reference: "artifact-store://build-agent/server@sha256:a79c13f1c727ff94959e80824cc704ea58b80d80ecdd00fd447698acebb35090"}, + {Name: "files", Kind: "archive", Reference: "artifact-store://build-agent/files/blobs/sha256:bccd3f47851436d1b45a3063cc2d7e34c5c109b2d030739bfbb4b9781703f9a9"}, + } + if len(r.Made) != len(want) { + t.Fatalf("made = %+v, want %+v", r.Made, want) + } + for i := range want { + if r.Made[i] != want[i] { + t.Errorf("made[%d] = %+v, want %+v", i, r.Made[i], want[i]) + } + } + var none BuildRecord + if err := json.Unmarshal([]byte(`{"id":"b","repository":"a/b"}`), &none); err != nil || none.Made != nil { + t.Errorf("a record without made: %+v, %v", none, err) + } +} diff --git a/go/delivery/source.go b/go/delivery/source.go index 580aaa1..08e38fc 100644 --- a/go/delivery/source.go +++ b/go/delivery/source.go @@ -389,6 +389,9 @@ type Module struct { Src uint64 `json:"src,omitempty"` Repository string `json:"repository"` Commit string `json:"commit"` + // Path is the module's directory in its repository, trimmed of slashes, empty when its manifest is the repository's + // root (novox/hq ADR 0478 clause 6): the build tools need it. A value written before has none. + Path string `json:"path,omitempty"` } // KeptInputs2 are SourceInputs2 without the module's name (the key has it) and without toolchains (those come from diff --git a/go/delivery/source_test.go b/go/delivery/source_test.go index c269277..cdfd10a 100644 --- a/go/delivery/source_test.go +++ b/go/delivery/source_test.go @@ -374,3 +374,26 @@ func TestForgeDirs(t *testing.T) { t.Error("dirs without dirs-known accepted") } } + +func TestModulePath(t *testing.T) { // 1588/AC1 + data, err := EncodeModule(Module{FP: "src1:x", Repository: "a/b", Commit: "c", Path: "modules/build-agent"}) + if err != nil { + t.Fatal(err) + } + if !strings.Contains(string(data), `"path":"modules/build-agent"`) { + t.Errorf("encoded %s has no path", data) + } + m, err := DecodeModule(data) + if err != nil || m.Path != "modules/build-agent" { + t.Errorf("round trip = %+v, %v", m, err) + } + // A value written before has no path: it decodes, checks, and encodes without the key. + old, err := DecodeModule([]byte(`{"v":1,"fp":"src1:x","repository":"a/b","commit":"c"}`)) + if err != nil || old.Path != "" { + t.Fatalf("old shape = %+v, %v", old, err) + } + again, _ := EncodeModule(old) + if strings.Contains(string(again), "path") { + t.Errorf("a module without a path encodes %s", again) + } +} diff --git a/go/delivery/testdata/build-record-build-agent.json b/go/delivery/testdata/build-record-build-agent.json index ea840ac..0e756e0 100644 --- a/go/delivery/testdata/build-record-build-agent.json +++ b/go/delivery/testdata/build-record-build-agent.json @@ -1 +1 @@ -{"id":"build-1792395447088936520","repository":"http://novox.internal:20000/novox/mesh-controller.git","module":"build-agent","commit":"7a74cee83f88e6585a5511c3cc53bdf0f5303d20","path":"modules/build-agent","manifest-digest":"sha256:0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef","source-fingerprint":"src1:e846efe73716b78e80860baaac96153de2cb76551325753838ca245d2160a3d7","source-inputs":{"Module":"build-agent","Tree":"11c0b4f90cae0d6e4ef9cc48cbfdf9f6dbe52bca","Bases":["sha256:d9e853e87e55526f6b2917df91a2115c36dd7c696a35be12163d44e6e2a4b6bc","sha256:8ac98ca534ac3f51e1f420a1dd2c15e74c75cfa0f23f3ad27eb5d7236c349a0c"],"Contexts":{"server":"narrow:d51ca744fd11af59d616c858f76c27b3e58e16e11fbdc0c720eb9d7d19d55fac"},"Toolchains":null,"Unpinned":""},"made":[{"name":"server","kind":"image","reference":"registry.example/build-agent@sha256:d9e853e87e55526f6b2917df91a2115c36dd7c696a35be12163d44e6e2a4b6bc"}],"at":"2026-10-19T09:38:00Z"} +{"id":"build-1792395447088936520","repository":"http://novox.internal:20000/novox/mesh-controller.git","module":"build-agent","commit":"7a74cee83f88e6585a5511c3cc53bdf0f5303d20","path":"modules/build-agent","manifest-digest":"sha256:0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef","source-fingerprint":"src1:e846efe73716b78e80860baaac96153de2cb76551325753838ca245d2160a3d7","source-inputs":{"Module":"build-agent","Tree":"11c0b4f90cae0d6e4ef9cc48cbfdf9f6dbe52bca","Bases":["sha256:d9e853e87e55526f6b2917df91a2115c36dd7c696a35be12163d44e6e2a4b6bc","sha256:8ac98ca534ac3f51e1f420a1dd2c15e74c75cfa0f23f3ad27eb5d7236c349a0c"],"Contexts":{"server":"narrow:d51ca744fd11af59d616c858f76c27b3e58e16e11fbdc0c720eb9d7d19d55fac"},"Toolchains":null,"Unpinned":""},"made":[{"name":"server","kind":"image","reference":"artifact-store://build-agent/server@sha256:a79c13f1c727ff94959e80824cc704ea58b80d80ecdd00fd447698acebb35090"},{"name":"files","kind":"archive","reference":"artifact-store://build-agent/files/blobs/sha256:bccd3f47851436d1b45a3063cc2d7e34c5c109b2d030739bfbb4b9781703f9a9"}],"at":"2026-10-19T09:38:00Z"} -- 2.54.0 From 66b052aeee697a8670f2e56b1e923b816e6fe8ae Mon Sep 17 00:00:00 2001 From: mesh-tools Date: Wed, 21 Oct 2026 09:08:15 +0000 Subject: [PATCH 2/2] Cite ADR 0478's clause on the module's directory by its number in the record's version 4 (issue 1588) --- go/delivery/source.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/go/delivery/source.go b/go/delivery/source.go index 08e38fc..a21bf9d 100644 --- a/go/delivery/source.go +++ b/go/delivery/source.go @@ -390,7 +390,7 @@ type Module struct { Repository string `json:"repository"` Commit string `json:"commit"` // Path is the module's directory in its repository, trimmed of slashes, empty when its manifest is the repository's - // root (novox/hq ADR 0478 clause 6): the build tools need it. A value written before has none. + // root (novox/hq ADR 0478 clause 8): the build tools need it. A value written before has none. Path string `json:"path,omitempty"` } -- 2.54.0