hub v0.155.0: the floor can never deliver a withdrawn controller build (R-1085); RomM/Ghost evidence
gates / gates (push) Successful in 6m44s
gates / gates (push) Successful in 6m44s
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0159rPz1ZhFKsS53msqPYxtS
This commit is contained in:
@@ -677,6 +677,14 @@ func (h *Handler) handleReport(w http.ResponseWriter, r *http.Request) {
|
||||
h.logger.Printf("[INFO] managed floor SERVED for %s: floor %s, agent requirement %q from %s (golden %s)",
|
||||
payload.CustomerID, fd.Floor, fd.MinAgent, src, fd.GoldenVersion)
|
||||
}
|
||||
} else if fd.HeldSpoiled {
|
||||
// R-1085: a withdrawn build — ONE [WARN] per change naming the tag and why, not one per report.
|
||||
note := "spoiled|" + fd.RequestedFloor
|
||||
if prev, ok := h.floorNotes.Load(payload.CustomerID); !ok || prev.(string) != note {
|
||||
h.floorNotes.Store(payload.CustomerID, note)
|
||||
h.logger.Printf("[WARN] managed floor HELD for %s: %s (controller floor withheld)",
|
||||
payload.CustomerID, fd.HoldReason())
|
||||
}
|
||||
} else if fd.Held {
|
||||
h.floorNotes.Delete(payload.CustomerID)
|
||||
// ONE sentence, from the decision itself — the two hold reasons must never drift apart
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"log"
|
||||
"net/http"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
// R-1085 over the wire — Scenario C through the PRODUCTION path (the real report handler → ResolveManagedFloor):
|
||||
// a box is never told to install a withdrawn build, and the hub says why in ONE [WARN] naming the tag, not one per
|
||||
// report. Red-proof: delete the SpoiledControllerTag block in store.ResolveManagedFloor → the ACK carries 0.316.3.
|
||||
func TestReportACK_NeverServesAWithdrawnBuild(t *testing.T) {
|
||||
h, st, _ := newTestHandler(t)
|
||||
var logs bytes.Buffer
|
||||
h.logger = log.New(&logs, "", 0)
|
||||
ack := func() (interface{}, bool) {
|
||||
rr := do(h, http.MethodPost, "/report", globalKey, `{"customer_id":"c"}`)
|
||||
if rr.Code != http.StatusOK {
|
||||
t.Fatalf("report status = %d", rr.Code)
|
||||
}
|
||||
var m map[string]interface{}
|
||||
_ = json.Unmarshal(rr.Body.Bytes(), &m)
|
||||
v, ok := m["min_controller_version"]
|
||||
return v, ok
|
||||
}
|
||||
|
||||
// A value stored the way an old hub (no form refusal) would have stored it.
|
||||
if err := st.SetGlobalMinControllerVersion("0.316.3"); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
for i := 0; i < 3; i++ {
|
||||
if v, ok := ack(); ok {
|
||||
t.Fatalf("report %d: the ACK must OMIT a withdrawn floor, got %v", i, v)
|
||||
}
|
||||
}
|
||||
if n := strings.Count(logs.String(), "[WARN] managed floor HELD for c:"); n != 1 {
|
||||
t.Errorf("want exactly ONE [WARN] across three reports, got %d:\n%s", n, logs.String())
|
||||
}
|
||||
if !strings.Contains(logs.String(), "0.316.3") || !strings.Contains(logs.String(), "WITHDRAWN") {
|
||||
t.Errorf("the [WARN] must name the tag and say withdrawn:\n%s", logs.String())
|
||||
}
|
||||
|
||||
// The control, on the same handler: an ordinary floor is served.
|
||||
if err := st.SetGlobalMinControllerVersion("0.317.0"); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if v, ok := ack(); !ok || v != "0.317.0" {
|
||||
t.Fatalf("an ordinary floor must be served, got %v (present=%v)", v, ok)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user