Node-engine: the have, the node's facts, the record, the health report and the data items are the seat's contract types, written through the node-engine client; the interim bridge is gone (Have group, ADR 0634 §1, §4; issue 1966)

Claude-Session: https://claude.ai/code/session_01NcbgfFSnn24M3GcqttoU7i
This commit is contained in:
2026-11-05 15:21:48 +01:00
parent 5906e18028
commit 7eb7b9fa62
44 changed files with 650 additions and 549 deletions
+12 -10
View File
@@ -5,7 +5,9 @@ import (
"context"
"encoding/json"
"fmt"
"git.novox.be/novox/mesh-contracts/go/clients/nodeengineclient"
nodeengine "git.novox.be/novox/mesh-contracts/go/seats/nodeengine"
"github.com/novox/mesh-host/internal/buckets"
engcomp "github.com/novox/mesh-host/internal/compositions"
"sort"
"strings"
@@ -160,11 +162,11 @@ func (s *Shadow) Run(ctx context.Context) error {
ins := []input{
{delivery.PlacementCandidatesBucket, ">", nil, nil},
{delivery.PlacementBucket, ">", (*Composer).takePlacement, nil},
{delivery.HaveBucket, "*." + delivery.HaveNodeWord, nil, nil},
{buckets.Have, "*." + nodeengineclient.NodeWord, nil, nil},
{delivery.ModulesBucket, ">", (*Composer).takeModule, nil},
{ResolvedBucket, node + ".>", (*Composer).takeValue, nil},
// What this node runs moved: an apply ends in its module's have.
{delivery.HaveBucket, node + ".>", nil, nil},
{buckets.Have, node + ".>", nil, nil},
}
type tagged struct {
in int
@@ -315,7 +317,7 @@ func (s *Shadow) takeCandidate(u agent.Update) bool {
// takeRecord takes a node's record, and says whether it changed: the node's own key changes with each answer written,
// which moves nothing composed.
func (s *Shadow) takeRecord(u agent.Update) bool {
node, _, isNode, err := delivery.ParseHaveKey(u.Key)
node, _, isNode, err := nodeengineclient.ParseHaveKey(u.Key)
if err != nil || !isNode {
return false
}
@@ -327,7 +329,7 @@ func (s *Shadow) takeRecord(u agent.Update) bool {
c.mu.Lock()
after, has := c.records[node]
c.mu.Unlock()
return had != has || (has && !delivery.SameNodeRecord(before, after))
return had != has || (has && !nodeengineclient.SameNodeRecord(before, after))
}
// How long the shadow waits before it says it is not ready, and how long a proposal's answer runs before it is said slow.
@@ -600,14 +602,14 @@ func (s *Shadow) heldToday() map[string]string {
// takeRan keeps the digest one of this node's module haves says runs, and says whether it changed: a have whose health
// or words alone moved runs the same.
func (s *Shadow) takeRan(u agent.Update) bool {
node, module, isNode, err := delivery.ParseHaveKey(u.Key)
node, module, isNode, err := nodeengineclient.ParseHaveKey(u.Key)
if err != nil || isNode || node != s.c.env.Node {
return false
}
s.mu.Lock()
defer s.mu.Unlock()
before, had := s.ran[module]
h, err := delivery.DecodeHave(u.Value)
h, err := nodeengineclient.DecodeHave(u.Value)
if s.heldNow == nil {
s.heldNow = map[string]string{}
}
@@ -615,18 +617,18 @@ func (s *Shadow) takeRan(u agent.Update) bool {
s.heldNow[module] = ""
if !u.Deleted && err == nil {
switch {
case h.Phase == delivery.PhaseHeld:
case h.Phase == nodeengineclient.PhaseHeld:
s.heldNow[module] = "held"
case h.Phase == delivery.PhaseFailed:
case h.Phase == nodeengineclient.PhaseFailed:
s.heldNow[module] = "failed"
case h.Phase != delivery.PhaseRemoved && h.FP == "" && h.Build != "":
case h.Phase != nodeengineclient.PhaseRemoved && h.Fp == "" && h.Build != "":
// A build of the old form: its have names a `build` and no `fp`, which no registered build of the trunk
// names, so the controller keeps it as it runs (issue 1126: novox's de-spiegel at build-…); a seed keeps it so.
s.heldNow[module] = "runs a build of the old form"
}
}
holdMoved := wasHeld != s.heldNow[module] // a hold's start or end changes the answer too
if u.Deleted || err != nil || h.Composed == "" || h.Phase == delivery.PhaseRemoved {
if u.Deleted || err != nil || h.Composed == "" || h.Phase == nodeengineclient.PhaseRemoved {
delete(s.ran, module)
return had || holdMoved
}