DLV-I14: the judge refuses a packages entry naming no declared package or an ill-formed series

Between the manifests (design 32): each name in a module's packages is a package some manifest declares, by the
builder's name <module>/<artifact>, and each accepted series is <major>.<minor>.

Claude-Session: https://claude.ai/code/session_01JG73KJNrH5EgFXMKKYSrig
This commit is contained in:
2026-11-04 14:02:57 +01:00
parent 20a9322209
commit c22f9d25dc
3 changed files with 54 additions and 1 deletions
@@ -86,6 +86,8 @@ func TestBusStateIsJudgedOnce(t *testing.T) {
}
}
// Between the manifests: two modules' names on the bus alike, and a read of bus state that moved (ADR 0596 §2).
sdk := catalogue.Manifest{Module: "mesh-sdk", Build: &catalogue.Build{Artifacts: []catalogue.Artifact{
{Name: "go", Kind: catalogue.ArtifactPackage, Language: "go"}, {Name: "img", Kind: catalogue.ArtifactImage}}}}
entry := func(name string) []catalogue.BusStateEntry {
return []catalogue.BusStateEntry{{Name: name, Storage: catalogue.StorageKeyValue, Template: catalogue.TemplateState}}
}
@@ -99,8 +101,16 @@ func TestBusStateIsJudgedOnce(t *testing.T) {
"reader": {Module: "reader", Reads: []string{"owner.cache"}}}, "reader reads \"owner.cache\", which owner has moved"},
{"a read of state still kept", catalogue.Shelf{"owner": {Module: "owner", State: []catalogue.StateDeclaration{{Name: "cache"}}},
"reader": {Module: "reader", Reads: []string{"owner.cache"}}}, ""},
// DLV-I14 (design 32): the packages section names a declared package, by the builder's name, in a well-formed series.
{"packages naming a declared package", catalogue.Shelf{"mesh-sdk": sdk, "user": {Module: "user", Packages: map[string]string{"mesh-sdk/go": "0.2"}}}, ""},
{"packages naming no declared package", catalogue.Shelf{"mesh-sdk": sdk, "user": {Module: "user", Packages: map[string]string{"mesh-sdk": "0.1"}}},
`user's packages name "mesh-sdk", which no manifest declares`},
{"packages naming an image", catalogue.Shelf{"mesh-sdk": sdk, "user": {Module: "user", Packages: map[string]string{"mesh-sdk/img": "0.1"}}},
`name "mesh-sdk/img", which no manifest declares`},
{"packages in an ill-formed series", catalogue.Shelf{"mesh-sdk": sdk, "user": {Module: "user", Packages: map[string]string{"mesh-sdk/go": "v0.2"}}},
`user's packages accept "mesh-sdk/go" in the series "v0.2"`},
} {
got := strings.Join(BusStateCatalogueProblems(c.shelf), "\n")
got := strings.Join(append(BusStateCatalogueProblems(c.shelf), PackagesCatalogueProblems(c.shelf)...), "\n")
if (c.want == "") != (got == "") || !strings.Contains(got, c.want) {
t.Errorf("%s: between the manifests: %q, want %q", c.name, got, c.want)
}
@@ -0,0 +1,41 @@
package judge
import (
"fmt"
"maps"
"slices"
"strings"
"git.novox.be/novox/mesh-sdk/go/catalogue"
)
// PackagesCatalogueProblems are the rules of a manifest's `packages` no single manifest can be judged against (DLV-I14;
// ADR 0606 §4, design 32 *A package, its series, and the series its users accept*): each name is a package some manifest
// of the shelf declares, named as the builder names it (`<module>/<artifact>`), and each series is `<major>.<minor>`.
func PackagesCatalogueProblems(shelf catalogue.Shelf) []string {
declared := map[string]bool{}
for _, module := range shelfOrder(shelf) {
if b := shelf[module].Build; b != nil {
for _, a := range b.Artifacts {
if a.Kind == catalogue.ArtifactPackage {
declared[module+"/"+a.Name] = true
}
}
}
}
var problems []string
for _, module := range shelfOrder(shelf) {
accepts := shelf[module].Packages
for _, name := range slices.Sorted(maps.Keys(accepts)) {
if !declared[name] {
problems = append(problems, fmt.Sprintf("%s's packages name %q, which no manifest declares as a package "+
"(a package is named <module>/<artifact>; design 32)", module, name))
}
if s := strings.TrimSpace(accepts[name]); !seriesForm.MatchString(s) {
problems = append(problems, fmt.Sprintf("%s's packages accept %q in the series %q, which is no <major>.<minor> "+
"such as 0.1 (design 32)", module, name, accepts[name]))
}
}
}
return problems
}
@@ -4692,6 +4692,8 @@ func CatalogueProblems(shelf catalogue.Shelf) []string {
problems = append(problems, ObjectsCatalogueProblems(shelf)...)
// Bus state in `requires`: a name on the bus has one owner, and the new form has no readers (ADR 0595, ADR 0596 §2).
problems = append(problems, BusStateCatalogueProblems(shelf)...)
// A manifest's packages name a declared package in a well-formed series (design 32, DLV-I14).
problems = append(problems, PackagesCatalogueProblems(shelf)...)
// A module that hears a restricted stream runs as an account of its own (novox/hq ADR 0376 §2).
problems = append(problems, RestrictedHearingProblems(shelf)...)
// A work-queue stream is never asked for by another module's consumes (novox/hq ADR 0436 §6).