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",