//go:build integration package main import ( "encoding/json" "testing" "time" "git.novox.be/novox/mesh-sdk/go/catalogue" "github.com/novox/mesh-controller/internal/inventory" ) // TestReplay201ThePlansSend replays novox/hq issue 201 (2026-10-02): two merges a minute apart made two plans; the // controller's plan rolled the newer controller onto the control node, and the node-engine's plan then sent that // machine the controller build before it, whose binary refused the seat row the newer one had widened. Here the // control node, anchor, was last sent the newer controller c2 while the mesh's record of the controller is the // build before it, c1, which passed its gate. The outcome asserted: a send that is no person's push — composed as a // plan's send composes it (keepingRecorded, what sendKeeps gives every send through sendToEach) — carries the // controller at c2, the build the machine was last sent, and not the older record; a person's push still carries // the record. Written with only what the controller had before its fix (mesh-controller #273) — the inventory's // build, gate, assignment and send records, keepingRecorded, planFor and declarationFor — so it is laid over the // commit before; the fix's own TestReplay201 reads what the fix added. Needs the store (MESH_TEST_POSTGRES), and // is named in testdata/store-tests. func TestReplay201ThePlansSend(t *testing.T) { open := aMesh(t) ctx := t.Context() inv := open.inventory const older, newer = "c1aaaaaaaaaa", "c2bbbbbbbbbb" old, now := time.Now().Add(-2*time.Hour), time.Now().Add(-time.Minute) record := func(commit string, asked time.Time) inventory.Build { t.Helper() manifest, _ := json.Marshal(catalogue.Manifest{Module: "mesh-controller", Version: "1"}) b := inventory.Build{ID: "build-mesh-controller-" + commit, Module: "mesh-controller", Commit: commit, Repository: "novox/mesh-controller", Manifest: manifest, Asked: asked, At: asked, Made: []inventory.Artifact{{Name: "x", Kind: "bundle", Reference: "sha256:" + commit + "0000000000000000"}}} if err := inv.RecordBuild(ctx, b); err != nil { t.Fatal(err) } return b } // The older controller rolled out and passed its gate; the newer one was asked after it and registered. before := record(older, old) if err := inv.RecordGate(ctx, inventory.GateVerdict{Build: before.ID, Module: "mesh-controller", Commit: older, Machines: []string{"anchor"}, Verdict: inventory.GatePassed}); err != nil { t.Fatal(err) } record(newer, now) if err := inv.RegisterModule(ctx, catalogue.Manifest{Module: "mesh-controller", Version: "1"}, inventory.Source{ Repository: "novox/mesh-controller", BuiltFrom: newer, Head: newer, Asked: now}); err != nil { t.Fatal(err) } if _, err := inv.Assign(ctx, "anchor", "mesh-controller"); err != nil { t.Fatal(err) } // The controller's plan sent anchor the newer controller. if err := inv.RecordSent(ctx, nodeID(t, open, "anchor"), "d-anchor", map[string]string{"mesh-controller": newer}); err != nil { t.Fatal(err) } // And the mesh's record of the controller is the build before it — whatever made it so. if err := inv.RestoreModule(ctx, before); err != nil { t.Fatal(err) } // The controller each send to anchor carries: a plan's send keeps recorded builds (keepingRecorded, what // sendKeeps gives every send but a person's push); a person's push composes the mesh's record. controllerSent := func(sends string, keeping bool) string { t.Helper() c := ctx if keeping { c = keepingRecorded(ctx) } plan, settings, err := resolveNode(c, open, "anchor") if err != nil { t.Fatalf("%s to anchor did not compose: %v", sends, err) } declared, err := declarationFor(c, open, "anchor", plan, settings) if err != nil { t.Fatalf("%s to anchor did not compose: %v", sends, err) } return declared.Builds["mesh-controller"] } if got := controllerSent("a plan's send", true); got != newer { t.Fatalf("a plan's send carried anchor the controller %s, older than the %s anchor was last sent: the "+ "older binary would read the row its successor widened", short(got), short(newer)) } if got := controllerSent("a person's push", false); got != older { t.Fatalf("a person's push carried the controller %s, not the mesh's record %s", short(got), short(older)) } }