package main import ( "reflect" "testing" "time" "github.com/novox/mesh-controller/internal/inventory" ) // novox/hq issue 754: a walk waiting for its delivery's word takes no build's outcome, nor does a walk take one for // a module it never asked; asked under an id, it takes that id's alone. func TestAWalkTakesOnlyTheOutcomesOfWhatItAsked(t *testing.T) { asked := time.Date(2026, 10, 14, 23, 30, 0, 0, time.UTC) before := asked.Add(-time.Minute) waiting := inventory.Plan{Delivery: &inventory.PlanDelivery{Awaits: "mesh-delivery"}} letGo := inventory.Plan{Delivery: &inventory.PlanDelivery{Awaits: "mesh-delivery", Go: &asked}} own := &inventory.PlanModule{State: "asked", AskedAt: &asked, Build: "build-own"} old := &inventory.PlanModule{State: "asked", AskedAt: &asked} for _, c := range []struct { what string p inventory.Plan state *inventory.PlanModule at time.Time id string takes bool }{ {"a rebuild while the walk waits", waiting, nil, asked, "build-rebuild", false}, {"its own id while it waits", waiting, own, asked, "build-own", false}, {"a module it never asked", letGo, nil, asked, "build-rebuild", false}, {"a module it never asked, state kept empty", letGo, &inventory.PlanModule{}, asked, "build-rebuild", false}, {"another id", letGo, own, asked, "build-rebuild", false}, {"its own id", letGo, own, asked, "build-own", true}, {"a plan from before ids, asked after it", letGo, old, asked.Add(time.Second), "x", true}, {"a plan from before ids, asked before it", letGo, old, before, "x", false}, {"a plan with no delivery, its own id", inventory.Plan{}, own, asked, "build-own", true}, } { if got := takesOutcome(c.p, c.state, c.at, c.id); got != c.takes { t.Errorf("%s: takes %v, want %v", c.what, got, c.takes) } } } // novox/hq issue 754: a tier partly asked asks the rest; a module held built that the plan never asked — the live // shape, a hand rebuild taken in during the wait, built after the plan was made — is asked again; one asked is kept. func TestATierPartlyAskedAsksTheRest(t *testing.T) { created := time.Date(2026, 10, 14, 23, 30, 0, 0, time.UTC) earlier, later := created.Add(-time.Hour), created.Add(7*time.Minute) p := inventory.Plan{Created: created, Tiers: [][]string{{"build-agent", "gitea", "route-proxy", "stale", "kept", "own"}}, Modules: map[string]*inventory.PlanModule{ "gitea": {}, "route-proxy": {State: "built", BuiltAt: &later, Commit: "c51357f8"}, "stale": {State: "built", BuiltAt: &earlier}, "kept": {State: "asked", AskedAt: &created, Build: "build-kept"}, "own": {State: "built", AskedAt: &created, BuiltAt: &later, Build: "build-own"}, }} if got, want := unaskedOf(p), []string{"build-agent", "gitea", "route-proxy", "stale"}; !reflect.DeepEqual(got, want) { t.Fatalf("unasked %v, want %v", got, want) } if !askedInTier(p) { t.Fatal("a tier with a module asked under an id reads as never asked") } p.Modules["kept"], p.Modules["own"] = nil, nil if askedInTier(p) { t.Fatal("a tier the plan never asked reads as asked") } } // novox/hq issue 754, as seen on 2026-10-14: a rebuild lands while the walk waits for its word; the walk is let go; // it asks every module of its tier, and completes it once those builds come in.