Issue 107: a declaration carries no order; rescue on an enrolled node is reconcile, not apply FILE
Both from the review of the issue-104 fix: a hand-applied file on an enrolled node is recorded as carried and would remove the foundation, and nothing on the wire orders one declaration against another.
This commit is contained in:
@@ -0,0 +1,42 @@
|
||||
---
|
||||
status: located
|
||||
opened: 2026-09-23
|
||||
located-in: [mesh-controller internal/link, mesh-host internal/link]
|
||||
fixed-by:
|
||||
amended-design:
|
||||
---
|
||||
|
||||
# 107 — A declaration carries no order, so a host cannot tell an older one from a newer
|
||||
|
||||
## What was observed
|
||||
|
||||
Reviewing the fix for [issue 104](../104-reconcile-applies-a-stale-declaration-and-refuses-nothing/00-report.md),
|
||||
2026-09-23. A signed declaration carries a vocabulary version, the node it is for, its mode and
|
||||
its resources — and nothing that orders it against another. Its only identity is the digest of
|
||||
its bytes. So a host asked to apply a file can say "this is not the one the mesh last sent"; it
|
||||
cannot say "this is older".
|
||||
|
||||
The same absence reaches the link. The host drains a backlog of declarations and applies the
|
||||
newest it received, but "newest" is decided by arrival within a batch of sixteen and a 750 ms
|
||||
window: a backlog of more than sixteen pushes queued across a `converge`/`adopt` pair, or a slow
|
||||
broker splitting one, applies a declaration the controller had already superseded. Not observed;
|
||||
constructed from the code, and narrow — but a converged declaration applied to a node that has
|
||||
since been returned to adopted is the incident of issue 104 by another door.
|
||||
|
||||
## Why it matters beyond this instance
|
||||
|
||||
Ordering is the one property a declaration needs that its signature does not give it. Every
|
||||
refusal the host can make about staleness today is "not the last", which is both too strict (a
|
||||
legitimately newer file is refused too) and too weak (a replay within a batch is not caught). The
|
||||
controller already holds a per-node lock while it composes and records each send; the order
|
||||
exists there and is thrown away at the wire.
|
||||
|
||||
## Open questions
|
||||
|
||||
- Should the signed declaration carry a per-node `sequence`, assigned under the controller's node
|
||||
hold and persisted with the node, and `supersedes` — the digest of the previous send — so a host
|
||||
refuses anything not strictly newer, on the link and from a file alike?
|
||||
- Should genesis sign its rewritten bundle as sequence zero, so one rule covers the bundle and no
|
||||
separate genesis-digest branch is needed on the host?
|
||||
- Is a sequence enough, or does a mode change deserve its own marker, so a replayed converged
|
||||
declaration is refused by mode as well as by order?
|
||||
Reference in New Issue
Block a user