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
+3 -3
View File
@@ -1155,9 +1155,6 @@ func selfComposer(session *link.Session, node string, hooks composerHooks, say f
env.ComposedState = link.EngineComposed{Session: session, Node: node}
// And each composition it writes there said as the seat's event composed, which the assigner waits on.
env.SayComposed = session.SayComposed
// And the catalog half read by the fingerprints its wants and runnings name, over its own calls of the seat mesh-catalog's
// verb entry on its link session (design 47 G §421): neither the indexer's nor the builder's states are read.
env.Entry = selfcompose.EntryCall(session.AskMeshSeat)
return selfcompose.New(env)
}
@@ -1199,6 +1196,9 @@ func composerEnv(session *link.Session, node string, say func(string), hooks com
} else if hooks.seatListFailed {
env.SeatList = selfcompose.Unread{}
}
// And the shadow too: the catalog half read by the fingerprints its wants and runnings name, over its own calls of the seat mesh-catalog's
// verb entry on its link session (design 47 G §421): neither the indexer's nor the builder's states are read.
env.Entry = selfcompose.EntryCall(session.AskMeshSeat)
return env
}
+1 -14
View File
@@ -12,7 +12,6 @@ import (
"git.novox.be/novox/mesh-contracts/go/seats/meshmoduleassigner"
nodeengine "git.novox.be/novox/mesh-contracts/go/seats/nodeengine"
condseat "git.novox.be/novox/mesh-contracts/health-and-repair/go/seats/meshconditions"
builderbuilds "git.novox.be/novox/mesh-delivery/modules/mesh-delivery-builder/builds"
"git.novox.be/novox/mesh-delivery/modules/mesh-delivery-contracts/go/clients/meshcatalogclient"
"git.novox.be/novox/mesh-delivery/modules/mesh-delivery-contracts/go/clients/meshdeliveryclient"
"git.novox.be/novox/mesh-delivery/modules/mesh-delivery-contracts/go/seats/meshcatalog"
@@ -493,7 +492,6 @@ func h8(t *testing.T, b *itBed, checkBuild bool) (func(), h8state) {
}
assignment, modules, manifests := kvOf(buckets.Assignments), kvOf(buckets.Modules), kvOf(buckets.Manifests)
resolved := kvOf(selfcompose.ResolvedBucket)
builds := kvOf(builderbuilds.BuilderBuildsBucket)
candidates := kvOf(buckets.ProposalCandidates)
packages := kvOf(link.PackagesBucket)
path := filepath.Join(b.dir, "web.conf")
@@ -523,10 +521,6 @@ func h8(t *testing.T, b *itBed, checkBuild bool) (func(), h8state) {
rec2, _ := nec.EncodeHaveNode(nodeengine.HaveByNodeNodeValue{Record: &nodeengine.NodeRecord{Node: "it2", Capabilities: []string{"service-manager"}}})
pkey2, _ := meshmoduleassignerclient.NodeKey("it2")
hkey2, _ := nec.HaveNodeKey("it2")
buildKey, _ := builderbuilds.BuilderBuildKey("web", fp)
done, _ := builderbuilds.EncodeBuilderBuild(builderbuilds.BuilderBuild{State: builderbuilds.BuildDone, Manifest: digest,
Artifacts: []builderbuilds.BuiltArtifact{{Name: "files", Kind: "archive", Reference: "artifact-store://web/files/blobs/" + fpDigest("f"), Digest: fpDigest("f")}}})
firstBuild := done
for _, w := range []struct {
kv nats.KeyValue
key string
@@ -534,7 +528,7 @@ func h8(t *testing.T, b *itBed, checkBuild bool) (func(), h8state) {
}{{manifests, mkey, mraw}, {modules, "web", modv}, {b.haves, hkey, rec},
{resolved, itNode + ".web.greeting", []byte(`{"value":"bonjour","source":"module"}`)},
{manifests, mlkey, mlraw}, {modules, "mailer", mlmod}, {b.haves, hkey2, rec2}, {assignment, pkey2, places2[pkey2]}, {assignment, "it2.mailer", places2["it2.mailer"]},
{resolved, "it2.mailer.domain", []byte(`{"value":"example.org","source":"module"}`)}, {builds, buildKey, firstBuild}} {
{resolved, "it2.mailer.domain", []byte(`{"value":"example.org","source":"module"}`)}} {
if _, err := w.kv.Put(w.key, w.value); err != nil {
t.Fatal(err)
}
@@ -566,7 +560,6 @@ func h8(t *testing.T, b *itBed, checkBuild bool) (func(), h8state) {
t.Fatal(err)
}
if checkBuild {
_ = buildKey
// The entry of the build its want names is asked of the catalog half through the node's session: one the half holds none
// of holds the want (entry-missing, naming the fingerprint) and nothing is applied; once the half holds it and it is
// asked again by hand, then a config event, and the node composes.
@@ -855,7 +848,6 @@ func TestNatsTheBusServerIsTakenOverAndReplacedOnlyWhenItsBuildChangesIt(t *test
}
assignment, modules, manifests := kvOf(buckets.Assignments), kvOf(buckets.Modules), kvOf(buckets.Manifests)
kvOf(selfcompose.ResolvedBucket)
builds := kvOf(builderbuilds.BuilderBuildsBucket)
kvOf(buckets.ProposalCandidates)
kvOf(link.PackagesBucket)
// The bus module at a build, done: its manifest written and the indexer's module naming it at fp.
@@ -872,11 +864,6 @@ func TestNatsTheBusServerIsTakenOverAndReplacedOnlyWhenItsBuildChangesIt(t *test
if _, err := manifests.Put(mkey, mraw); err != nil {
t.Fatal(err)
}
bkey, _ := builderbuilds.BuilderBuildKey("nats", fp)
done, _ := builderbuilds.EncodeBuilderBuild(builderbuilds.BuilderBuild{State: builderbuilds.BuildDone, Manifest: digest})
if _, err := builds.Put(bkey, done); err != nil {
t.Fatal(err)
}
if _, err := modules.Put("nats", modv); err != nil {
t.Fatal(err)
}