Read how a module says each resource is ready, and send it to engines that read it (hq ADR 0240, to-be 48 Phase B)
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 covered: a later merge that contains it was delivered: novox/mesh-controller@4291fee68e95 (merged as a5a132ac into main, walk plan-17913907…
mesh/delivery-group group feat/health-the-field delivered: every member is delivered
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 covered: a later merge that contains it was delivered: novox/mesh-controller@4291fee68e95 (merged as a5a132ac into main, walk plan-17913907…
mesh/delivery-group group feat/health-the-field delivered: every member is delivered
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.
This commit is contained in:
@@ -161,3 +161,36 @@ func TestAReportWithNoHealthRaisesAndKeepsNothing(t *testing.T) {
|
||||
t.Fatalf("the report's health was not kept: %+v %v %v", kept, had, err)
|
||||
}
|
||||
}
|
||||
|
||||
// A declared `health` is sent only to an engine whose own statement says it reads it (novox/hq ADR 0240
|
||||
// Phase B): an older engine is strict and would refuse the whole declaration for the field.
|
||||
func TestHealthIsSentOnlyToAnEngineThatSaysItReadsIt(t *testing.T) {
|
||||
open := aMesh(t)
|
||||
ctx := t.Context()
|
||||
inv := open.inventory
|
||||
reads := func() bool {
|
||||
t.Helper()
|
||||
got, err := engineReadsHealth(ctx, inv, "anchor")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
return got
|
||||
}
|
||||
if reads() {
|
||||
t.Fatal("an engine that never stated anything is sent health")
|
||||
}
|
||||
if err := stateHealth(ctx, inv, nil, "anchor", aStatement(h0, link.StateHealthy), h0); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if reads() {
|
||||
t.Fatal("an engine judging liveness alone is sent health")
|
||||
}
|
||||
later := aStatement(h0.Add(time.Minute), link.StateHealthy)
|
||||
later.Contract = link.ReadinessContract
|
||||
if err := stateHealth(ctx, inv, nil, "anchor", later, h0.Add(time.Minute)); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !reads() {
|
||||
t.Fatal("an engine that reads health is not sent it")
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user