hub: the held-floor REASON must match the CAUSE (CAMPAIGN-11 follow-on)
gates / gates (push) Successful in 7s
gates / gates (push) Successful in 7s
v0.97.0 introduced a second hold reason and left both surfaces printing the first. The freshly deployed hub logged, for the campaign box: managed floor HELD for c11: agent "0.125.0" < MinAgent 0.113.0 which is FALSE — 0.125.0 is ABOVE 0.113.0. That box is held because its floor sits above the vouched golden, not because of its agent. CLAUDE.md's corollary exactly: when a verdict changes which field it counts from, the alarm text has to change with it, or a true alarm reads as one to dismiss. Both the ACK log line and the Hosts-dashboard HeldReason now come from one ManagedFloorDecision.HoldReason(), and TestResolveManagedFloor_HoldReasonMatchesTheCause pins each reason to its cause.
This commit is contained in:
@@ -1,6 +1,9 @@
|
||||
package store
|
||||
|
||||
import "testing"
|
||||
import (
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
// setHostAgent enrolls a host for customerID and records its agent version (the reality column).
|
||||
func setHostAgent(t *testing.T, s *Store, customerID, hostID, agentVer string) {
|
||||
@@ -180,3 +183,49 @@ func TestResolveManagedFloor_R216_FloorAboveGolden(t *testing.T) {
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// The hold REASON must match the hold CAUSE. This is `CLAUDE.md`'s corollary, and it caught a real
|
||||
// slip in this very session: v0.97.0 added a second hold reason, and for one deploy the live hub
|
||||
// logged `managed floor HELD for c11: agent "0.125.0" < MinAgent 0.113.0` — a comparison that is
|
||||
// FALSE, for a box held because its floor sat above the golden. A true alarm that misdescribes itself
|
||||
// is one the operator learns to dismiss.
|
||||
func TestResolveManagedFloor_HoldReasonMatchesTheCause(t *testing.T) {
|
||||
t.Run("beyond-golden hold names the floor and the golden, not the agent", func(t *testing.T) {
|
||||
s := newTestStore(t)
|
||||
_ = s.SetGlobalMinControllerVersion("0.200.0")
|
||||
_ = s.SetArtifactManifest(ArtifactManifest{GoldenVersion: "0.192.0", MinAgent: "0.113.0"})
|
||||
setHostAgent(t, s, "c11", "c11-36d660", "0.125.0")
|
||||
|
||||
reason := s.ResolveManagedFloor("c11").HoldReason()
|
||||
if strings.Contains(reason, "< MinAgent") {
|
||||
t.Fatalf("the beyond-golden hold claims an agent comparison that is FALSE here (0.125.0 > 0.113.0): %q", reason)
|
||||
}
|
||||
for _, want := range []string{"0.200.0", "0.192.0", "ABOVE"} {
|
||||
if !strings.Contains(reason, want) {
|
||||
t.Errorf("hold reason must name %q; got %q", want, reason)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("below-MinAgent hold still names the agent comparison", func(t *testing.T) {
|
||||
s := newTestStore(t)
|
||||
_ = s.SetGlobalMinControllerVersion("0.113.0")
|
||||
_ = s.SetArtifactManifest(ArtifactManifest{GoldenVersion: "0.113.0", MinAgent: "0.81.0"})
|
||||
setHostAgent(t, s, "c1", "h1", "0.79.0")
|
||||
|
||||
reason := s.ResolveManagedFloor("c1").HoldReason()
|
||||
if !strings.Contains(reason, "0.79.0") || !strings.Contains(reason, "MinAgent 0.81.0") {
|
||||
t.Fatalf("the below-MinAgent hold must name the agent comparison; got %q", reason)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("not held → no reason", func(t *testing.T) {
|
||||
s := newTestStore(t)
|
||||
_ = s.SetGlobalMinControllerVersion("0.113.0")
|
||||
_ = s.SetArtifactManifest(ArtifactManifest{GoldenVersion: "0.113.0", MinAgent: ""})
|
||||
setHostAgent(t, s, "c1", "h1", "0.70.0")
|
||||
if r := s.ResolveManagedFloor("c1").HoldReason(); r != "" {
|
||||
t.Fatalf("a served floor must have no hold reason, got %q", r)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user