package main import ( "strings" "testing" "time" "github.com/novox/mesh-controller/internal/catalogue" "github.com/novox/mesh-controller/internal/inventory" "github.com/novox/mesh-controller/internal/link" ) // novox/hq issue 296: a plan saved a few seconds ago that has stood in its tier for forty minutes says // forty minutes, and LATE — the line counted from the last save, which every advance made. func TestAPlansLineCountsFromItsTierNotFromItsLastSave(t *testing.T) { now := time.Date(2026, 10, 7, 20, 30, 0, 0, time.UTC) asked := now.Add(-40 * time.Minute) p := inventory.Plan{ID: "plan-t", Repository: "novox/mesh-catalog", Commit: "3ad22356", State: inventory.PlanBuilding, Created: now.Add(-40 * time.Minute), Updated: now.Add(-3 * time.Second), TierEntered: now.Add(-40 * time.Minute), Tiers: [][]string{{"a"}}, Modules: map[string]*inventory.PlanModule{"a": {State: "asked", AskedAt: &asked}}} line := planLine(p, now) if !strings.Contains(line, "building for 40m0s") || !strings.Contains(line, "LATE") { t.Fatalf("a plan in its tier for 40m, saved 3s ago, reads %q", line) } st := planStatuses([]inventory.Plan{p}, now, pauseView{}, nil)[0] if !st.Late || !st.Since.Equal(p.TierEntered) { t.Errorf("status --json says %+v", st) } if _, late := openPlans([]inventory.Plan{p}, now, pauseView{}, nil); late != 1 { t.Errorf("status counted %d late", late) } // LATE is the stalled condition said on the line: the same start and the same bound, measured or not. bounds := boundsOf([]inventory.Duration{{Subject: p.Repository, Took: 20 * time.Minute}}) if got := bounds.of(p.Repository); got != time.Hour { t.Fatalf("a repository whose tiers took 20m is given %s", got) } if got := bounds.of("novox/other"); got != tierAtLeast { t.Fatalf("a repository with nothing measured is given %s", got) } for _, in := range []time.Duration{40 * time.Minute, 70 * time.Minute} { q := p q.TierEntered = now.Add(-in) bound := bounds.of(q.Repository) late := strings.Contains(planLineWith(q, now, pauseView{}, bound), "LATE") stalled := len(watchPlans(&signalFacts{now: now, plans: []planFacts{{id: q.ID, repository: q.Repository, commit: q.Commit, tiers: 1, entered: inTierSince(q), bound: bound}}})) == 1 if late != stalled || late != (in > bound) { t.Errorf("in its tier %s with a bound of %s: LATE %v, stalled %v", in, bound, late, stalled) } } // A plan read without its tier's stamp counts from its last save, the only time it has. old := p old.TierEntered = time.Time{} if line := planLine(old, now); !strings.Contains(line, "for 3s") || strings.Contains(line, "LATE") { t.Errorf("a plan without its tier's stamp reads %q", line) } // A walk that waited for its delivery's word counts its wait from when it was opened, and its tier // from the word. waiting := p waiting.Delivery = &inventory.PlanDelivery{Awaits: catalogue.DeliverySeat} waiting.Modules = map[string]*inventory.PlanModule{} if line := planLine(waiting, now); !strings.Contains(line, "for 40m0s") || strings.Contains(line, "LATE") { t.Errorf("a walk waiting 40m reads %q", line) } if st := planStatuses([]inventory.Plan{waiting}, now, pauseView{}, nil)[0]; st.Late { t.Errorf("a waiting walk is called late: %+v", st) } let := now.Add(-5 * time.Minute) gone := p gone.Delivery = &inventory.PlanDelivery{Awaits: catalogue.DeliverySeat, Go: &let} if line := planLine(gone, now); !strings.Contains(line, "building for 5m0s") || strings.Contains(line, "LATE") { t.Errorf("a walk let go 5m ago, opened 40m ago, reads %q", line) } } // novox/hq issue 296: a plan whose tier stands still is not written again by every advance — its revision, // its last save and its `plan-moved` stay where its last change left them. func TestAPlanStandingStillIsNotSavedAgain(t *testing.T) { open := aMesh(t) ctx := t.Context() inv := open.inventory asked := asksRecorded(t) if err := inv.RegisterModule(ctx, catalogue.Manifest{Module: "app", Version: "1"}, inventory.Source{Repository: "novox/mesh-catalog", Seat: "git", Path: "modules/app", Ref: "main", BuiltFrom: "c0", Head: "c0"}); err != nil { t.Fatal(err) } m := link.SourceMoved{Owner: "novox", Repo: "mesh-catalog", Base: "main", Commit: "c1aaaaaaaa", Paths: []string{"modules/app/index.ts"}, ModuleDirs: []string{"modules/app"}, ModuleDirsSaid: true} if err := (following{open: open}).SourceMoved(ctx, m); err != nil { t.Fatal(err) } advanceHeld(ctx, open) recent, err := inv.RecentPlans(ctx, 1) if err != nil || len(recent) != 1 || len(*asked) != 1 { t.Fatalf("no plan building: %v %v, asked %v", recent, err, *asked) } before := recent[0] if before.State != inventory.PlanBuilding || before.Modules["app"] == nil || before.Modules["app"].State != "asked" { t.Fatalf("the plan is not waiting on its build: %+v", before) } for range 3 { advanceHeld(ctx, open) } after, err := inv.PlanByID(ctx, before.ID) if err != nil { t.Fatal(err) } if after.Revision != before.Revision || !after.Updated.Equal(before.Updated) { t.Fatalf("a plan that did not move was saved again: revision %d → %d, saved %s → %s", before.Revision, after.Revision, before.Updated, after.Updated) } if len(*asked) != 1 { t.Fatalf("advancing asked again: %v", *asked) } }