Fill the catalog's versions from every number the builder gave, numbered or published (design 47 G §372, A-350)
The builder numbers fresh versions without publishing them, so a fill from published alone would number again below what the builder already said, and one version would name two contents. The fill and its kind 1 and 3 edges take numbered and published alike; the version-form check and the claimed cut stay. A version the builder numbered without a digest is filled with none. Builds: design 47 G §372, A-350, A-351 Claude-Session: https://claude.ai/code/session_01NcbgfGKaxw984XyAPfLm4h
This commit is contained in:
@@ -17,9 +17,9 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
// The first fill of the versions (design 47 G §372): at the first start under G the state versions is filled once, as
|
// The first fill of the versions (design 47 G §372): at the first start under G the state versions is filled once, as
|
||||||
// released, for each module from the highest published version over every artifact of the module that the builder's state
|
// released, for each module from the highest version over every artifact of the module that the builder's state versions
|
||||||
// versions held, read by the builder's tool builder_versions as a kept call; then versions-filled is said once, and the
|
// gave a number, numbered or published (A-350), read by the builder's tool builder_versions as a kept call; then
|
||||||
// builder reserves nothing before it (§369).
|
// versions-filled is said once, and the builder reserves nothing before it (§369).
|
||||||
const (
|
const (
|
||||||
// BuilderVersionsCall is the tool the manifest names in its invokes (until that tool goes).
|
// BuilderVersionsCall is the tool the manifest names in its invokes (until that tool goes).
|
||||||
BuilderVersionsCall = "mesh-delivery-builder.builder_versions"
|
BuilderVersionsCall = "mesh-delivery-builder.builder_versions"
|
||||||
@@ -39,6 +39,11 @@ type BuilderVersion struct {
|
|||||||
At time.Time `json:"at"`
|
At time.Time `json:"at"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// givenANumber says whether the builder's state versions gave the version its number: numbered, or numbered and then
|
||||||
|
// published (A-350: the builder numbers fresh versions it has not published, so a fill from published alone would number
|
||||||
|
// again below what the builder already said).
|
||||||
|
func givenANumber(state string) bool { return state == "numbered" || state == "published" }
|
||||||
|
|
||||||
// BuilderVersionsAnswer is what builder_versions answers for a name.
|
// BuilderVersionsAnswer is what builder_versions answers for a name.
|
||||||
type BuilderVersionsAnswer struct {
|
type BuilderVersionsAnswer struct {
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
@@ -90,10 +95,10 @@ func (ix *Indexer) FillVersions(ctx context.Context, ask VersionsAsker) error {
|
|||||||
name string
|
name string
|
||||||
ref string
|
ref string
|
||||||
}
|
}
|
||||||
best := map[string][]found1{} // by module: each artifact's highest published version
|
best := map[string][]found1{} // by module: each artifact's highest numbered or published version (A-350)
|
||||||
var unanswered error
|
var unanswered error
|
||||||
for _, e := range entries {
|
for _, e := range entries {
|
||||||
var top string // the module's highest published version
|
var top string // the module's highest version the builder gave a number, numbered or published (A-350)
|
||||||
per := []found1{}
|
per := []found1{}
|
||||||
for _, a := range e.Artifacts {
|
for _, a := range e.Artifacts {
|
||||||
name := versionNameOf(e.Module, a)
|
name := versionNameOf(e.Module, a)
|
||||||
@@ -106,7 +111,7 @@ func (ix *Indexer) FillVersions(ctx context.Context, ask VersionsAsker) error {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
for _, v := range ans.Versions {
|
for _, v := range ans.Versions {
|
||||||
if _, ok := versionParts(v.Version); !ok || v.State != "published" {
|
if _, ok := versionParts(v.Version); !ok || !givenANumber(v.State) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
per = append(per, found1{v: v, name: name, ref: a.Ref})
|
per = append(per, found1{v: v, name: name, ref: a.Ref})
|
||||||
|
|||||||
@@ -66,7 +66,7 @@ func (ix *Indexer) filledEdges(ctx context.Context, entry meshcatalog.CatalogEnt
|
|||||||
}
|
}
|
||||||
var best *BuilderVersion
|
var best *BuilderVersion
|
||||||
for i, v := range ans.Versions {
|
for i, v := range ans.Versions {
|
||||||
if _, ok := versionParts(v.Version); !ok || v.State != "published" || v.At.After(claimed) {
|
if _, ok := versionParts(v.Version); !ok || !givenANumber(v.State) || v.At.After(claimed) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if best == nil || v.At.After(best.At) {
|
if best == nil || v.At.After(best.At) {
|
||||||
|
|||||||
@@ -87,10 +87,10 @@ func TestAVersionIsReleasedOnceEveryArtifactIsPublished(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Design 47 G §372: the first fill records, once, each module's highest published version over its artifacts as released
|
// Design 47 G §372, A-350: the first fill records, once, each module's highest version the builder gave a number, numbered or
|
||||||
// and says versions-filled once; a builder_versions that does not answer holds it and, after five minutes, is the finding
|
// published, over its artifacts as released and says versions-filled once; a builder_versions that does not answer holds it and, after five minutes, is the finding
|
||||||
// call-unanswered; a fill made is not made again.
|
// call-unanswered; a fill made is not made again.
|
||||||
func TestTheFirstFillOfTheVersionsComesFromTheBuildersPublished(t *testing.T) {
|
func TestTheFirstFillOfTheVersionsComesFromTheBuildersNumbers(t *testing.T) {
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
now := time.Date(2026, 11, 1, 3, 0, 0, 0, time.UTC)
|
now := time.Date(2026, 11, 1, 3, 0, 0, 0, time.UTC)
|
||||||
w := newFindings()
|
w := newFindings()
|
||||||
@@ -128,7 +128,8 @@ func TestTheFirstFillOfTheVersionsComesFromTheBuildersPublished(t *testing.T) {
|
|||||||
case "@novox/mesh-sdk":
|
case "@novox/mesh-sdk":
|
||||||
return BuilderVersionsAnswer{Name: name, Versions: []BuilderVersion{pub("0.1.18", "sha256:ts18")}}, nil
|
return BuilderVersionsAnswer{Name: name, Versions: []BuilderVersion{pub("0.1.18", "sha256:ts18")}}, nil
|
||||||
case "avahi/image":
|
case "avahi/image":
|
||||||
return BuilderVersionsAnswer{Name: name, Versions: []BuilderVersion{pub("0.2.3", "sha256:av")}}, nil
|
// published 0.1.0, numbered up to 0.1.14 and never published (A-350): the fill starts above 0.1.14
|
||||||
|
return BuilderVersionsAnswer{Name: name, Versions: []BuilderVersion{pub("0.1.0", "sha256:av"), {Version: "0.1.14", State: "numbered", Revision: "9"}}}, nil
|
||||||
}
|
}
|
||||||
return BuilderVersionsAnswer{Name: name}, nil
|
return BuilderVersionsAnswer{Name: name}, nil
|
||||||
}
|
}
|
||||||
@@ -157,6 +158,9 @@ func TestTheFirstFillOfTheVersionsComesFromTheBuildersPublished(t *testing.T) {
|
|||||||
if len(sdk) != 1 || sdk[0].Version != "0.1.18" || len(sdk[0].Artifacts) != 1 || sdk[0].Artifacts[0].Artifact != "mesh-sdk:ts" || sdk[0].Source != 9 {
|
if len(sdk) != 1 || sdk[0].Version != "0.1.18" || len(sdk[0].Artifacts) != 1 || sdk[0].Artifacts[0].Artifact != "mesh-sdk:ts" || sdk[0].Source != 9 {
|
||||||
t.Errorf("mesh-sdk's filled version: %+v (the higher of Go's 0.1.14 and npm's 0.1.18)", sdk)
|
t.Errorf("mesh-sdk's filled version: %+v (the higher of Go's 0.1.14 and npm's 0.1.18)", sdk)
|
||||||
}
|
}
|
||||||
|
if avahi, _ := ModuleVersions(ctx, ix.Versions, "avahi"); len(avahi) != 1 || avahi[0].Version != "0.1.14" || len(avahi[0].Artifacts) != 1 || avahi[0].Artifacts[0].Digest != "" {
|
||||||
|
t.Errorf("avahi's filled version: %+v (numbered 0.1.14 above published 0.1.0, so the first G build of 0.1 is 0.1.15, with no digest where the builder kept none, A-351)", avahi)
|
||||||
|
}
|
||||||
if fresh, _ := ModuleVersions(ctx, ix.Versions, "fresh"); len(fresh) != 0 {
|
if fresh, _ := ModuleVersions(ctx, ix.Versions, "fresh"); len(fresh) != 0 {
|
||||||
t.Errorf("a module with none published is filled: %+v", fresh)
|
t.Errorf("a module with none published is filled: %+v", fresh)
|
||||||
}
|
}
|
||||||
@@ -462,7 +466,8 @@ func TestTheFirstFillGivesTheNewestVersionsTheirFilledEdges(t *testing.T) {
|
|||||||
}
|
}
|
||||||
switch name {
|
switch name {
|
||||||
case "x/lib":
|
case "x/lib":
|
||||||
return BuilderVersionsAnswer{Versions: []BuilderVersion{pub("0.1.1", "sha256:l1", t0), pub("0.1.2", "sha256:l2", t0.Add(2*time.Hour))}}, nil
|
// 0.1.1 numbered and not published still counts (A-350)
|
||||||
|
return BuilderVersionsAnswer{Versions: []BuilderVersion{{Version: "0.1.1", State: "numbered", Digest: "sha256:l1", Revision: "9", At: t0}, pub("0.1.2", "sha256:l2", t0.Add(2*time.Hour))}}, nil
|
||||||
case "app/program":
|
case "app/program":
|
||||||
return BuilderVersionsAnswer{Versions: []BuilderVersion{pub("0.3.1", "sha256:a1", t0.Add(time.Hour))}}, nil
|
return BuilderVersionsAnswer{Versions: []BuilderVersion{pub("0.3.1", "sha256:a1", t0.Add(time.Hour))}}, nil
|
||||||
}
|
}
|
||||||
@@ -482,7 +487,7 @@ func TestTheFirstFillGivesTheNewestVersionsTheirFilledEdges(t *testing.T) {
|
|||||||
switch e.Kind {
|
switch e.Kind {
|
||||||
case 1:
|
case 1:
|
||||||
if e.Version != "0.1.1" || e.Digest != "sha256:l1" || !e.Stale {
|
if e.Version != "0.1.1" || e.Digest != "sha256:l1" || !e.Stale {
|
||||||
t.Errorf("kind 1 is the version published before the build was claimed: %+v", e)
|
t.Errorf("kind 1 is the version numbered or published before the build was claimed: %+v", e)
|
||||||
}
|
}
|
||||||
case 4:
|
case 4:
|
||||||
if e.Version != "0.9.1" || e.Digest != "sha256:prov/program" {
|
if e.Version != "0.9.1" || e.Digest != "sha256:prov/program" {
|
||||||
|
|||||||
Reference in New Issue
Block a user