Check that the catalogue holds no module mesh-delivery but through the names its handover needs, and say how the seat passes (issue 1351)

This commit is contained in:
2026-10-20 00:59:36 +00:00
parent d16fa1e052
commit 3b03c220ad
2 changed files with 88 additions and 0 deletions
+19
View File
@@ -19,3 +19,22 @@ module and the backup's words, and the pull request's comment shows it. The hold
of such a delivery asks the controller (`delivery-backups-again`) to take the backups again and the delivery goes on
delivering; a record from before the controller cleared the failure does not hold it again. A held delivery already
ends as covered or delivered when a later merge covers it.
## Taking the seat over from today's module
The gate claims the seat `mesh-delivery` beside the module `mesh-delivery`, which the catalogue no longer holds. The controller
keeps a module that is assigned (it refuses to forget it), so the running module goes by a handover of verbs after the merge,
never by hand on a machine (novox/hq ADR 0449 §4, ADR 0450 §6):
1. assign `mesh-delivery-gate` to the machine that holds the seat (`mesh-controller.assign`);
2. check that `mesh-controller.seats` still names `mesh-delivery`, held by the running module;
3. unassign `mesh-delivery` from that machine (`mesh-controller.unassign`) and push it (`mesh-controller.push`);
4. the seat passes: the gate reads the controller's assignments and the node-engine's have keys, finds the module on no machine,
carries its deliveries, groups and pull keys over once (the key `carried` in its `deliveries` says it did), reads the controller's
walks and the forge's open pull requests, and acts.
Until then the gate is silent: it takes no event, writes no key, asks nothing and answers no verb but `delivery_status`, which
says why (`holds-the-seat`, `seat-waits`).
The catalogue holds the names of the old module that the handover needs, and no others: the three buckets the gate carries
over, and the event the issue tracker and the tool runner hear until the module is forgotten (`catalogue_test.go`).
@@ -0,0 +1,69 @@
package main
import (
"encoding/json"
"os"
"path/filepath"
"slices"
"strings"
"testing"
)
// **Today's module is gone from the catalogue** (novox/hq ADR 0437 §1, issue 1351; how it is checked): no `modules/mesh-delivery`
// is held, no manifest declares the module `mesh-delivery`, and no manifest names the module in what it reads, hears or
// calls but through the seat's name (`mesh-delivery` as a seat or a repository, `seat:mesh-delivery.<verb>`) and through
// the names below, each of which stays until today's module is forgotten by the controller, because it is the only way to
// reach what that module left: the three buckets the gate carries over (ADR 0450 §6) and the event the trackers hear
// (issue 1350). Removing the module from the catalogue does not stop the running module: the controller keeps it until it is
// unassigned (mesh-controller upgrades.go retireDeleted), and the handover follows the merge by verbs.
var oldModuleNames = map[string][]string{
"mesh-delivery-gate": {"mesh-delivery.deliveries", "mesh-delivery.groups", "mesh-delivery.pulls"},
"mesh-issues": {"mesh-delivery.transition"},
}
func TestTheCatalogueHoldsNoModuleMeshDeliveryButThroughTheNamesItsHandoverNeeds(t *testing.T) {
modules := filepath.Join("..", "..", "..")
if _, err := os.Stat(filepath.Join(modules, "mesh-delivery")); err == nil {
t.Fatal("modules/mesh-delivery is still in the catalogue: its code is the gate's now")
}
dirs, err := os.ReadDir(modules)
if err != nil {
t.Fatal(err)
}
read := 0
for _, dir := range dirs {
raw, err := os.ReadFile(filepath.Join(modules, dir.Name(), "module.json"))
if err != nil {
continue
}
read++
var manifest any
if err := json.Unmarshal(raw, &manifest); err != nil {
t.Fatalf("%s: %v", dir.Name(), err)
}
if m, _ := manifest.(map[string]any); m["module"] == "mesh-delivery" {
t.Errorf("%s declares the module mesh-delivery", dir.Name())
}
var walk func(v any)
walk = func(v any) {
switch x := v.(type) {
case string:
if strings.HasPrefix(x, "mesh-delivery.") && !slices.Contains(oldModuleNames[dir.Name()], x) {
t.Errorf("%s names the module mesh-delivery in %q: through the seat, or the gate's name", dir.Name(), x)
}
case []any:
for _, e := range x {
walk(e)
}
case map[string]any:
for _, e := range x {
walk(e)
}
}
}
walk(manifest)
}
if read < 20 {
t.Fatalf("only %d manifests were read: the catalogue is not where the test looks", read)
}
}