mesh/merge-gate pass: builds build-agent, mesh-controller, route-proxy → ace, g14, novox, shanks; no bus step; every machine composes with the change as it…
mesh/repo-check pass: its merge-check.sh passed
mesh/delivery-group group feat/health-the-field delivering: 1 of 3 delivered
mesh/delivery held for a person: merged, and the controller opened no walk for it within 10m0s — nothing it holds follows that branch, or the merge was…
A module could say nothing about what ready means for what it runs, so a web application with its port open and its requests hanging passed everything for eleven hours (issue 145). A long-running resource now carries `health` — the image's own check adopted by name, http, tcp, exec, unit or a module's own tool, with its timing — refused near its author when it names a port or an address, an endpoint the module does not declare, a tool it does not serve, a tool check alone, or a timing outside the record's bounds. It is composed with the endpoint as the port this machine published it on, and sent only to a node-engine whose statement says it reads it: an older one would refuse the whole declaration. The engine is granted its own machine's instance of each health tool. `module check` warns of every long-running resource without `health`, counts them for the catalogue, and refuses them from 2026-11-18. A check's findings stay out of a condition's summary. The node-engine's validator is vendored at its Phase B commit, so what is composed is judged by the words the engine takes.
55 lines
2.4 KiB
Go
55 lines
2.4 KiB
Go
package link
|
|
|
|
import (
|
|
"encoding/json"
|
|
"testing"
|
|
)
|
|
|
|
func TestTheWireFormatIsExactlyTheseFieldNames(t *testing.T) {
|
|
// The contract with the host, which defines these separately because it requires nothing
|
|
// present and does not import this. A matching test lives there; rename a field on either
|
|
// side and both fail, rather than the mismatch surfacing on a real machine.
|
|
for _, c := range []struct {
|
|
value any
|
|
expect []string
|
|
}{
|
|
{Signed{Declaration: []byte("{}"), Signature: []byte("x")}, []string{"declaration", "signature"}},
|
|
{Report{Node: "n", Applied: []string{"a"}, Failed: map[string]string{"k": "v"}, Refused: "r"},
|
|
[]string{"node", "applied", "failed", "refused"}},
|
|
{Report{Node: "n", Held: []Held{{ID: "m.f"}}, Firewall: "ufw", Reachable: []Reach{{Port: 1}}},
|
|
[]string{"node", "held", "firewall", "reachable"}},
|
|
{Held{ID: "m.f", Module: "m", Kind: "file", Target: "/f", Changed: "rewritten", Kept: "/k"},
|
|
[]string{"id", "module", "kind", "target", "since", "changed", "kept"}},
|
|
{Reach{Protocol: "tcp", Address: "0.0.0.0", Port: 8080, By: "hello-web", Published: true,
|
|
ContainerPort: 80},
|
|
[]string{"protocol", "address", "port", "by", "published", "container-port"}},
|
|
{EnrolRequest{Node: "n", Secret: "s", PublicKey: []byte("k")},
|
|
[]string{"node", "secret", "public_key"}},
|
|
// novox/hq ADR 0240: every long-running resource's health, in every report and in its own event.
|
|
{Report{Node: "n", Health: &Health{Contract: LivenessContract}}, []string{"node", "health"}},
|
|
{Health{Contract: LivenessContract, Resources: []ResourceHealth{}}, []string{"contract", "at", "resources"}},
|
|
{ResourceHealth{Module: "m", Resource: "m.r", Kind: "container", Target: "t", State: StateUnhealthy,
|
|
Reason: "restarting", Streak: 2, Restarts: 3, Check: "http", Needs: "postgres-database"},
|
|
[]string{"module", "resource", "kind", "target", "state", "reason", "since", "streak", "restarts",
|
|
"check", "needs"}},
|
|
{HealthSaid{Node: "n"}, []string{"node", "health"}},
|
|
} {
|
|
raw, err := json.Marshal(c.value)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
var fields map[string]any
|
|
if err := json.Unmarshal(raw, &fields); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
for _, want := range c.expect {
|
|
if _, ok := fields[want]; !ok {
|
|
t.Errorf("%T has no %q field; the host reads that name", c.value, want)
|
|
}
|
|
}
|
|
if len(fields) != len(c.expect) {
|
|
t.Errorf("%T has %d fields, expected %d: %v", c.value, len(fields), len(c.expect), fields)
|
|
}
|
|
}
|
|
}
|