Each send is numbered, inside the signed bytes
novox/hq 04-ISSUES/107. The controller already held a per-node lock while it composed and recorded each send; the order existed and was thrown away at the wire. Each send now takes the next number for its node, one higher than the last, under that hold and before the body exists — so the number is inside what the mesh signs, and a replayed older declaration cannot borrow a newer one's. Zero is not sent. A host reads absence as "no order claimed", which is the shape of every declaration before this, so nothing that worked before changes for a machine sent nothing since numbering existed. One subtlety, and it is the one that would have read every machine as behind for ever: the mesh decides a machine is behind by comparing the digest of what it WOULD send against what it DID send, and a number changes the bytes. The read-only comparison composes with the number the machine was LAST sent, not a fresh one, so it is byte for byte what was sent when nothing else changed. Hosts went first and every machine runs one that understands the field.
This commit is contained in:
@@ -18,6 +18,10 @@ import (
|
||||
// make a machine look out of date for ever, or send something `plan` never showed.
|
||||
type sendable struct {
|
||||
Resources []map[string]any
|
||||
// Sequence orders this send against every other to the same node: one higher each time, taken
|
||||
// under the node's hold just before the body is made (novox/hq 04-ISSUES/107). Zero is not sent
|
||||
// at all, which a host reads as "no order claimed" — the shape of every declaration before this.
|
||||
Sequence int64
|
||||
// Adoption is nil for a converged node, and then the body is byte for byte what it was before
|
||||
// adoption existed: an older host parses the envelope strictly and would refuse the key.
|
||||
Adoption *adoptionEnvelope
|
||||
@@ -38,6 +42,9 @@ func (s sendable) Body() ([]byte, error) {
|
||||
if s.Adoption != nil {
|
||||
envelope["adoption"] = s.Adoption
|
||||
}
|
||||
if s.Sequence > 0 {
|
||||
envelope["sequence"] = s.Sequence
|
||||
}
|
||||
// An empty declaration is deliberate here — the node owns nothing the mesh put there
|
||||
// (novox/hq issue 127) — and the host refuses an empty body unless it is told the emptiness
|
||||
// is meant, so a truncated or mis-composed body is never mistaken for "own nothing".
|
||||
|
||||
Reference in New Issue
Block a user