No change to a machine takes effect unseen (hq ADR 0217, to-be 44)
mesh/merge-gate pass: builds build-agent, mesh-controller, route-proxy → ace, g14, novox, shanks; no bus step; every machine composes with the change as it…
mesh/repo-check pass: its merge-check.sh passed
mesh/delivery delivered
mesh/delivery-group group feat/no-change-takes-effect-unseen delivered: every member is delivered

Two incidents had one shape: a change took effect that nobody saw first (hq issues 241, 304).
Three guards, each silent when nothing is at stake:

- settings show [--history], and a set that answers each key it adds, changes and removes, and
  refuses a removal unless --replace; the replaced or cleared layer is kept in settings_history,
  in the same transaction as the write (migration 0078).
- every send keeps a summary of what it sent (no file content), plan <node> --diff compares with
  it, and push with no machine is refused unless --all.
- a push that would give a running container's mount another host directory holds that machine,
  naming the module, mount and both directories, until push <node> --move <module>; a named push's
  cascade is held the same way.

Rebased onto main and fitted to it: the hold runs before the push says what it recreates, a whole
push still says so first and leaves machines waiting for a gate, the verb's push with no machine is
still --behind and a push still needs why. The verbs take plan diff, settings replace and history,
and push move beside a machine, each refused where it cannot take effect.
This commit is contained in:
jochen
2026-10-08 01:44:43 +02:00
parent 5ddc59cd32
commit 4499e85476
18 changed files with 1073 additions and 75 deletions
+26 -8
View File
@@ -407,6 +407,10 @@ func (a *verbArguments) commandLine() ([]string, error) {
if on("files") {
return []string{"plan", str("node"), "--files"}, nil
}
// What a push would change there (novox/hq ADR 0217); diff with files is passed over, and so refused.
if on("diff") {
return []string{"plan", str("node"), "--diff"}, nil
}
return []string{"plan", str("node"), "--json"}, nil
case "assign", "unassign":
if err := need("node", "module"); err != nil {
@@ -441,10 +445,16 @@ func (a *verbArguments) commandLine() ([]string, error) {
// behind is not read here: given with a machine, it is refused as passed over — naming
// a machine and asking for every machine behind are two requests, and guessing one
// would push a machine nobody named, or not push one somebody did.
return append([]string{"push", n, "--wait", "0"}, why...), nil
argv := []string{"push", n, "--wait", "0"}
// A running module's data moving is sent only when said, per module (novox/hq ADR 0217).
if m := str("move"); m != "" {
argv = append(argv, "--move", m)
}
return append(argv, why...), nil
}
// No machine: the whole mesh, whether or not behind said so. The command's answer says it
// first, so a caller who meant one machine reads that it was not one.
// first, so a caller who meant one machine reads that it was not one. move is not read: a
// machine whose data would move is held and named, and sent by a push that names it.
on("behind")
return append([]string{"push", "--behind", "--wait", "0"}, why...), nil
case "hand-act":
@@ -672,13 +682,21 @@ func (a *verbArguments) commandLine() ([]string, error) {
return nil, err
}
var argv []string
if on("clear") {
switch {
case on("clear"):
argv = []string{"settings", "clear", str("module")}
} else {
argv = []string{"settings", "set", str("module")}
// Neither values nor clear: the command says its usage, which names both.
if v := str("values"); v != "" {
argv = append(argv, v)
case str("values") != "":
argv = []string{"settings", "set", str("module"), str("values")}
// What a set removes is refused unless meant (novox/hq ADR 0217).
if on("replace") {
argv = append(argv, "--replace")
}
default:
// Neither values nor clear: the layer as it stands, which is what a caller reads before
// replacing it (novox/hq ADR 0217) — and with history, the layers it replaced.
argv = []string{"settings", "show", str("module")}
if on("history") {
argv = append(argv, "--history")
}
}
if n := str("node"); n != "" {