From 1b1a94f35b2440b2853d8aa4ba053d29aa873805 Mon Sep 17 00:00:00 2001 From: jochen Date: Thu, 29 Oct 2026 22:52:54 +0100 Subject: [PATCH] Give every alert kind the controller raises its home in the keeper's table, as the lead settled them under the operator's yes, so compare names no kind without one (issue 1952) --- .../cmd/mesh-conditions/homes.go | 123 ++++++++++++++---- .../cmd/mesh-conditions/keeper.go | 6 +- .../cmd/mesh-conditions/keeper_test.go | 18 +++ modules/mesh-conditions/module.json | 2 + 4 files changed, 123 insertions(+), 26 deletions(-) diff --git a/modules/mesh-conditions/cmd/mesh-conditions/homes.go b/modules/mesh-conditions/cmd/mesh-conditions/homes.go index 1f0d378c..a7207c24 100644 --- a/modules/mesh-conditions/cmd/mesh-conditions/homes.go +++ b/modules/mesh-conditions/cmd/mesh-conditions/homes.go @@ -5,10 +5,8 @@ package main // a kind that ends with the controller or that the controller never raises, and the keeper reads it to carry, until the // lease write, the controller's conditions of the kinds that end with it. // -// The rows below are what ADR 0564 decides, by the controller's source of each kind as the live controller says it -// (mesh-controller.conditions, read 2026-10-29). **About twenty-five kinds the controller raises have no home in the -// record** (L4.md, "Missing decision"): they have no row here on purpose, and `compare` names each as "no home decided" -// until the lead's decision adds its row. +// The rows are ADR 0564's and the lead's table of 2026-10-29, by the controller's source of each kind. A kind with no +// row is named by `compare` as "no home decided". // Home is where one condition kind lives. type Home struct { @@ -27,39 +25,116 @@ type Home struct { Replaced bool } -// The kinds' homes, by kind. +// The kinds' homes, by kind: ADR 0564's rows, and the 63 kinds the controller's code raises that the record left without +// one, as the lead settled them under the operator's yes on 2026-10-29 (.work/47-release/kinds-section.html, with the +// lead's three changes: lease-split and image-missing do not end, and the data rows read their readings from disk-load). var Homes = map[string]Home{ // The watchman's watchdogs (clause 4). - "silent": {Source: "S1", Controller: true, Observer: watchman}, - "max-deliveries": {Source: "S9", Controller: true, Observer: watchman}, - "slow-consumer": {Source: "S9", Controller: true, Observer: watchman}, - "tools-silent": {Source: "S11", Controller: true, Observer: watchman}, - "apply-failing": {Source: "S21", Controller: true, Observer: watchman}, - "module-unhealthy": {Source: "health", Controller: true, Observer: watchman}, - "stuck": {Source: "DM", Controller: true, Observer: watchman}, + "silent": {Source: "S1", Controller: true, Observer: watchman}, + "max-deliveries": {Source: "S9", Controller: true, Observer: watchman}, + "slow-consumer": {Source: "S9", Controller: true, Observer: watchman}, + "refused": {Source: "S9", Controller: true, Observer: watchman}, + "connection-closed": {Source: "S9", Controller: true, Observer: watchman}, + "bus-faults-unread": {Source: "S9", Controller: true, Observer: watchman}, + "tools-silent": {Source: "S11", Controller: true, Observer: watchman}, + "apply-failing": {Source: "S21", Controller: true, Observer: watchman}, + "module-unhealthy": {Source: "health", Controller: true, Observer: watchman}, + "stuck": {Source: "DM", Controller: true, Observer: watchman}, + "provider-failing": {Source: "S8", Controller: true, Observer: watchman}, + "provider-silent": {Source: "S8", Controller: true, Observer: watchman}, + "self-check-silent": {Source: "S10", Controller: true, Observer: watchman}, + // From the provision keys in waits (ADR 0570 §7), a setting's wait from the node's own health report. + "needs-operator": {Source: "health", Controller: true, Observer: watchman}, + // From the vault's record of each secret given (ADR 0570 §7). + "secret-given": {Source: "desk", Controller: true, Observer: watchman}, + // The watchman reading each node's own health report key (a4's, mesh-host). + "machine-network": {Source: "node", Controller: true, Observer: watchman}, + "network-rewritten": {Source: "node", Controller: true, Observer: watchman}, + "network-unreachable": {Source: "node", Controller: true, Observer: watchman}, + "machine-units": {Source: "node", Controller: true, Observer: watchman}, + "relogin-needed": {Source: "health", Controller: true, Observer: watchman}, + "directory-used-as-found": {Source: "health", Controller: true, Observer: watchman}, // The self-check's probes (clause 6, the Context's table). - "holder-silent": {Source: "D3", Controller: true, Observer: selfCheck}, - "archives-missing": {Source: "D4", Controller: true, Observer: selfCheck}, - "consumer-wrong": {Source: "D6", Controller: true, Observer: selfCheck}, - "data-unmeasured": {Source: "D13", Controller: true, Observer: selfCheck}, - "agent-can-become-root": {Source: "DA", Controller: true, Observer: selfCheck}, - "root-not-free": {Source: "D-root", Controller: true, Observer: selfCheck}, - "probe-failed": {Source: "doctor", Controller: true, Observer: selfCheck}, + "resolver-wrong": {Source: "D2", Controller: true, Observer: selfCheck}, + "holder-silent": {Source: "D3", Controller: true, Observer: selfCheck}, + "archives-missing": {Source: "D4", Controller: true, Observer: selfCheck}, + "archives-unheld": {Source: "D4", Controller: true, Observer: selfCheck}, + "lease-split": {Source: "D5", Controller: true, Observer: selfCheck}, // a seat held once answers from two holders + "consumer-wrong": {Source: "D6", Controller: true, Observer: selfCheck}, + "consumer-lost": {Source: "D6", Controller: true, Observer: selfCheck}, // and the watchman's S9 + "consumer-behind": {Source: "D6", Controller: true, Observer: selfCheck}, + "stream-wrong": {Source: "D7", Controller: true, Observer: selfCheck}, + "own-address-banned": {Source: "D8", Controller: true, Observer: selfCheck}, + "cleanup-waiting": {Source: "D11", Controller: true, Observer: selfCheck}, // its data half reads disk-load (L7) + "binding-kept": {Source: "D12", Controller: true, Observer: selfCheck}, + "binding-moved": {Source: "D12", Controller: true, Observer: selfCheck}, + "binding-moving": {Source: "D12", Controller: true, Observer: selfCheck}, + "data-unmeasured": {Source: "D13", Controller: true, Observer: selfCheck}, + "data-shrank": {Source: "D13", Controller: true, Observer: selfCheck}, // readings from disk-load (L7) + "empty-replacement": {Source: "D13", Controller: true, Observer: selfCheck}, + "data-held-twice": {Source: "D13", Controller: true, Observer: selfCheck}, + "data-quiet": {Source: "D13", Controller: true, Observer: selfCheck}, + "backup-stale": {Source: "D13", Controller: true, Observer: selfCheck}, + "data-missing": {Source: "D13", Controller: true, Observer: selfCheck}, + "array-degraded": {Source: "D13", Controller: true, Observer: selfCheck}, + "protection-missing": {Source: "D13", Controller: true, Observer: selfCheck}, + "bus-reconnects": {Source: "D15", Controller: true, Observer: selfCheck}, + "bucket-or-log-filling": {Source: "fill", Controller: true, Observer: selfCheck}, + "bucket-or-log-unread": {Source: "fill", Controller: true, Observer: selfCheck}, + "grant-composes-nothing": {Source: "withheld", Controller: true, Observer: selfCheck}, + "watchdogs-silent": {Source: "DW", Controller: true, Observer: selfCheck}, + "core-unhealthy": {Source: "H-bus", Controller: true, Observer: selfCheck}, + "agent-can-become-root": {Source: "DA", Controller: true, Observer: selfCheck}, + "root-not-free": {Source: "D-root", Controller: true, Observer: selfCheck}, + "probe-failed": {Source: "doctor", Controller: true, Observer: selfCheck}, // The healers' own (clause 7, Limits 2). "healer-wanted": {Source: "S15", Controller: true, Observer: healers}, "healers-braked": {Source: "healers", Controller: true, Observer: healers}, + // The assigner's, as its own findings (the bus step, ADR 0565 §9). + "bus-maintenance": {Source: "bus", Controller: true, Observer: assigner}, + "bus-upgrade-failed": {Source: "DB", Controller: true, Observer: assigner}, + // The provisioner's (ADR 0570 §5): its own ask replaces retire-waiting; a declined key stays its finding. + "retire-waiting": {Source: "retire", Controller: true, Observer: provisioner}, + "retire-rejected": {Source: "retire", Controller: true, Observer: provisioner}, + // The router's own: no channel delivered a question. + "asks-undelivered": {Source: "asks", Controller: true, Observer: messenger}, + // The artifact store's seat (L7): an image a want names is missing from the store. Its holder is not built yet, + // so the keeper reads no findings of it until L7 names the module. + "image-missing": {Source: "S25", Controller: true, Observer: artifactStore}, // The kinds that end with the controller and are carried until its lease write (clauses 4, 9). - "controller-deaf": {Source: "S4", Controller: true, Carried: true}, - "lease-lost": {Source: "S12", Controller: true, Carried: true}, + "controller-deaf": {Source: "S4", Controller: true, Carried: true}, + "lease-lost": {Source: "S12", Controller: true, Carried: true}, + "call-hung": {Source: "S7", Controller: true, Carried: true}, + "stale-writer": {Source: "S13", Controller: true, Carried: true}, + "facts-stale": {Source: "S14", Controller: true, Carried: true}, + "status-slow": {Source: "D9", Controller: true, Carried: true}, + "vault-silent": {Source: "send", Controller: true, Carried: true}, + "declaration-files-not-put": {Source: "send", Controller: true, Carried: true}, + "config-not-followed": {Source: "config", Controller: true, Carried: true}, + "assignment-not-made": {Source: "assign", Controller: true, Carried: true}, + "builds-not-laid-out": {Source: "start", Controller: true, Carried: true}, + "sent-builds-not-copied": {Source: "start", Controller: true, Carried: true}, + "fingerprint-not-composed": {Source: "done keys", Controller: true, Carried: true}, + "take-in-not-consumed": {Source: "take-in", Controller: true, Carried: true}, + "take-in-stalled": {Source: "take-in", Controller: true, Carried: true}, + "new-module-waits": {Source: "register", Controller: true, Carried: true}, + "left-out": {Source: "send", Controller: true, Carried: true}, + "declaration-refused": {Source: "D1", Controller: true, Carried: true}, + "unknown-field": {Source: "read", Controller: true, Carried: true}, + "bus-objects-unasserted": {Source: "send", Controller: true, Carried: true}, // The kinds that end, their faults observed otherwise (the Context's table). "core-behind": {Source: "D10", Controller: true, Replaced: true}, } // The observers, as the table names them. const ( - watchman = "mesh-delivery-watchman" - selfCheck = "mesh-self-check" - healers = "mesh-healers" + watchman = "mesh-delivery-watchman" + selfCheck = "mesh-self-check" + healers = "mesh-healers" + assigner = "mesh-delivery-assigner" + provisioner = "mesh-provisioner" + messenger = "messenger" + artifactStore = "mesh-artifact-store" ) // homeOf is the home of a condition's kind, and whether the table has one. diff --git a/modules/mesh-conditions/cmd/mesh-conditions/keeper.go b/modules/mesh-conditions/cmd/mesh-conditions/keeper.go index 802126f0..24908f1d 100644 --- a/modules/mesh-conditions/cmd/mesh-conditions/keeper.go +++ b/modules/mesh-conditions/cmd/mesh-conditions/keeper.go @@ -38,8 +38,10 @@ const ( // HistoryKeptFor is how long a transition is kept (clause 3). const HistoryKeptFor = 90 * 24 * time.Hour -// Observers are the modules whose `findings` the keeper reads (clause 2; ADR 0565 §8 for the assigner's). -var Observers = []string{health.WatchmanModule, health.SelfCheckModule, health.HealersModule, delivery.AssignerModule} +// Observers are the modules whose `findings` the keeper reads (clause 2; ADR 0565 §8 for the assigner's; the lead's +// table of 2026-10-29 for the provisioner's and the router's). The artifact store's holder joins with L7. +var Observers = []string{health.WatchmanModule, health.SelfCheckModule, health.HealersModule, delivery.AssignerModule, + "mesh-provisioner", "messenger"} // The other states it reads, as `.`. const ( diff --git a/modules/mesh-conditions/cmd/mesh-conditions/keeper_test.go b/modules/mesh-conditions/cmd/mesh-conditions/keeper_test.go index cc90e26a..199f90e2 100644 --- a/modules/mesh-conditions/cmd/mesh-conditions/keeper_test.go +++ b/modules/mesh-conditions/cmd/mesh-conditions/keeper_test.go @@ -301,6 +301,24 @@ func TestCompareCountsOnlyWhatBothSidesRaise(t *testing.T) { if cmp.Same != 1 || len(cmp.Differences) != 2 { t.Errorf("compare: %+v", cmp) } + // The lead's table of 2026-10-29: each kind has its home, lease-split and image-missing do not end, and the 20 + // that end are carried. + carried := 0 + for _, h := range Homes { + if h.Carried { + carried++ + } + } + for kind, observer := range map[string]string{"needs-operator": watchman, "machine-network": watchman, "lease-split": selfCheck, + "data-shrank": selfCheck, "bus-upgrade-failed": assigner, "retire-waiting": provisioner, "asks-undelivered": messenger, + "image-missing": artifactStore} { + if h, ok := Homes[kind]; !ok || h.Observer != observer || h.Carried { + t.Errorf("%s's home is %+v", kind, h) + } + } + if len(Homes) != 82 || carried != 20 { // 19 of ADR 0564 and the 63 of the table + t.Errorf("the table holds %d kinds, %d carried", len(Homes), carried) + } if _, err := r.k.TakeOver(nil, "jochen", "now"); err == nil || !strings.Contains(err.Error(), "2 difference") { t.Errorf("take-over while compare differs: %v", err) } diff --git a/modules/mesh-conditions/module.json b/modules/mesh-conditions/module.json index 89354c38..3a8a90a9 100644 --- a/modules/mesh-conditions/module.json +++ b/modules/mesh-conditions/module.json @@ -24,6 +24,8 @@ "mesh-self-check.findings", "mesh-healers.findings", "mesh-delivery-assigner.findings", + "messenger.findings", + "mesh-provisioner.findings", "mesh-healers.attempts", "mesh-controller.conditions", "mesh-controller.lease",