No change to a machine takes effect unseen (hq ADR 0217)

Three guards, each silent when nothing is at stake:
- settings: show reads a layer; set says what it adds, changes and removes, refuses a removal
  without --replace, and keeps the layer it replaced (settings_history, migration 0057).
- push: plan --diff compares with what the machine was last sent, now kept as a summary that holds
  no file content; push with no machine needs --all.
- a running container whose mount would point at another directory holds that machine's push
  until --move names the module; the other machines go ahead.
This commit is contained in:
2026-10-05 15:32:28 +02:00
parent 869fb6d6bf
commit ac42d89391
13 changed files with 946 additions and 28 deletions
+18 -9
View File
@@ -119,8 +119,13 @@ var ControllerVerbs = []Verb{
}, []string{"node", "provision", "from", "module"})},
{Name: "unpin", Description: "Take that choice back, putting the question to the mesh again.",
Input: schema(map[string]string{"node": "the machine's name", "provision": "the provision"}, []string{"node", "provision"})},
{Name: "push", Description: "Send a machine everything it should be — or every machine that is behind, when no machine is named.",
Input: schema(map[string]string{"node": "the machine's name; every machine behind when absent"}, nil)},
{Name: "push", Description: "Send a machine everything it should be — or every machine that is behind, when no machine is named. " +
"A push that would move a running module's data to another directory is held for that machine and says so; " +
"name the module in move to send it.",
Input: schema(map[string]string{
"node": "the machine's name; every machine behind when absent",
"move": "modules whose data may move with this push, comma-separated (optional)",
}, nil)},
{Name: "rotate", Description: "Replace a credential. A pair credential, by provision (and a consuming machine, " +
"else every holder): both ends are re-sent together. Or a module's own secret, by machine, module and " +
"name: made anew and the machine sent, so the module starts again on it — only for a secret its " +
@@ -139,14 +144,18 @@ var ControllerVerbs = []Verb{
"node": "the machine that runs the module",
"module": "the module's name",
}, []string{"node", "module"})},
{Name: "settings", Description: "Set what an assignment is configured with: a module's settings for the whole mesh, " +
"or for one machine. Replaces that layer whole — what it does not name, it no longer sets — and takes effect " +
"at the next push. With clear, removes the layer and the module is back to what its definition says.",
{Name: "settings", Description: "Read or set what an assignment is configured with: a module's settings for the whole mesh, " +
"or for one machine. Without values or clear, answers the layer as it stands — read it before setting it. " +
"Setting replaces that layer whole and says what it adds, changes and removes; a set that would remove a key " +
"is refused unless replace is \"true\". The replaced layer is kept (history). Takes effect at the next push. " +
"With clear, removes the layer and the module is back to what its definition says.",
Input: schema(map[string]string{
"module": "the module's name",
"values": "the settings as a JSON object, for set",
"node": "one machine; the whole mesh when absent",
"clear": "\"true\" to remove the layer instead of setting it",
"module": "the module's name",
"values": "the settings as a JSON object, for set",
"node": "one machine; the whole mesh when absent",
"clear": "\"true\" to remove the layer instead of setting it",
"replace": "\"true\" when the set is meant to remove keys the layer had",
"history": "\"true\", without values: the layers this one replaced, latest first",
}, []string{"module"})},
{Name: "command", Description: "Run one command line of the controller's own, as you would type it at its " +
"shell — `node account g14 jochen`, `node show ace`, `module list` — and answer what it printed. The " +