DLV-B9: a bundle answered in the registry seat's form keeps the artifact-store form it derives for each counted engine that does not read it
The builder's forms gain seat-reference for bundles and archives (oci-artifact-registry/<module>/<artifact>@<digest>); the old-form window writes the older artifact-store reference beside it (catalogue.InArtifactStore), the oldest kept in the single reference (ADR 0624 §1, §3), so mesh-build-go's seat-form answer no longer strands an engine stating nothing. Claude-Session: https://claude.ai/code/session_01JG73KJNrH5EgFXMKKYSrig
This commit is contained in:
@@ -1342,6 +1342,44 @@ func aDoneKeyKeepsEachFormACountedNodeReads(t *testing.T) {
|
||||
if got := fs.Needs(withBoth); !slices.Equal(got, []string{"form:new", "form:old"}) {
|
||||
t.Errorf("needs %v", got)
|
||||
}
|
||||
// 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"}},
|
||||
} {
|
||||
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)
|
||||
}
|
||||
}
|
||||
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.
|
||||
for _, row := range []struct {
|
||||
name string
|
||||
|
||||
@@ -308,7 +308,7 @@ func TestTheBuildersVersions(t *testing.T) {
|
||||
}
|
||||
})
|
||||
t.Run("old form", func(t *testing.T) {
|
||||
// One kind, a first form and a newer one (the builder's own forms are all first today, so no window opens).
|
||||
// One kind, a first form and a newer one.
|
||||
fs := forms.ArtifactForms{{Name: "registry", First: true, Kinds: []string{"image"}}, {Name: "oci", Kinds: []string{"image"}}}
|
||||
both := []string{forms.FormNeed("oci")}
|
||||
for _, c := range []struct {
|
||||
@@ -327,8 +327,10 @@ func TestTheBuildersVersions(t *testing.T) {
|
||||
t.Errorf("%s: Holding = %v, want %v", c.name, got, c.want)
|
||||
}
|
||||
}
|
||||
if got := Holding(forms.Current, map[string][]string{"a": nil}, nil); got != nil {
|
||||
t.Errorf("forms.Current, a node stating nothing: Holding = %v, want none", got)
|
||||
// The builder's own forms: the registry seat's form of a bundle is not a first form, so a node stating nothing
|
||||
// holds the window and one stating form:seat-reference does not.
|
||||
if got := Holding(forms.Current, map[string][]string{"a": nil, "b": {forms.FormNeed(forms.FormSeatReference)}}, nil); !reflect.DeepEqual(got, []string{"a"}) {
|
||||
t.Errorf("forms.Current, a node stating nothing and one stating form:seat-reference: Holding = %v, want a", got)
|
||||
}
|
||||
t0 := time.Unix(0, 0)
|
||||
w, closed, overdue := OldFormWindow{}.Step([]string{"c"}, t0)
|
||||
|
||||
+44
-4
@@ -32,20 +32,28 @@ const (
|
||||
FormPackageVersion = "package-version"
|
||||
)
|
||||
|
||||
// ArtifactForm is one reference form: its name, whether it is a first form, the artifact kinds it names, and how a
|
||||
// reference is told to be in it.
|
||||
// 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).
|
||||
const FormSeatReference = catalogue.ReferenceFormSeat
|
||||
|
||||
// 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).
|
||||
type ArtifactForm struct {
|
||||
Name string
|
||||
First bool
|
||||
Kinds []string
|
||||
Is func(reference string) bool
|
||||
Older func(reference string) string
|
||||
}
|
||||
|
||||
// ArtifactForms are the forms a builder knows, oldest first.
|
||||
type ArtifactForms []ArtifactForm
|
||||
|
||||
// Current are the forms the builder writes and the assigner knows: the three first forms (delivery.BuiltArtifact's
|
||||
// reference by kind).
|
||||
// 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}},
|
||||
@@ -53,6 +61,16 @@ var Current = ArtifactForms{
|
||||
Kinds: []string{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},
|
||||
Is: func(r string) bool {
|
||||
seat, _, ok := catalogue.InRegistrySeat(r)
|
||||
return ok && seat == catalogue.OciArtifactRegistrySeat
|
||||
},
|
||||
// The same blob in the artifact store's form: oci-artifact-registry/<m>/<a>@<d> is artifact-store://<m>/<a>/blobs/<d>.
|
||||
Older: func(r string) string {
|
||||
path, _ := catalogue.InArtifactStore(r)
|
||||
return catalogue.ArtifactStoreScheme + path
|
||||
}},
|
||||
}
|
||||
|
||||
// FormNeed is the reader capability a form needs of a node-engine: `form:<name>`.
|
||||
@@ -180,9 +198,12 @@ func (fs ArtifactForms) Kept(kind string, present, counted map[string][]string)
|
||||
// Choose names a built artifact by the references the build answered in the forms Kept keeps (ADR 0624 §1, §3): the
|
||||
// oldest kept form in the single Reference, every kept one in References when there are more than one. A reference in a
|
||||
// form Kept does not keep is left out, unless none of the answered is kept: then the artifact keeps what was answered,
|
||||
// its first answered in Reference, since a key names where its artifact is (ADR 0498 clause 1).
|
||||
// its first answered in Reference, since a key names where its artifact is (ADR 0498 clause 1). An answered reference
|
||||
// in a form that derives an older one (ArtifactForm.Older) answers that older one too, so the build answers one form and
|
||||
// the key keeps each a counted node reads.
|
||||
func (fs ArtifactForms) Choose(a delivery.BuiltArtifact, answered []string, present, counted map[string][]string) delivery.BuiltArtifact {
|
||||
kept := fs.Kept(a.Kind, present, counted)
|
||||
answered = fs.withOlder(a.Kind, answered)
|
||||
type ref struct {
|
||||
at int
|
||||
reference string
|
||||
@@ -224,3 +245,22 @@ func (fs ArtifactForms) Choose(a delivery.BuiltArtifact, answered []string, pres
|
||||
}
|
||||
return a
|
||||
}
|
||||
|
||||
// withOlder is answered with, after it, each older reference an answered one's form derives that was not answered itself.
|
||||
func (fs ArtifactForms) withOlder(kind string, answered []string) []string {
|
||||
out := slices.Clone(answered)
|
||||
for _, r := range answered {
|
||||
name, ok := fs.FormOf(kind, r)
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
for _, f := range fs {
|
||||
if f.Name == name && f.Older != nil {
|
||||
if older := f.Older(r); !slices.Contains(out, older) {
|
||||
out = append(out, older)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user