From b62bb158398d7ce672ab3aaed984ae008e684ae8 Mon Sep 17 00:00:00 2001 From: jochen Date: Wed, 14 Oct 2026 03:21:53 +0200 Subject: [PATCH 1/2] Say which provision five consumers' checks exercise, so a database down is one condition (hq issue 145) gitea, nextcloud, umami and n8n gain an http check that reaches their database through their own endpoint; mesh-knowledge's watch already asks the database and now names it. While postgres is unhealthy, their findings are held under its condition instead of raising one each. --- health-undeclared | 2 +- modules/gitea/module.json | 7 +++++++ .../mesh-knowledge/cmd/mesh-knowledge/manifest_test.go | 6 ++++++ modules/mesh-knowledge/module.json | 1 + modules/n8n/module.json | 7 +++++++ modules/nextcloud/module.json | 8 ++++++++ modules/umami/module.json | 8 ++++++++ 7 files changed, 38 insertions(+), 1 deletion(-) diff --git a/health-undeclared b/health-undeclared index 1723e8c2..29ac652b 100644 --- a/health-undeclared +++ b/health-undeclared @@ -1,4 +1,4 @@ -66 +62 The long-running resources of this catalogue that do not say how they are ready (`health`, novox/hq ADR 0240 rule 8), as `module check` counts them. It may only go down: merge-check.sh fails a change that raises it, and one that lowers it writes the new number on the first line. From 2026-11-18, or once it is 0, a long-running diff --git a/modules/gitea/module.json b/modules/gitea/module.json index 5f751f90..c97134a5 100644 --- a/modules/gitea/module.json +++ b/modules/gitea/module.json @@ -149,6 +149,13 @@ { "id": "server", "type": "container", + "health": { + "kind": "http", + "endpoint": "web", + "path": "/api/healthz", + "status": 200, + "needs": "postgres-database" + }, "name": "gitea", "image": "gitea/gitea@sha256:87a67ee09d3ae0d1df5fda5dcda3e2a1f9236a45b0a59025d6e00e46adc43bef", "env": { diff --git a/modules/mesh-knowledge/cmd/mesh-knowledge/manifest_test.go b/modules/mesh-knowledge/cmd/mesh-knowledge/manifest_test.go index d9d5b069..6f09d217 100644 --- a/modules/mesh-knowledge/cmd/mesh-knowledge/manifest_test.go +++ b/modules/mesh-knowledge/cmd/mesh-knowledge/manifest_test.go @@ -121,6 +121,12 @@ func TestItsProcessesAreThePreparationTheActAndTheJudge(t *testing.T) { !reflect.DeepEqual(m.Tools, []string{HealthTool, HighestTool}) { t.Fatalf("watch %v, tools %v", watch, m.Tools) } + // The watch's verdict is whether the database serves, so its check names the provision it exercises: while the + // database's provider is unhealthy, this finding is held under the provider's condition (hq ADR 0240 rule 5, + // issue 145). + if h["needs"] != "postgres-database" { + t.Fatalf("watch's check needs %v; it exercises postgres-database", h["needs"]) + } if watch["env"].(map[string]any)["MESH_KNOWLEDGE_STATUS"] != m.Build.Artifacts[0].Env["MESH_KNOWLEDGE_STATUS"] { t.Fatal("watch writes another status file than the health tool reads") } diff --git a/modules/mesh-knowledge/module.json b/modules/mesh-knowledge/module.json index dbb08b00..6b914427 100644 --- a/modules/mesh-knowledge/module.json +++ b/modules/mesh-knowledge/module.json @@ -156,6 +156,7 @@ "health": { "kind": "tool", "tool": "knowledge_health", + "needs": "postgres-database", "interval": "60s", "timeout": "10s", "looks": 2, diff --git a/modules/n8n/module.json b/modules/n8n/module.json index 7666572a..8e89145f 100644 --- a/modules/n8n/module.json +++ b/modules/n8n/module.json @@ -97,6 +97,13 @@ { "id": "server", "type": "container", + "health": { + "kind": "http", + "endpoint": "web", + "path": "/healthz/readiness", + "status": 200, + "needs": "postgres-database" + }, "name": "n8n", "artifact": "server", "network": "n8n", diff --git a/modules/nextcloud/module.json b/modules/nextcloud/module.json index 4d648e01..2d40594c 100644 --- a/modules/nextcloud/module.json +++ b/modules/nextcloud/module.json @@ -83,6 +83,14 @@ { "id": "server", "type": "container", + "health": { + "kind": "http", + "endpoint": "web", + "path": "/status.php", + "status": 200, + "body": "\"installed\":true", + "needs": "postgres-database" + }, "name": "nextcloud", "image": "nextcloud@sha256:fb966733647ea03f0446b0c22eac9733c8eb616d37b960caca9d4c3010e14a08", "env-file": [ diff --git a/modules/umami/module.json b/modules/umami/module.json index 48cbe619..2e6895ea 100644 --- a/modules/umami/module.json +++ b/modules/umami/module.json @@ -89,6 +89,14 @@ { "id": "server", "type": "container", + "health": { + "kind": "http", + "endpoint": "web", + "path": "/api/share/mesh-health", + "status": 404, + "timeout": "10s", + "needs": "postgres-database" + }, "name": "umami", "image": "ghcr.io/umami-software/umami@sha256:85909afc45bdcda1917394594a087421fdbb05610fded0fa9f6fb861abb2f367", "network": "umami", From 2bb5d344f6f1c05936172eaff5157f9740d6ba96 Mon Sep 17 00:00:00 2001 From: jochen Date: Wed, 14 Oct 2026 07:07:11 +0200 Subject: [PATCH 2/2] Hold umami's check to the share route's own 404, so an unknown route cannot pass it (hq issue 145, review 262) Any route umami does not serve answers 404 too, as an HTML page. The share route answers JSON with code not-found only after the database was asked; with the database down it answers 500. --- modules/umami/module.json | 1 + 1 file changed, 1 insertion(+) diff --git a/modules/umami/module.json b/modules/umami/module.json index 2e6895ea..d44da3cc 100644 --- a/modules/umami/module.json +++ b/modules/umami/module.json @@ -94,6 +94,7 @@ "endpoint": "web", "path": "/api/share/mesh-health", "status": 404, + "body": "\"code\":\"not-found\"", "timeout": "10s", "needs": "postgres-database" },