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:
2026-11-04 14:45:00 +01:00
parent 3a64fde7d9
commit 3caa8291b0
3 changed files with 87 additions and 7 deletions
+44 -4
View File
@@ -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
}