Add the replay of issue 349: a merge acted on late superseded the merge after it (hq issue 349)
mesh/merge-gate out of date: judged against trunk 584ee991961c, the trunk is now 1c9bc9cf0041; judged again on a recheck or when it is merged
mesh/repo-check out of date: judged against trunk 584ee991961c, the trunk is now 1c9bc9cf0041; judged again on a recheck or when it is merged
mesh/delivery-group group fix/349-replay checking: composed check out of date: novox/mesh-controller@f796dc0b7307 was judged against trunk 584ee991961c, the tr…
mesh/delivery superseded: a newer head of the same pull request

Two catalogue merges acted on in reverse order left the fixed module planned at
the commit without the fix. The replay uses only what the controller had before
#179, so mesh-lab's prover can show it fails there and passes on #179 and main.
Listed among the store tests, so a check without a database cannot pass its skip.
This commit is contained in:
jochen
2026-10-13 05:21:56 +02:00
parent 584ee99196
commit f796dc0b73
2 changed files with 68 additions and 0 deletions
+67
View File
@@ -0,0 +1,67 @@
package main
import (
"testing"
"time"
"github.com/novox/mesh-controller/internal/catalogue"
"github.com/novox/mesh-controller/internal/inventory"
"github.com/novox/mesh-controller/internal/link"
)
// Replay of novox/hq issue 349 (2026-10-09): two merges into the catalogue's main were acted on in reverse order.
// The later one (a082615b, a security fix to the forge's module) was planned first; the earlier one (8ff8197a,
// another module), handed over late, was planned after it, and its plan superseded the later merge's at tier 0
// with "gitea planned there again": the forge's module was to be built for the commit without the fix. Written
// only with what the controller had before its fix (mesh-controller #179): a mesh, two registered modules of the
// catalogue, the merges as the forge announces them, the plans the inventory keeps — so it is laid over the
// commit before.
func TestReplay349(t *testing.T) {
open := aMesh(t)
ctx := t.Context()
inv := open.inventory
asksWithPaths(t)
for _, module := range []string{"app", "notes"} {
if err := inv.RegisterModule(ctx, catalogue.Manifest{Module: module, Version: "1"},
inventory.Source{Repository: "novox/mesh-catalog", Seat: "git", Path: "modules/" + module, Ref: "main",
BuiltFrom: "c0", Head: "c0"}); err != nil {
t.Fatal(err)
}
}
// Both made after the modules were last looked at, so neither is history.
made := time.Now().UTC().Add(time.Minute)
merge := func(commit, module string, at time.Time) link.SourceMoved {
return link.SourceMoved{Owner: "novox", Repo: "mesh-catalog", Base: "main", Commit: commit,
MergedAt: at.Format(time.RFC3339Nano), Paths: []string{"modules/" + module + "/module.json"},
ModuleDirs: []string{"modules/" + module}, ModuleDirsSaid: true}
}
const fix, earlier = "a082615bfix", "8ff8197aearlier"
// The later merge, the fix to notes, is acted on first; the earlier one, moving app, after it.
if err := (following{open: open}).SourceMoved(ctx, merge(fix, "notes", made.Add(time.Minute))); err != nil {
t.Fatal(err)
}
if err := (following{open: open}).SourceMoved(ctx, merge(earlier, "app", made)); err != nil {
t.Fatal(err)
}
plans, err := inv.RecentPlans(ctx, 20)
if err != nil {
t.Fatal(err)
}
// A plan superseded hands its modules to the plan that took it over; the plans left standing are what the mesh
// builds. One of them builds the fixed module, and every one that does builds it at the commit holding the fix.
built := 0
for _, p := range plans {
t.Logf("%s %s at %.8s: %v %s", p.ID, p.State, p.Commit, p.Tiers, p.Note)
if _, holds := p.Modules["notes"]; !holds || p.State == inventory.PlanSuperseded {
continue
}
built++
if p.Commit != fix {
t.Errorf("%s plans the fixed module notes at %s, a commit without the fix %s: %s", p.ID, p.Commit, fix, p.Note)
}
}
if built == 0 {
t.Error("no plan left standing builds notes, the module the later merge fixed")
}
}
+1
View File
@@ -40,3 +40,4 @@
./internal/inventory TestAStoredBuildWithASilentMergeableFileIsStillReadAndComposed ./internal/inventory TestAStoredBuildWithASilentMergeableFileIsStillReadAndComposed
./cmd/mesh-controller TestPlanAndNodeListAnOptionalRequirementLeftUnbound ./cmd/mesh-controller TestPlanAndNodeListAnOptionalRequirementLeftUnbound
./cmd/mesh-controller TestReplay340 ./cmd/mesh-controller TestReplay340
./cmd/mesh-controller TestReplay349