Reconcile: adopt initialization's consolidated HQ as canonical, re-home this session's new work #24
@@ -1,8 +1,9 @@
|
|||||||
---
|
---
|
||||||
status: open
|
status: fixed
|
||||||
opened: 2026-08-29
|
opened: 2026-08-29
|
||||||
located-in: [mesh-host, mesh-control]
|
located-in: [mesh-host, mesh-control]
|
||||||
fixed-by:
|
fixed-by:
|
||||||
|
- "mesh-host: the store records where each resource came from — carried or declared — and each origin removes only its own. Verified in the lab on the exact scenario that caused this: the substrate survived, and a later declaration still removed what it had itself declared."
|
||||||
amended-design:
|
amended-design:
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -55,15 +56,28 @@ So the first node is left in a state no other node is in, and the ordinary path
|
|||||||
- **Special-casing the first node.** [ADR 0004](../../02-DECISIONS/0004-a-node-and-how-it-joins.md)
|
- **Special-casing the first node.** [ADR 0004](../../02-DECISIONS/0004-a-node-and-how-it-joins.md)
|
||||||
is explicit that its specialness lasts two commands, and this would extend it for ever.
|
is explicit that its specialness lasts two commands, and this would extend it for ever.
|
||||||
|
|
||||||
## The shape of an answer, not yet chosen
|
## The fix
|
||||||
|
|
||||||
The store needs to record **where a resource came from** — carried, or declared — and reconcile
|
**The store records where each resource came from** — `carried` or `declared` — and each origin
|
||||||
each against its own source. A declaration would then remove only what the mesh previously
|
removes only its own. A declaration removes what the mesh previously declared and never what the
|
||||||
declared, and the bundle would remain the bundle's business until the mesh is told about it.
|
bundle raised; reconciling the bundle removes what the bundle previously raised and never what the
|
||||||
|
mesh assigned.
|
||||||
|
|
||||||
That leaves a real question behind it: **what happens when the mesh eventually does declare the
|
State written before the field existed reads as `carried`, because everything a host had applied
|
||||||
substrate**, which it must, or the substrate can never be upgraded. Two sources claiming the same
|
at that point came from its bundle — there was no other way to tell it anything. Guessing the
|
||||||
container is the ambiguity this issue is made of, moved rather than removed.
|
other way would have the first upgrade remove the substrate, which is this fault arriving through
|
||||||
|
the change that fixes it.
|
||||||
|
|
||||||
|
**Verified on the scenario that caused it.** A first node raised eleven resources, enrolled, and
|
||||||
|
was sent the same two-resource declaration. Both applied; the store, the broker and the control
|
||||||
|
plane were still running afterwards. A second declaration dropping one resource removed that
|
||||||
|
resource and nothing else, so removal by omission still works — which is the property that had to
|
||||||
|
survive the fix.
|
||||||
|
|
||||||
|
**What remains open** is what happens when the mesh eventually declares the substrate, which it
|
||||||
|
must, or the substrate can never be upgraded. Two sources claiming one container is the ambiguity
|
||||||
|
this issue is made of, narrowed rather than removed: it can no longer happen by accident, and
|
||||||
|
nothing yet says what it means when it happens on purpose.
|
||||||
|
|
||||||
## How it was found
|
## How it was found
|
||||||
|
|
||||||
@@ -73,3 +87,18 @@ this fell out of it.
|
|||||||
|
|
||||||
The declaration was two lines and destroyed a working mesh in under a second, which is worth
|
The declaration was two lines and destroyed a working mesh in under a second, which is worth
|
||||||
holding on to: this is not an edge case reached by trying, it is the first thing that happens.
|
holding on to: this is not an edge case reached by trying, it is the first thing that happens.
|
||||||
|
|
||||||
|
|
||||||
|
## Two more faults found while fixing it
|
||||||
|
|
||||||
|
Both of the same shape, and worth recording because the shape is the point.
|
||||||
|
|
||||||
|
**A report published to an unbound routing key vanishes.** The control plane bound `enrol` and not
|
||||||
|
`report`, so nodes announced what they had applied into a void — the broker accepted each message,
|
||||||
|
found no queue for it, and dropped it. The publisher was told nothing. Reports are now published
|
||||||
|
`mandatory`, so anything unroutable comes back and is said out loud, and the binding covers every
|
||||||
|
key a node may publish.
|
||||||
|
|
||||||
|
**A publish failure was being swallowed.** `publishReport` discarded its error, so a node that
|
||||||
|
could not tell the mesh what it had done looked identical to one that had. That is the fault this
|
||||||
|
repository keeps cataloguing, written by hand into the newest code in it.
|
||||||
|
|||||||
Reference in New Issue
Block a user