J8: sdk/forms names an image and an upstream copy in the seat reference form, each deriving its artifact-store form

ADR 0624: container-image-registry/<module>/<artifact>@<digest> and the holder's container-image-registry/upstream/<host>/<path>@<digest> are form:seat-reference; Older derives artifact-store://... so a key keeps both. The registry form now precedes the artifact-store form, so a node stating nothing keeps the recorded store form of an image.

Claude-Session: https://claude.ai/code/session_01JG73KJNrH5EgFXMKKYSrig
This commit is contained in:
2026-11-04 15:55:45 +01:00
parent c47f0af0ab
commit bf92a37730
2 changed files with 78 additions and 42 deletions
@@ -1365,39 +1365,48 @@ func aDoneKeyKeepsEachFormACountedNodeReads(t *testing.T) {
// The builder's own forms (forms.Current): a bundle a build step answers in the registry seat's form (mesh-build-go's
// oci-artifact-registry/<module>/<artifact>@<digest>) keeps the artifact-store form it derives for each counted node
// whose engine does not state form:seat-reference, that one in the single reference (ADR 0624 §1, §3).
seatRef, storeRef := "oci-artifact-registry/m/code@"+digest, "artifact-store://m/code/blobs/"+digest
seat := []string{forms.FormNeed(forms.FormSeatReference), "word:module"}
for _, row := range []struct {
name string
present, counted map[string][]string
reference string
references []string
needs []string
}{
{"seat form answered, B away stating nothing: the derived store form stays, in the single reference",
map[string][]string{"a": seat}, map[string][]string{"a": seat, "b": nil}, storeRef, []string{storeRef, seatRef},
[]string{"form:artifact-store", "form:seat-reference"}},
{"seat form answered, every counted engine reads it: the seat form only",
map[string][]string{"a": seat}, map[string][]string{"a": seat, "b": seat}, seatRef, nil, []string{"form:seat-reference"}},
{"seat form answered, a present engine stating nothing: the store form only",
map[string][]string{"a": seat, "b": nil}, map[string][]string{"a": seat, "b": nil}, storeRef, nil, []string{"form:artifact-store"}},
{"seat form answered, no node present: the store form", nil, map[string][]string{"a": seat}, storeRef, nil, []string{"form:artifact-store"}},
// Each kind the seat form names (a bundle through oci-artifact-registry, an image and an upstream copy through
// container-image-registry, the copy under the holder's own upstream/<host>/<path>), with the artifact-store form it derives.
for _, k := range []struct{ kind, seatRef, storeRef string }{
{"bundle", "oci-artifact-registry/m/code@" + digest, "artifact-store://m/code/blobs/" + digest},
{"image", "container-image-registry/m/code@" + digest, "artifact-store://m/code@" + digest},
{"upstream", "container-image-registry/upstream/quay.io:443/org/app@" + digest, "artifact-store://upstream/quay.io:443/org/app@" + digest},
} {
a := forms.Current.Choose(delivery.BuiltArtifact{Name: "code", Kind: "bundle", Digest: digest}, []string{seatRef}, row.present, row.counted)
if a.Reference != row.reference || !slices.Equal(a.References, row.references) {
t.Errorf("%s: %q %v, want %q %v", row.name, a.Reference, a.References, row.reference, row.references)
}
needs := forms.Current.Needs([]delivery.BuiltArtifact{a})
if !slices.Equal(needs, row.needs) {
t.Errorf("%s: needs %v, want %v", row.name, needs, row.needs)
}
for node, stated := range row.counted {
if forms.Current.Held(needs, stated) {
t.Errorf("%s: the want of %s is held", row.name, node)
seatRef, storeRef := k.seatRef, k.storeRef
for _, row := range []struct {
name string
present, counted map[string][]string
reference string
references []string
needs []string
}{
{"seat form answered, B away stating nothing: the derived store form stays, in the single reference",
map[string][]string{"a": seat}, map[string][]string{"a": seat, "b": nil}, storeRef, []string{storeRef, seatRef},
[]string{"form:artifact-store", "form:seat-reference"}},
{"seat form answered, every counted engine reads it: the seat form only",
map[string][]string{"a": seat}, map[string][]string{"a": seat, "b": seat}, seatRef, nil, []string{"form:seat-reference"}},
{"seat form answered, a present engine stating nothing: the store form only",
map[string][]string{"a": seat, "b": nil}, map[string][]string{"a": seat, "b": nil}, storeRef, nil, []string{"form:artifact-store"}},
{"seat form answered, no node present: the store form", nil, map[string][]string{"a": seat}, storeRef, nil, []string{"form:artifact-store"}},
} {
a := forms.Current.Choose(delivery.BuiltArtifact{Name: "code", Kind: k.kind, Digest: digest}, []string{seatRef}, row.present, row.counted)
if a.Reference != row.reference || !slices.Equal(a.References, row.references) {
t.Errorf("%s %s: %q %v, want %q %v", k.kind, row.name, a.Reference, a.References, row.reference, row.references)
}
needs := forms.Current.Needs([]delivery.BuiltArtifact{a})
if !slices.Equal(needs, row.needs) {
t.Errorf("%s %s: needs %v, want %v", k.kind, row.name, needs, row.needs)
}
for node, stated := range row.counted {
if forms.Current.Held(needs, stated) {
t.Errorf("%s %s: the want of %s is held", k.kind, row.name, node)
}
}
// mesh-sdk's referenceProblem does not yet know the holder's upstream/<host>/<path> naming (a request to the SDK's owner).
if _, err := delivery.EncodeBuilderBuild(delivery.BuilderBuild{State: delivery.BuildDone, Manifest: strings.TrimPrefix(digest, "sha256:"), Artifacts: []delivery.BuiltArtifact{a}, Needs: needs}); err != nil && k.kind != "upstream" {
t.Errorf("%s %s: %v", k.kind, row.name, err)
}
}
if _, err := delivery.EncodeBuilderBuild(delivery.BuilderBuild{State: delivery.BuildDone, Manifest: strings.TrimPrefix(digest, "sha256:"), Artifacts: []delivery.BuiltArtifact{a}, Needs: needs}); err != nil {
t.Errorf("%s: %v", row.name, err)
}
}
// What the assigner holds a want by (ADR 0624 §2), from the same forms.
+39 -12
View File
@@ -32,12 +32,31 @@ const (
FormPackageVersion = "package-version"
)
// FormSeatReference is the form a registry seat answers for a bundle or an archive it published,
// oci-artifact-registry/<module>/<artifact>@sha256:<digest> (novox/hq ADR 0605 §9; catalogue.SeatReference, read back by
// catalogue.InRegistrySeat), read by a node-engine that states form:seat-reference (catalogue.ReferenceFormSeat). Not a
// first form: an engine stating nothing reads its blob only in the older artifact-store form, which it derives (Older).
// FormSeatReference is the form a registry seat answers for what it published,
// <seat>/<module>/<artifact>@sha256:<digest> (novox/hq ADR 0605 §9; catalogue.SeatReference, read back by
// catalogue.InRegistrySeat): a bundle or an archive through oci-artifact-registry, an image through
// container-image-registry, and an upstream copy through container-image-registry under the holder's own naming,
// container-image-registry/upstream/<host>/<path>@sha256:<digest>. It is read by a node-engine that states
// form:seat-reference (catalogue.ReferenceFormSeat). Not a first form: an engine stating nothing reads the artifact in the
// older artifact-store form, which it derives (Older).
const FormSeatReference = catalogue.ReferenceFormSeat
// upstreamPrefix opens an upstream copy's name in the image seat's answer: the holder's naming, upstream/<host>/<path>.
const upstreamPrefix = "upstream/"
// inSeatReference reads a reference in the seat form: the seat it came through and the name and digest after it,
// <module>/<artifact>@<digest> (or upstream/<host>/<path>@<digest> for an upstream copy of the image seat).
func inSeatReference(r string) (seat, path string, ok bool) {
if seat, path, ok = catalogue.InRegistrySeat(r); ok {
return seat, path, true
}
rest, found := strings.CutPrefix(r, catalogue.ContainerImageRegistrySeat+"/"+upstreamPrefix)
if !found || !strings.Contains(rest, "@sha256:") {
return "", "", false
}
return catalogue.ContainerImageRegistrySeat, upstreamPrefix + rest, true
}
// ArtifactForm is one reference form: its name, whether it is a first form, the artifact kinds it names, how a
// reference is told to be in it, and, for a form that names the same artifact an older form does, that older reference
// (Older, nil when it derives none): the old-form window writes it beside the answered one (ADR 0624 §1, §3).
@@ -55,21 +74,29 @@ type ArtifactForms []ArtifactForm
// Current are the forms the builder writes and the assigner knows: the three first forms (delivery.BuiltArtifact's
// reference by kind), then the registry seat's form of a bundle or an archive.
var Current = ArtifactForms{
{Name: FormArtifactStore, First: true, Is: func(r string) bool { return strings.HasPrefix(r, artifactStore) },
Kinds: []string{catalogue.ArtifactBundle, catalogue.ArtifactArchive, catalogue.ArtifactImage, catalogue.ArtifactUpstream}},
// The registry form precedes the artifact-store form: what a build key kept of an image is recorded without the
// registry's address (catalogue.Recorded), so the artifact-store form is the newest first form an image has, the one
// Kept keeps for a node that states nothing.
{Name: FormRegistry, First: true, Is: func(r string) bool { return !strings.HasPrefix(r, artifactStore) && strings.Contains(r, "@sha256:") },
Kinds: []string{catalogue.ArtifactImage, catalogue.ArtifactUpstream}},
{Name: FormArtifactStore, First: true, Is: func(r string) bool { return strings.HasPrefix(r, artifactStore) },
Kinds: []string{catalogue.ArtifactBundle, catalogue.ArtifactArchive, catalogue.ArtifactImage, catalogue.ArtifactUpstream}},
{Name: FormPackageVersion, First: true, Is: func(r string) bool { return strings.LastIndex(r, "@") > 0 && !strings.Contains(r, "@sha256:") },
Kinds: []string{catalogue.ArtifactPackage}},
{Name: FormSeatReference, Kinds: []string{catalogue.ArtifactBundle, catalogue.ArtifactArchive},
{Name: FormSeatReference, Kinds: []string{catalogue.ArtifactBundle, catalogue.ArtifactArchive, catalogue.ArtifactImage, catalogue.ArtifactUpstream},
Is: func(r string) bool {
seat, _, ok := catalogue.InRegistrySeat(r)
return ok && seat == catalogue.OciArtifactRegistrySeat
seat, _, ok := inSeatReference(r)
return ok && (seat == catalogue.OciArtifactRegistrySeat || seat == catalogue.ContainerImageRegistrySeat)
},
// The same blob in the artifact store's form: oci-artifact-registry/<m>/<a>@<d> is artifact-store://<m>/<a>/blobs/<d>.
// The same artifact in the artifact store's form: oci-artifact-registry/<m>/<a>@<d> is artifact-store://<m>/<a>/blobs/<d>;
// container-image-registry/<m>/<a>@<d> (an upstream copy's upstream/<h>/<p>@<d> likewise) is artifact-store://<m>/<a>@<d>.
Older: func(r string) string {
path, _ := catalogue.InArtifactStore(r)
return catalogue.ArtifactStoreScheme + path
seat, rest, _ := inSeatReference(r)
if seat == catalogue.OciArtifactRegistrySeat {
path, _ := catalogue.InArtifactStore(r)
return catalogue.ArtifactStoreScheme + path
}
return catalogue.ArtifactStoreScheme + rest
}},
}