diff --git a/cmd/mesh-controller/sendable.go b/cmd/mesh-controller/sendable.go index 8c282ac..fdebf7e 100644 --- a/cmd/mesh-controller/sendable.go +++ b/cmd/mesh-controller/sendable.go @@ -38,6 +38,12 @@ func (s sendable) Body() ([]byte, error) { if s.Adoption != nil { envelope["adoption"] = s.Adoption } + // An empty declaration is deliberate here — the node owns nothing the mesh put there + // (novox/hq issue 127) — and the host refuses an empty body unless it is told the emptiness + // is meant, so a truncated or mis-composed body is never mistaken for "own nothing". + if len(s.Resources) == 0 { + envelope["owns_nothing"] = true + } return json.Marshal(envelope) } diff --git a/cmd/mesh-controller/sendable_test.go b/cmd/mesh-controller/sendable_test.go index f831e34..73ce86c 100644 --- a/cmd/mesh-controller/sendable_test.go +++ b/cmd/mesh-controller/sendable_test.go @@ -355,3 +355,25 @@ func TestTheMachineSideOfAMappingIsMovedEverywhereTheNumberIsUsed(t *testing.T) t.Fatalf("the consumer is told the forge answers on %v", told) } } + +func TestAnEmptyDeclarationSaysOwnsNothing(t *testing.T) { + // The host refuses an empty body unless told the emptiness is meant (novox/hq issue 127). + body, err := sendable{}.Body() + if err != nil { + t.Fatal(err) + } + var env map[string]any + if err := json.Unmarshal(body, &env); err != nil { + t.Fatal(err) + } + if env["owns_nothing"] != true { + t.Fatalf("an empty declaration must mark owns_nothing; got %v", env) + } + // A declaration with resources does not carry the marker. + body, _ = sendable{Resources: []map[string]any{{"id": "x"}}}.Body() + var env2 map[string]any + _ = json.Unmarshal(body, &env2) + if _, present := env2["owns_nothing"]; present { + t.Fatalf("a non-empty declaration must not mark owns_nothing; got %v", env) + } +}