R3-1, R3-2, R3-3: the node-engine reads no build of the builder; the shadow builds from the entry it holds

The composer's Build is made from the catalog half's entry it holds and the parts of the want that names it (buildOf); the
inputs of the indexer's modules and the builder's builds, takeBuildDone, takeModule and the builder read are gone, and mesh-host
names no BuilderBuildsBucket. The shadow takes the entries of the builds it composes from (askBuildsEntries), builds a module a
candidate adds from its entry and the candidate's `added` parts (A-316), and holds, with the reason, a module whose entry
has no part given, whose fingerprint the verb module does not give, or for which it errors (A-312). Its composer is given the
entry call as the node's own is. Rows: a built module added with and without parts, the verb module answering no fingerprint
and erroring.

Builds: design 47 G §421, §628, A-308, A-312, A-316
This commit is contained in:
2026-11-12 23:05:06 +01:00
parent e558510a54
commit 23799a30ed
12 changed files with 279 additions and 359 deletions
-38
View File
@@ -5,7 +5,6 @@ import (
"errors"
"git.novox.be/novox/mesh-contracts/go/clients/nodeengineclient"
"git.novox.be/novox/mesh-contracts/go/seats/nodeengine"
"git.novox.be/novox/mesh-delivery/modules/mesh-delivery-builder/builds"
"git.novox.be/novox/mesh-delivery/modules/mesh-delivery-contracts/go/clients/meshcatalogclient"
"github.com/novox/mesh-host/internal/buckets"
engcomp "github.com/novox/mesh-host/internal/compositions"
@@ -17,8 +16,6 @@ import (
"git.novox.be/novox/mesh-sdk/go/catalogue"
"github.com/novox/mesh-host/internal/compose/frombus"
"github.com/novox/mesh-host/internal/agent"
)
// fakeData is the engine's state data as a map, counting the writes and deletes made.
@@ -231,39 +228,4 @@ func TestTheEngineKeepsEachPlacedModulesDataItems(t *testing.T) {
if wrote, _ := pc.WritePackages(context.Background()); wrote {
t.Error("the verb's write of a key holding what was composed wrote it again")
}
// The items are worked out from what the pass read: a done build is read over the bus once, not again for the data
// items after the pass (a module in a running build is read again, since it may land).
b := newFakeBus()
done, _ := builds.EncodeBuilderBuild(builds.BuilderBuild{State: builds.BuildDone, Manifest: meshcatalogclient.ManifestDigest([]byte(lemurs))})
running, _ := builds.EncodeBuilderBuild(builds.BuilderBuild{State: "building"})
fp := meshcatalogclient.SourcePrefix2 + strings.Repeat("b", 64)
doneKey, _ := builds.BuilderBuildKey("web", fp)
runningKey, _ := builds.BuilderBuildKey("pg", fp)
b.kv[builds.BuilderBuildsBucket+"/"+doneKey], b.kv[builds.BuilderBuildsBucket+"/"+runningKey] = done, running
r := reader{c: New(b.env())}
for range 3 {
if got, err := r.Build(context.Background(), "web", fp); err != nil || got.State != builds.BuildDone {
t.Fatalf("the done build: %+v, %v", got, err)
}
if got, err := r.Build(context.Background(), "pg", fp); err != nil || got.State != "building" {
t.Fatalf("the running build: %+v, %v", got, err)
}
}
reads := map[string]int{}
for _, read := range b.reads {
reads[read[1]]++
}
if reads[doneKey] != 1 || reads[runningKey] != 3 {
t.Errorf("the builds were read %v times over the bus; want the done one once, the running one each time", reads)
}
// A done key the builder claims again (a gone step, issue 1937) and lands done again is read again, not served kept.
again, _ := builds.EncodeBuilderBuild(builds.BuilderBuild{State: builds.BuildDone, Manifest: meshcatalogclient.ManifestDigest([]byte("{}"))})
b.mu.Lock()
b.kv[builds.BuilderBuildsBucket+"/"+doneKey] = again
b.mu.Unlock()
r.c.takeBuildDone(agent.Update{Key: doneKey, Value: running})
if got, err := r.Build(context.Background(), "web", fp); err != nil || got.Manifest != meshcatalogclient.ManifestDigest([]byte("{}")) {
t.Errorf("a done build written again is served as %+v (%v), not read again", got, err)
}
}