Merge pull request 'Issue 244: located — the console drops a mesh seat's node, and a push ran on every machine' (#121) from issues/244-located into main

This commit was merged in pull request #121.
This commit is contained in:
2026-10-05 22:55:03 +00:00
2 changed files with 84 additions and 1 deletions
@@ -1,5 +1,5 @@
---
status: open
status: located
opened: 2026-10-05
located-in: [mesh-tools, mesh-controller]
fixed-by:
@@ -60,6 +60,26 @@ and it is wrong.
schema describes — a test that calls each with its schema's required set and asserts the answer
is not "needs" an argument the schema does not have.
## Seen again, 2026-10-05 and 2026-10-06 — and once it did harm
The same picture for more of the mesh's own verbs, read through the console:
```
mesh_describe mesh-controller.push → {"properties": {}}
mesh_describe mesh-controller.plan → {"properties": {}}
mesh_describe mesh-controller.assign → module only, no node
mesh_describe mesh-controller.pin → provision, from, module — no node
mesh_describe mesh-controller.settings → module, values, clear — no node
```
`build` and `queue`, which take no machine, described in full. For `plan` this is the refusal above.
For **`push` it was worse than a refusal**: a push takes no required argument, so a call naming one
machine arrived empty, ran as a push of every machine behind, and answered "N node(s) told" — an
operator who believed they had pushed one machine had pushed the mesh. Nothing in the answer said the
machine had been lost.
The diagnosis is in [`01-diagnosis.md`](01-diagnosis.md).
## Worked around, for now
Through `<node>/node-login-shell.execute`, running the controller's own command line on the
@@ -0,0 +1,63 @@
# Diagnosis
## 2026-10-06
**The schema is not empty where it is kept.** The controller's verb table declares `node` for every
verb that acts on a machine, and so does the seat's record: asked through the console,
`mesh-controller.tools` answers `push`, `plan`, `assign`, `pin` and `settings` each with `node` among
their properties. The controller's announcement on the bus carries the same schemas. So the
controller publishes them whole, and the loss is after it.
**The console takes `node` out of every schema and every call.** The console's address grammar
(ADR 0195) puts the machine in the address for a seat held on every machine (`<node>/<seat>.<verb>`)
and for a module on one machine (`<node>/<module>.<tool>`), and so describes those tools without a
`node` argument and deletes one from their calls. It did both for **every** address — including a
seat held once for the mesh, where there is no machine in the address and `node` is the verb's own
argument: the machine the verb acts on. That is exactly the set observed: each verb lost `node` and
nothing else, `push` and `plan` had nothing else and described as empty, and the verbs that take no
machine (`build`, `queue`) were untouched. The older flat listing of the same console had this right
(it kept a mesh seat's schema as declared); the address form did not carry the distinction over.
**Why the verb then refused, or did the wrong thing.** The controller's verbs read the arguments they
know and ignore the rest. Given nothing, `plan` and `node` said they needed `node`; `push`, whose
`node` is optional, read its absence as "every machine behind" and did that. A verb that ignores what
it does not read cannot tell "nothing was asked" from "something was lost on the way".
**Ruled out.**
- A stale seat record. The record is older than the controller's current source (some verbs lack
arguments added since), but it carries `node` wherever the source does.
- The controller's announcement. It sends the record's schema per verb, unchanged.
**Located in** `mesh-tools` (the console: the schema it describes and the arguments it sends) and
`mesh-controller` (verbs that pass over what they are given).
## What the fix does, and how it is checked
Pull requests: novox/mesh-tools#14 and novox/mesh-controller#71 — open, not merged.
- **The console** takes `node` out only where the address names the machine. There, a `node` naming
the same machine is redundant and dropped; one naming another machine is refused. A call to a seat's
verb carrying an argument the verb does not declare is refused, naming it — the seat's record is the
mesh's own description of the verb, so the console can judge it.
- **The controller** refuses, naming the argument: one the verb does not declare; one it declares but
did not use for the command it composed (two arguments where one wins, or half of a two-argument
shape); a switch that is neither "true" nor "false". A push that names no machine says, as the
first line of its answer, that it is a push of the whole mesh and which machines it is sending, and
its last line names the machines told. `plan` gains `files`, `push` gains `behind` (the whole mesh
said outright, refused beside `node`), and the listing verbs a `limit`.
- **Checked by tests that walk every verb the controller announces:** for every combination of a
verb's declared arguments, the verb either refuses or every argument given changes the command it
runs; every verb refuses an argument it does not declare, and `node` where it takes none; and every
flag of the command a verb runs — read from the command's own source — is an argument of the verb's
schema or is listed, with the reason, as set by the verb or withheld from it. A verb added later,
or a flag added to a command, fails these until its schema says how a caller reaches it.
What the tests do not check is the console's own describe-and-call path against a live bus; its unit
test covers the choice of when `node` is the address's and when it is the verb's.
## Related
Issue 259 is another way a named push reached every machine: there the machine arrived and the
controller's flush after it sent the others. Different cause, same reader's harm — the answer of a
push is the only place that says how far it went, which is why the whole-mesh line is in the answer.