Read the rest of the mesh and who is on the network with the current manifests: a node's kept build applies only to its own resolution, as the controller keeps a recorded module after reading both (review round 2, item 1). The test asserting the opposite failed first

This commit is contained in:
2026-10-20 07:06:09 +00:00
parent 28d4b9eb0d
commit 0729556ba3
5 changed files with 19 additions and 15 deletions
+1 -1
View File
@@ -30,7 +30,7 @@ import (
// (ADR 0446 clause 2).
type Input struct {
// Catalogue is the shelf: every module's manifest by name (inv.Catalogue), as it is to be composed. A recorded
// module kept at the build a machine runs (keepRecorded) is that node's Kept, applied to its own resolution only.
// module kept at the build a machine runs (keepRecorded) is that node's Kept, applied to its own resolution only (never to the rest of the mesh).
Catalogue map[string]catalogue.Manifest
// Nodes is every node the mesh has (inv.Nodes and inv.Overlays together, one row per node).
Nodes []Node
+1 -1
View File
@@ -243,7 +243,7 @@ func (c *composer) onTheNetwork() []Node {
if len(n.Assigned) == 0 {
continue
}
got, err := catalogue.Resolve(c.shelfFor(n), n.Assigned,
got, err := catalogue.Resolve(c.in.Catalogue, n.Assigned,
catalogue.Node{Name: n.Name, Site: n.Place.Site, Capabilities: n.Capabilities},
catalogue.World{Unchecked: true, Holdings: c.in.Holdings})
if err != nil {
+11 -7
View File
@@ -6,6 +6,7 @@ import (
"testing"
"git.novox.be/novox/mesh-sdk/go/catalogue"
"git.novox.be/novox/mesh-sdk/go/overlay"
)
func resourceIDs(d Declared) []string {
@@ -369,20 +370,23 @@ func TestAKeptModuleChangesOnlyTheResolutionOfTheNodeThatKeepsIt(t *testing.T) {
}
}
// And the rest of the mesh, as a node composes against it, offers what each other node's kept build offers, not the current one.
func TestTheRestOfTheMeshReadsEachOtherNodesKeptBuild(t *testing.T) {
// Another node's kept build changes neither the rest of the mesh nor who is on the network: the controller reads both with the
// current manifests, and only then keeps a recorded module for the node it composes (recorded_kept.go keepRecorded).
func TestAnotherNodesKeptBuildDoesNotChangeTheRestOfTheMeshOrWhoIsOnTheNetwork(t *testing.T) {
in := threeNodes(t)
nodeOf(t, &in, "anchor").Kept = map[string]catalogue.Manifest{"objects": {Module: "objects", Version: "0"}, overlayName(): {Module: overlayName(), Version: "0"}}
w, _, _, err := TheRestOfTheMesh(in, "laptop")
if err != nil || len(providers(w, "s3-bucket")) != 1 {
t.Fatalf("before: %v %v", providers(w, "s3-bucket"), err)
t.Errorf("a kept build changed what anchor offers: %v %v", providers(w, "s3-bucket"), err)
}
nodeOf(t, &in, "anchor").Kept = map[string]catalogue.Manifest{"objects": {Module: "objects", Version: "0"}}
w, _, _, err = TheRestOfTheMesh(in, "laptop")
if err != nil || len(providers(w, "s3-bucket")) != 0 {
t.Errorf("a node keeping a build that offers nothing still offers: %v %v", providers(w, "s3-bucket"), err)
where, err := newComposer(in).whereEveryoneIs()
if err != nil || where["anchor"] == "" {
t.Errorf("a kept build took anchor off the network: %v %v", where, err)
}
}
func overlayName() string { return overlay.Name }
// Round 1, finding 6: the nodes the composition did not count as on the network are returned, said, not lost.
func TestANodeNotCountedAsOnTheNetworkIsSaidInTheResult(t *testing.T) {
in := aMesh(t)
+3 -2
View File
@@ -233,8 +233,9 @@ func (c *composer) resolution(nodeName string) (catalogue.Resolution, error) {
}
// shelfFor is the catalogue as one node composes its own set: the Input's, with each recorded or core module the node keeps at the
// build it runs put in place of the current one (plan.go keepRecorded). A copy: the Input's catalogue, and so every other node's
// resolution, is untouched.
// build it runs put in place of the current one (plan.go keepRecorded). A copy: the Input's catalogue is untouched. Only the node's own planFor and
// resolution use it; the rest of the mesh and who is on the network are read with the current manifests, as the controller reads them
// before it keeps a recorded module.
func (c *composer) shelfFor(node Node) map[string]catalogue.Manifest {
if len(node.Kept) == 0 {
return c.in.Catalogue
+3 -4
View File
@@ -71,7 +71,6 @@ func (c *composer) theRestOfTheMesh(exclude string) (catalogue.World, Passes, []
node catalogue.Node
assigned []string
pins map[string]catalogue.Chosen
shelf map[string]catalogue.Manifest
}
var others []candidate
// Every machine's assignments, before the holdings are read by any resolution (novox/hq ADR 0449 clause 4): a seat
@@ -95,14 +94,14 @@ func (c *composer) theRestOfTheMesh(exclude string) (catalogue.World, Passes, []
others = append(others, candidate{
node: catalogue.Node{Name: n.Name, Site: n.Place.Site, Capabilities: n.Capabilities,
At: onNetwork[n.Name], PublicDomain: n.PublicDomain},
assigned: theirs, pins: n.Pins, shelf: c.shelfFor(n)})
assigned: theirs, pins: n.Pins})
}
var left []LeftOut
offered := map[string][]catalogue.Provider{}
var firstHeld []catalogue.Held
for _, o := range others {
got, err := catalogue.Resolve(o.shelf, o.assigned, o.node, catalogue.World{Unchecked: true, Holdings: holdings})
got, err := catalogue.Resolve(shelf, o.assigned, o.node, catalogue.World{Unchecked: true, Holdings: holdings})
if err != nil {
// Said, not skipped: a machine dropped here offers nothing and holds nothing.
left = append(left, LeftOut{Node: o.node.Name, Err: err})
@@ -139,7 +138,7 @@ func (c *composer) theRestOfTheMesh(exclude string) (catalogue.World, Passes, []
// Each machine is resolved with its own pins, as its plan is.
theirs := world
theirs.Pinned = o.pins
got, err := catalogue.Resolve(o.shelf, o.assigned, o.node, theirs)
got, err := catalogue.Resolve(shelf, o.assigned, o.node, theirs)
if err != nil {
// Said only for the whole-mesh view: with one machine excluded, the view is partial by design.
if exclude == "" {