Rename mesh-control -> mesh-controller, substrate -> foundation

One name per thing, per the HQ glossary: the module/container/image/binary/repo
becomes mesh-controller, the seat the-controller, and the store+broker pair the
foundation (embedded base bundles, default template and example lock renamed with
their go:embed directives). No behaviour change — a pure vocabulary rename.

Claude-Session: https://claude.ai/code/session_01D6qtiYU3P9jk3pnAXyAFyx
This commit is contained in:
2026-09-16 18:40:40 +02:00
parent 366840fc0d
commit c3b88b9148
77 changed files with 157 additions and 157 deletions
+141
View File
@@ -0,0 +1,141 @@
package main
import (
"encoding/json"
"strings"
"testing"
"time"
"github.com/novox/mesh-controller/internal/inventory"
)
// The shape something other than a person reads.
//
// Hard to change once anything is built against it, so it stays close to what the domain already
// calls things and carries no summary field that would have to be kept true.
func statusOf(t *testing.T, wrong []inventory.Doing, nodes, quiet []inventory.Node,
behind map[string][]string, sources map[string]inventory.Source) map[string]any {
t.Helper()
body, err := statusAsJSON(answers{
wrong: wrong, nodes: nodes, quiet: quiet, behind: behind, sources: sources})
if err != nil {
t.Fatal(err)
}
var parsed map[string]any
if err := json.Unmarshal(body, &parsed); err != nil {
t.Fatalf("what a board would read is not JSON: %v", err)
}
return parsed
}
func TestRefusedAndFailedStayDistinctAllTheWayOut(t *testing.T) {
// They are fixed in different places, so one word for both would send half the readers of a
// page to the wrong one.
got := statusOf(t,
[]inventory.Doing{
{Node: "one", Outcome: inventory.OutcomeRefused, Refused: "a file needs a path"},
{Node: "two", Outcome: inventory.OutcomeFailed, Applied: 3,
Failed: []inventory.FailedResource{{ID: "shell.pkg", Error: "target not found"}}},
},
[]inventory.Node{{Name: "one"}, {Name: "two"}}, nil, nil, nil)
wrong, _ := got["wrong"].([]any)
if len(wrong) != 2 {
t.Fatalf("got %v", got["wrong"])
}
first, _ := wrong[0].(map[string]any)
if first["outcome"] != inventory.OutcomeRefused || first["refused"] == nil {
t.Fatalf("a refusal did not survive: %v", first)
}
second, _ := wrong[1].(map[string]any)
if second["outcome"] != inventory.OutcomeFailed {
t.Fatalf("a failure did not survive: %v", second)
}
if second["applied"] != float64(3) {
// "Three of eight" and "none of eight" are different machines.
t.Fatalf("what did apply was not carried: %v", second)
}
}
func TestAMachineThatNeverSpokeSaysSoByOmission(t *testing.T) {
// Never heard from and quiet for a while are different situations, and a zero time would read
// as a date in 1970 on any page that formatted it.
got := statusOf(t, nil,
[]inventory.Node{{Name: "silent"}, {Name: "away", LastSeen: time.Now().Add(-3 * time.Hour)}},
[]inventory.Node{{Name: "silent"}, {Name: "away", LastSeen: time.Now().Add(-3 * time.Hour)}},
nil, nil)
quiet, _ := got["quiet"].([]any)
if len(quiet) != 2 {
t.Fatalf("got %v", got["quiet"])
}
never, _ := quiet[0].(map[string]any)
if _, said := never["lastSeen"]; said {
t.Fatalf("a machine that never spoke carries a time: %v", never)
}
away, _ := quiet[1].(map[string]any)
if _, said := away["lastSeen"]; !said {
t.Fatalf("a machine that has been quiet carries no time: %v", away)
}
}
func TestNothingWrongIsAnEmptyListRatherThanNothing(t *testing.T) {
// A page distinguishing "no machines are wrong" from "this field is missing" would have to
// handle both, and null is the one that gets forgotten.
got := statusOf(t, nil, []inventory.Node{{Name: "a", LastSeen: time.Now()}}, nil, nil, nil)
for _, key := range []string{"wrong", "quiet", "behind"} {
list, ok := got[key].([]any)
if !ok {
t.Fatalf("%q is %T, not a list", key, got[key])
}
if len(list) != 0 {
t.Fatalf("%q is not empty: %v", key, list)
}
}
// And how many machines there are, so a reader can tell "none wrong" from "none at all".
if got["machines"] != float64(1) {
t.Fatalf("got %v", got["machines"])
}
}
func TestWhatIsBehindNamesTheMachinesRunningTheOldOne(t *testing.T) {
// A module being out of date is a fact about the catalogue; machines running the old one is
// the thing with consequences.
got := statusOf(t, nil, nil, nil,
map[string][]string{"shell": {"workstation", "laptop"}},
map[string]inventory.Source{"shell": {BuiltFrom: "aaaaaaa1", Head: "bbbbbbb2"}})
behind, _ := got["behind"].([]any)
if len(behind) != 1 {
t.Fatalf("got %v", got["behind"])
}
row, _ := behind[0].(map[string]any)
if row["module"] != "shell" || row["builtFrom"] != "aaaaaaa1" || row["head"] != "bbbbbbb2" {
t.Fatalf("got %v", row)
}
on, _ := row["on"].([]any)
if len(on) != 2 {
t.Fatalf("the machines running the old one are not named: %v", row)
}
}
func TestNoSecretIsInWhatABoardReads(t *testing.T) {
// Everything here comes from the mesh's own records, which hold no readable secret — but a
// shape a page is built against is exactly where one would eventually be added for
// convenience, so this says it out loud.
body, err := statusAsJSON(answers{
wrong: []inventory.Doing{{Node: "a", Outcome: inventory.OutcomeRefused,
Refused: "resource \"x\": a file needs a path"}},
nodes: []inventory.Node{{Name: "a"}},
refused: map[string]string{"a": "nothing provides \"database\", wanted by web"},
})
if err != nil {
t.Fatal(err)
}
for _, word := range []string{"password", "secret", "sealed", "credential", "token"} {
if strings.Contains(strings.ToLower(string(body)), word) {
t.Fatalf("what a board reads carries a %q field:\n%s", word, body)
}
}
}