Node-engine: the value version comes from mesh-sdk go/keys, not go/delivery (H-2, ADR 0634 §1, §4; issue 1966)

Claude-Session: https://claude.ai/code/session_01NcbgfFSnn24M3GcqttoU7i
This commit is contained in:
2026-11-05 14:59:39 +01:00
parent cdd428a7d8
commit 0871fa7cc4
6 changed files with 23 additions and 18 deletions
+2 -1
View File
@@ -2,6 +2,7 @@ package frombus
import (
"fmt"
sdkkeys "git.novox.be/novox/mesh-sdk/go/keys"
"sort"
"strconv"
@@ -27,7 +28,7 @@ func Export(in compose.Input, node string) (delivery.Placement, error) {
}
// At the version a placement key is read at, with a list of modules even when none is placed: the export is the
// seed's value, and the reader refuses a value of version 0 or without its modules.
p := delivery.Placement{V: delivery.Version, Node: node, Modules: []delivery.PlacedModule{}, Decided: delivery.NodeDecided{
p := delivery.Placement{V: sdkkeys.Version, Node: node, Modules: []delivery.PlacedModule{}, Decided: delivery.NodeDecided{
Endpoint: n.Place.Endpoint, Site: n.Place.Site, Hub: n.Place.Hub, Address: n.Place.Address,
PublicDomain: n.PublicDomain, Account: n.Account, AccountHome: n.AccountHome, AgentAccount: n.AgentAccount,
AgentHome: n.AgentAccountHome, Adopted: n.Adopted, Taken: n.Taken}}
+2 -2
View File
@@ -7,6 +7,7 @@ import (
"encoding/json"
"errors"
"fmt"
sdkkeys "git.novox.be/novox/mesh-sdk/go/keys"
"sort"
"strconv"
"strings"
@@ -17,7 +18,6 @@ import (
occ "git.novox.be/novox/mesh-contracts/operator-and-conversation/go/clients/operatorchannelclient"
oc "git.novox.be/novox/mesh-contracts/operator-and-conversation/go/seats/operatorchannel"
stdio "git.novox.be/novox/mesh-sdk/go"
"git.novox.be/novox/mesh-sdk/go/delivery"
)
// The node seat node-engine's acts (novox/hq ADR 0563).
@@ -273,7 +273,7 @@ func (h *HandActs) Call(c EngineCall) (any, error) {
return nil, errors.New("this engine states no manifest reads yet: its node agent has not started")
}
reads, at := h.ManifestReads()
return nodeengine.ManifestReadsAnswer{V: delivery.Version, Node: h.Node, ManifestReads: reads,
return nodeengine.ManifestReadsAnswer{V: sdkkeys.Version, Node: h.Node, ManifestReads: reads,
StatedAt: at.UTC().Format(time.RFC3339Nano)}, nil
case "acts":
if id := arg("id"); id != "" {
+5 -4
View File
@@ -5,6 +5,7 @@ import (
"encoding/json"
"errors"
"fmt"
sdkkeys "git.novox.be/novox/mesh-sdk/go/keys"
"github.com/novox/mesh-host/internal/compositions"
"sort"
"strings"
@@ -205,7 +206,7 @@ func resourceWords(r ResourceHealth) string {
// nodeFacts is the node's own facts of a report, each as the JSON the report carries it in.
func nodeFacts(r Report) delivery.HaveNode {
n := delivery.HaveNode{V: delivery.Version}
n := delivery.HaveNode{V: sdkkeys.Version}
carry := func(into *json.RawMessage, empty bool, v any) {
if empty {
return
@@ -375,7 +376,7 @@ func (q *Session) writeHaves(ctx context.Context, bus Bus) {
sort.Strings(modules)
for _, module := range modules {
f := s.modules[module]
h := delivery.Have{V: delivery.Version, FP: f.FP, Composed: f.Composed, Build: f.Build,
h := delivery.Have{V: sdkkeys.Version, FP: f.FP, Composed: f.Composed, Build: f.Build,
Phase: delivery.PhaseRunning, Health: delivery.HealthUnknown, Detail: f.Detail}
h.Kept = f.Kept
if delivery.Phase(f.Phase) == delivery.PhaseWaitingYes {
@@ -507,7 +508,7 @@ func (q *Session) writeRemoved(ctx context.Context, b HaveBucket, node string) b
delete(s.removed, module)
continue
}
h := delivery.Have{V: delivery.Version, Build: s.removed[module], Phase: delivery.PhaseRemoved,
h := delivery.Have{V: sdkkeys.Version, Build: s.removed[module], Phase: delivery.PhaseRemoved,
Health: delivery.HealthUnknown, Detail: "the applied declaration no longer holds the module"}
raw, err := delivery.EncodeHave(h)
if err != nil {
@@ -730,7 +731,7 @@ func (q *Session) NoteNode(ctx context.Context, composed string, sealed composit
s.nodeComposed = composed
s.nodeSealed = sealed
if s.node == nil {
n := delivery.HaveNode{V: delivery.Version}
n := delivery.HaveNode{V: sdkkeys.Version}
s.node = &n
}
s.mu.Unlock()
+10 -9
View File
@@ -5,6 +5,7 @@ import (
"encoding/json"
"errors"
"fmt"
sdkkeys "git.novox.be/novox/mesh-sdk/go/keys"
"github.com/novox/mesh-host/internal/compositions"
"slices"
"strings"
@@ -178,8 +179,8 @@ func TestAnAppliedModuleIsWrittenRunningAndAFailedOneFailed(t *testing.T) {
// 1132/AC5: a have equal to the bucket's value is not written; a different one is written over the last revision.
func TestAHaveIsWrittenOnlyWhenItDiffers(t *testing.T) {
l := newHaveLink()
l.put(t, "n1.a", delivery.Have{V: delivery.Version, Build: "b-1", Phase: delivery.PhaseRunning, Health: delivery.HealthOK})
l.put(t, "n1.b", delivery.Have{V: delivery.Version, Build: "b-0", Phase: delivery.PhaseRunning, Health: delivery.HealthOK})
l.put(t, "n1.a", delivery.Have{V: sdkkeys.Version, Build: "b-1", Phase: delivery.PhaseRunning, Health: delivery.HealthOK})
l.put(t, "n1.b", delivery.Have{V: sdkkeys.Version, Build: "b-0", Phase: delivery.PhaseRunning, Health: delivery.HealthOK})
q, _ := aHaveQueue(l)
q.SayFacts(context.Background(), appliedModules())
if l.kv["n1.a"].rev != 1 {
@@ -258,7 +259,7 @@ func TestTheNodeKeyCarriesTheNodesFacts(t *testing.T) {
t.Fatal(err)
}
enc := func(v any) json.RawMessage { b, _ := json.Marshal(v); return b }
want := delivery.HaveNode{V: delivery.Version, Windows: enc(rep.Windows), Busy: enc(rep.Busy), Strays: enc(rep.Strays),
want := delivery.HaveNode{V: sdkkeys.Version, Windows: enc(rep.Windows), Busy: enc(rep.Busy), Strays: enc(rep.Strays),
Filters: enc(rep.Filters), Profile: enc(rep.Profile)}
if !delivery.SameHaveNode(got, want) {
t.Errorf("the node key holds %+v, want %+v", got, want)
@@ -280,7 +281,7 @@ func TestTheNodeKeyCarriesTheNodesFacts(t *testing.T) {
if got, err = delivery.DecodeHaveNode(l.kv["n1.node"].value); err != nil || got.Record == nil {
t.Fatalf("the node key holds no record: %+v, %v", got, err)
}
wantRecord := delivery.NodeRecord{V: delivery.Version, Node: "n1", TunnelKey: "tk", SealingKey: "sk", ServingKey: "pk",
wantRecord := delivery.NodeRecord{V: sdkkeys.Version, Node: "n1", TunnelKey: "tk", SealingKey: "sk", ServingKey: "pk",
Certificate: "cert", Trusts: keys.Trusts, Capabilities: []string{"apt", "bus-state-calls", "ledger-calls", "systemd"}, OutwardLinks: []string{"eth0"}, NetworksSaid: true,
Networks: []catalogue.AttachedNetwork{{Link: "eth0", Network: "192.0.2.0/24"}}, Contract: NodeKeyContract,
ManifestReads: catalogue.ManifestReads()} // what it reads of a manifest: its contract's (ADR 0614 §4)
@@ -460,7 +461,7 @@ func TestARemovedModuleAddedBackIsWrittenWithItsNewPhase(t *testing.T) {
// bucket is not created again.
func TestAModuleNeverWrittenIsNotWrittenRemoved(t *testing.T) {
l := newHaveLink()
l.put(t, "n1.c", delivery.Have{V: delivery.Version, Build: "b-9", Phase: delivery.PhaseRunning, Health: delivery.HealthOK})
l.put(t, "n1.c", delivery.Have{V: sdkkeys.Version, Build: "b-9", Phase: delivery.PhaseRunning, Health: delivery.HealthOK})
q, _ := aHaveQueue(l)
q.SayFacts(context.Background(), appliedModules())
q.SayFacts(context.Background(), onlyA())
@@ -502,8 +503,8 @@ func TestARefusedRemovalIsWrittenByTheNextPass(t *testing.T) {
// before: one of them the new declaration lacks is written removed, one that is not in the bucket is not created.
func TestARestartedNodeEngineWritesTheRemovalFromTheReportsBefore(t *testing.T) {
l := newHaveLink()
l.put(t, "n1.a", delivery.Have{V: delivery.Version, Build: "b-1", Phase: delivery.PhaseRunning, Health: delivery.HealthOK})
l.put(t, "n1.b", delivery.Have{V: delivery.Version, Build: "b-2", Phase: delivery.PhaseRunning, Health: delivery.HealthOK})
l.put(t, "n1.a", delivery.Have{V: sdkkeys.Version, Build: "b-1", Phase: delivery.PhaseRunning, Health: delivery.HealthOK})
l.put(t, "n1.b", delivery.Have{V: sdkkeys.Version, Build: "b-2", Phase: delivery.PhaseRunning, Health: delivery.HealthOK})
q, _ := aHaveQueue(l) // fresh: nothing written by this process
r := onlyA()
r.Before = []string{"a", "b", "c"}
@@ -652,7 +653,7 @@ func TestAModuleSaidAgainOverAnOlderEnginesUnknownIsWrittenWithThisEnginesHealth
l := newHaveLink()
fp := "src2:" + strings.Repeat("a", 64)
dig := "sha256:" + strings.Repeat("b", 64)
l.put(t, "n1.xorg", delivery.Have{V: delivery.Version, FP: fp, Composed: dig, Phase: delivery.PhaseRunning,
l.put(t, "n1.xorg", delivery.Have{V: sdkkeys.Version, FP: fp, Composed: dig, Phase: delivery.PhaseRunning,
Health: delivery.HealthUnknown})
q, _ := aHaveQueue(l)
if !q.SayHealth(context.Background(), *healthOf(map[string]string{"web": StateHealthy})) {
@@ -748,7 +749,7 @@ func TestADeclarationReportMovesAHealthAndARemovalForgetsIt(t *testing.T) {
// key that does not exist is not made up and is said once; a writer that drops the list again is written over.
func TestAUserListReachesTheHaveOfAModuleNoApplyHereSays(t *testing.T) {
l := newHaveLink()
older := delivery.Have{V: delivery.Version, Build: "build-1", Phase: delivery.PhaseRunning, Health: delivery.HealthOK}
older := delivery.Have{V: sdkkeys.Version, Build: "build-1", Phase: delivery.PhaseRunning, Health: delivery.HealthOK}
l.put(t, "n1.nats", older)
q, said := aHaveQueue(l)
dig := "sha256:" + strings.Repeat("c", 64)
+2 -1
View File
@@ -2,6 +2,7 @@ package link
import (
"encoding/json"
sdkkeys "git.novox.be/novox/mesh-sdk/go/keys"
"slices"
"sort"
"sync"
@@ -60,7 +61,7 @@ func recordOf(node string, r Report, keys RecordKeys) *delivery.NodeRecord {
if err != nil || json.Unmarshal(raw, &p) != nil {
return nil
}
rec := &delivery.NodeRecord{V: delivery.Version, Node: node, TunnelKey: keys.TunnelKey, SealingKey: keys.SealingKey,
rec := &delivery.NodeRecord{V: sdkkeys.Version, Node: node, TunnelKey: keys.TunnelKey, SealingKey: keys.SealingKey,
ServingKey: keys.ServingKey, Certificate: keys.Certificate, Authority: keys.Authority, Trusts: keys.Trusts,
ManifestReads: manifestReads()}
for _, c := range p.Capabilities {
+2 -1
View File
@@ -5,6 +5,7 @@ import (
"encoding/json"
"errors"
"fmt"
sdkkeys "git.novox.be/novox/mesh-sdk/go/keys"
"strings"
"sync"
"time"
@@ -413,7 +414,7 @@ func (q *Session) SayReads() {
}
q.reads.linked = true
q.reads.Unlock()
q.SayEngine(nodeengine.EventManifestReadsChanged, nodeengine.ManifestReadsChangedEvent{V: delivery.Version,
q.SayEngine(nodeengine.EventManifestReadsChanged, nodeengine.ManifestReadsChangedEvent{V: sdkkeys.Version,
Node: q.Membership.Node, ManifestReads: manifestReads(), At: time.Now().UTC().Format(time.RFC3339Nano), Why: why})
}