Judge: a store holder that builds is no longer refused by its manifest (issue 1966)
The operator's decision of 2026-11-04: the fresh-mesh circle, a holder whose build publishes through itself, is caught where a fresh mesh starts (issue 1152), not by a rule that refuses the registry seats' holder. Claude-Session: https://claude.ai/code/session_01JG73KJNrH5EgFXMKKYSrig
This commit is contained in:
@@ -2845,19 +2845,6 @@ func parseManifest(raw []byte, predefined catalogue.PredefinedList) (catalogue.M
|
||||
problems = append(problems, movedProblems(m)...)
|
||||
problems = append(problems, collectionProblems(m)...)
|
||||
problems = append(problems, undeliveredBundles(m)...)
|
||||
// **What provides the artifact store cannot be delivered through it** (novox/hq 04-ISSUES/029).
|
||||
//
|
||||
// Building publishes to the store, and the builder will not start without one. So a module
|
||||
// that provides the store and also builds something asks the mesh to put an artifact into the
|
||||
// thing that artifact is needed to create.
|
||||
//
|
||||
// It is the question the foundation record asks of every candidate — can it grant itself the
|
||||
// thing it provides? The store cannot create its own database, the broker cannot create its
|
||||
// own virtual host, and a registry cannot grant itself a repository. Such a module names its
|
||||
// image, exactly as the bundle names the three a first node starts from.
|
||||
//
|
||||
// Refused here because the alternative is a build that never returns, on a mesh new enough
|
||||
// that nobody is watching it yet.
|
||||
if m.Build != nil && len(m.Bundles) > 0 {
|
||||
// The output of a build, written beside the build that produces it (ADR 0175). A resource
|
||||
// naming a digest beside an `artifact` would be the same mistake, and is caught the same way:
|
||||
@@ -2867,21 +2854,12 @@ func parseManifest(raw []byte, predefined catalogue.PredefinedList) (catalogue.M
|
||||
"produced; a manifest states `build.artifacts` and nothing about what came out",
|
||||
m.Module))
|
||||
}
|
||||
if m.Build != nil && len(m.Build.Artifacts) > 0 {
|
||||
for _, o := range m.Offers() {
|
||||
if o != catalogue.ArtifactStoreProvision {
|
||||
continue
|
||||
}
|
||||
problems = append(problems, fmt.Sprintf(
|
||||
"%s provides %q and also builds %d artifact(s), which cannot both be true: "+
|
||||
"building publishes to the artifact store, so this asks the mesh to put an "+
|
||||
"artifact into the thing that artifact is needed to create. A module that "+
|
||||
"provides the store names its image instead. One that wants more beside it "+
|
||||
"— an interface, a tool server — is a second module, mirrored in the "+
|
||||
"ordinary way once this one is running",
|
||||
m.Module, catalogue.ArtifactStoreProvision, len(m.Build.Artifacts)))
|
||||
}
|
||||
}
|
||||
// **A store holder that builds is not refused by its manifest** (the operator, 2026-11-04, issue 1966; this rule
|
||||
// came from novox/hq 04-ISSUES/029). A rule here refused a module that provides `artifact-store` and also builds an
|
||||
// artifact: building publishes to the store, so on a fresh mesh with no store yet such a build would wait for the
|
||||
// module it belongs to. The registry seats' holder builds the program it runs in front of the store (design 51),
|
||||
// so it publishes through itself; that circle is a fact of a mesh's first start, not of a manifest. It is caught where
|
||||
// a fresh mesh starts, by the genesis fix of issue 1152, and no rule refuses the manifest for it.
|
||||
for to := range m.Serves {
|
||||
var offered bool
|
||||
for _, o := range m.Offers() {
|
||||
|
||||
@@ -4239,24 +4239,17 @@ func TestTakesSettingsIsRefusedWhereItCannotMeanAnything(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// The module that provides the artifact store may not be delivered through it.
|
||||
//
|
||||
// Building publishes to the store and the builder will not start without one, so a module that
|
||||
// provides the store and also builds something asks the mesh to put an artifact into the thing
|
||||
// that artifact is needed to create. On a mesh new enough to have no registry, that is a build
|
||||
// that never returns (novox/hq 04-ISSUES/029).
|
||||
func TestTheArtifactStoreCannotBeDeliveredThroughItself(t *testing.T) {
|
||||
// A store holder that builds is not refused by its manifest (the operator, 2026-11-04, issue 1966). The fresh-mesh
|
||||
// circle the rule of novox/hq 04-ISSUES/029 refused, a holder whose build publishes through itself, is caught where a
|
||||
// fresh mesh starts (issue 1152), not here.
|
||||
func TestAStoreHolderThatBuildsIsNotRefusedByItsManifest(t *testing.T) {
|
||||
_, err := ParseManifest([]byte(`{"module":"registry","version":"1",` +
|
||||
`"provides":[{"name":"artifact-store","scope":"mesh"}],` +
|
||||
`"build":{"artifacts":[{"name":"registry","kind":"upstream","from":"registry:2"}]},` +
|
||||
`"resources":[{"id":"store","type":"container","name":"mesh-registry",` +
|
||||
`"artifact":"registry","ports":["5000:5000"]}]}`))
|
||||
if err == nil {
|
||||
t.Fatal("a registry module that builds its own image was accepted; the build has " +
|
||||
"nowhere to publish until the module it belongs to is already running")
|
||||
}
|
||||
if !strings.Contains(err.Error(), "artifact-store") {
|
||||
t.Fatalf("refused without naming the provision the cycle turns on: %v", err)
|
||||
if err != nil {
|
||||
t.Fatalf("a module that provides the artifact store and builds was refused: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user