Merge b6/registry into the registry milestone's join: the console reads through the assigner's client, with the seat name mesh-module-assigner (issue 1966)

Claude-Session: https://claude.ai/code/session_01NcbgfFSnn24M3GcqttoU7i
This commit is contained in:
2026-11-05 15:39:17 +01:00
12 changed files with 134 additions and 71 deletions
+4 -5
View File
@@ -18,7 +18,6 @@ import (
"encoding/json"
"errors"
"fmt"
"git.novox.be/novox/mesh-sdk/go/buscompose"
"git.novox.be/novox/mesh-sdk/go/membership"
"log"
"regexp"
@@ -355,7 +354,7 @@ func (c *Conn) Credential() Credential { return c.cred }
// Follow reads a module's membership on this machine once and follows it live, so its tools are
// served where the mesh issued them (ADR 0175). It is read from the grants part's state memberships, its key
// `<node>.<module>` (novox/hq ADR 0571 clause 7 and 10, mesh-sdk buscompose.GrantsMembershipsBucket), and nowhere else:
// `<node>.<module>` (novox/hq ADR 0571 clause 7 and 10, mesh-sdk membership.GrantsBucket), and nowhere else:
// the old assignments stream is not read and its subject is not heard.
func (c *Conn) Follow(module string) {
c.mu.Lock()
@@ -434,10 +433,10 @@ func (c *Conn) watchGrants(module string, say bool) bool {
c.Logf(format, a...)
}
}
key := buscompose.MembershipKey(c.node, module)
key := membership.GrantsKey(c.node, module)
// First the key's direct get, which the account is granted alone: a bus that refuses it, or a state not there yet,
// answers at once, where binding the bucket would wait out its bound on a refusal.
bucket := buscompose.GrantsMembershipsBucket
bucket := membership.GrantsBucket
probe, err := c.nc.Request("$JS.API.DIRECT.GET.KV_"+bucket+".$KV."+bucket+"."+key, nil, GrantsPatience)
if err != nil || probe.Header.Get("Status") == "503" {
why := "it did not answer"
@@ -457,7 +456,7 @@ func (c *Conn) watchGrants(module string, say bool) bool {
kv, err := js.KeyValue(ctx, bucket)
if err != nil {
logf("[mesh-tools] the grants part's memberships (%s) cannot be read (%v); %s has no membership "+
"until it can be", buscompose.GrantsMembershipsBucket, err, module)
"until it can be", membership.GrantsBucket, err, module)
return false
}
w, err := kv.Watch(context.Background(), key)
+40 -22
View File
@@ -17,8 +17,10 @@ package console
// session — so a tool that arrived a minute ago is found without the client reconnecting.
import (
assigner "git.novox.be/novox/mesh-contracts/placement/go/clients/meshmoduleassignerclient"
"git.novox.be/novox/mesh-contracts/placement/go/seats/meshmoduleassigner"
meshcatalogclient "git.novox.be/novox/mesh-delivery/contracts/go/clients/meshcatalogclient"
"git.novox.be/novox/mesh-sdk/go/catalogue"
"git.novox.be/novox/mesh-sdk/go/delivery"
"context"
"encoding/json"
@@ -30,6 +32,7 @@ import (
"github.com/novox/mesh-tools/node-tools/internal/announce"
"github.com/novox/mesh-tools/node-tools/internal/bus"
"github.com/novox/mesh-tools/node-tools/internal/firstview"
)
// IndexKept is how long what the mesh answered is kept before it is asked again: long enough that
@@ -149,7 +152,7 @@ type index struct {
// called missing while it is here (2026-10-05).
Unheard []unheard
// Placed is the state seat-holders as the seat mesh-module-assigner's holder wrote it (novox/hq ADR 0571 clause 4), by its
// keys `<seat>` and `<seat>.<node>`, read with delivery.HoldersOf; PlacedWhy says why it could not be read.
// keys `<seat>` and `<seat>.<node>`, read with assigner.HoldersOf; PlacedWhy says why it could not be read.
Placed map[string][]byte
PlacedWhy string
// Replaces is what each verb and tool replaces (novox/hq ADR 0245):
@@ -337,7 +340,7 @@ func indexOn(conn *bus.Conn, src Source, held announce.Known, before func(announ
}
l.NotAnswering = append(l.NotAnswering, recordsWhy...)
if x.PlacedWhy != "" {
l.NotAnswering = append(l.NotAnswering, delivery.SeatHoldersRead+" (who holds which seat by placement could not be read: "+
l.NotAnswering = append(l.NotAnswering, assigner.SeatHoldersRead+" (who holds which seat by placement could not be read: "+
x.PlacedWhy+")")
}
for _, u := range x.Unheard {
@@ -357,7 +360,7 @@ func indexOn(conn *bus.Conn, src Source, held announce.Known, before func(announ
}
// Source is where the console reads the four states of the indexer and the assigner it indexes the mesh by: the assigner's
// placement and seat-holders, the indexer's modules and manifests, by `<owner>.<state>` (delivery.PlacementRead and the
// placement and seat-holders, the indexer's modules and manifests, by `<owner>.<state>` (assigner.PlacementRead and the
// rest). The tool runner's is its first views (firstview.Views), never the owners' state (novox/hq ADR 0615 §1).
type Source interface {
// State is every current value of a state by key; an error says why it cannot be told yet.
@@ -366,16 +369,16 @@ type Source interface {
Entry(name, key string) ([]byte, error)
}
// seatHoldersOn reads the state seat-holders whole (novox/hq ADR 0571 clause 4), as delivery.SeatHoldersRead.
// seatHoldersOn reads the state seat-holders whole (novox/hq ADR 0571 clause 4), as assigner.SeatHoldersRead.
func seatHoldersOn(src Source) (map[string][]byte, error) {
return src.State(delivery.SeatHoldersRead)
return src.State(assigner.SeatHoldersRead)
}
// The indexer's states the console reads (novox/hq ADR 0571 clauses 4 and 5): every module, and each manifest by its
// digest, by the names a reader's manifest declares.
var (
modulesRead = delivery.IndexerModule + ".modules"
manifestsRead = delivery.IndexerModule + ".manifests"
modulesRead = firstview.ModulesRead
manifestsRead = firstview.ManifestsRead
)
// manifestFacts is what the console takes of a manifest: the tools it declares and what each replaces. A manifest's
@@ -388,20 +391,20 @@ type manifestFacts struct {
var manifestsKept sync.Map // digest → manifestFacts
// recordsOn is every module the indexer holds, with where the placement seat places it and whether it declares tools,
// and every machine placement names (delivery.ModuleNames, delivery.MachineNames). What cannot be read is said, one line
// and every machine placement names (moduleNames, assigner.MachineNames). What cannot be read is said, one line
// per state, for the listing's not answering.
func recordsOn(src Source) (recorded []recordedModule, machines []string, why []string) {
placements, err := src.State(delivery.PlacementRead)
placements, err := src.State(assigner.PlacementRead)
if err != nil {
why = append(why, delivery.PlacementRead+" (where modules are placed could not be read, so what is missing cannot "+
why = append(why, assigner.PlacementRead+" (where modules are placed could not be read, so what is missing cannot "+
"be said: "+err.Error()+")")
}
machines = delivery.MachineNames(placements)
machines = assigner.MachineNames(placements)
on := map[string][]string{}
// The placement's keys in either form, a node key and its module keys or the form before (research 072 row 37).
assembled, err := delivery.PlacementsOf(placements)
assembled, err := assigner.PlacementsOf(placements)
if err != nil {
why = append(why, delivery.PlacementRead+" (not every key is a placement: "+err.Error()+")")
why = append(why, assigner.PlacementRead+" (not every key is a placement: "+err.Error()+")")
}
for _, node := range machines {
for _, m := range assembled[node].Modules {
@@ -412,13 +415,13 @@ func recordsOn(src Source) (recorded []recordedModule, machines []string, why []
if err != nil {
return nil, machines, append(why, modulesRead+" (which modules there are could not be read: "+err.Error()+")")
}
names, err := delivery.ModuleNames(modules)
names, err := moduleNames(modules)
if err != nil {
return nil, machines, append(why, modulesRead+" ("+err.Error()+")")
}
for _, name := range names {
r := recordedModule{Module: name, On: on[name]}
if m, err := delivery.DecodeModule(modules[name]); err == nil && m.Manifest != "" {
if m, err := meshcatalogclient.DecodeModule(modules[name]); err == nil && m.Manifest != "" {
facts, err := manifestOf(src, m.Manifest)
if err != nil {
why = append(why, name+" (its manifest could not be read, so whether it answers tools is not known: "+err.Error()+")")
@@ -431,6 +434,21 @@ func recordsOn(src Source) (recorded []recordedModule, machines []string, why []
return recorded, machines, why
}
// moduleNames is every module the indexer holds, sorted, from its state `modules` as a reader holds its keys (key to
// value; a deleted key absent). A key that is not a module's is refused, naming it.
func moduleNames(keys map[string][]byte) ([]string, error) {
out := make([]string, 0, len(keys))
for k := range keys {
module, err := meshcatalogclient.ParseModulesKey(k)
if err != nil {
return nil, err
}
out = append(out, module)
}
sort.Strings(out)
return out, nil
}
// manifestOf is what the console takes of the manifest of a digest, read from the indexer's manifests once.
func manifestOf(src Source, digest string) (manifestFacts, error) {
if kept, ok := manifestsKept.Load(digest); ok {
@@ -443,12 +461,12 @@ func manifestOf(src Source, digest string) (manifestFacts, error) {
if entry == nil {
return manifestFacts{}, fmt.Errorf("the indexer holds no manifest %s", digest)
}
m, err := delivery.DecodeManifest(entry)
m, err := meshcatalogclient.DecodeManifest(entry)
if err != nil {
return manifestFacts{}, err
}
var facts manifestFacts
if err := json.Unmarshal([]byte(m.JSON), &facts); err != nil {
if err := json.Unmarshal([]byte(m.Manifest), &facts); err != nil {
return manifestFacts{}, err
}
manifestsKept.Store(digest, facts)
@@ -456,19 +474,19 @@ func manifestOf(src Source, digest string) (manifestFacts, error) {
}
// placedHolders is who holds seat (on node, for a seat held per machine) by placement, or none.
func (x *index) placedHolders(seat, node string) []delivery.SeatHolder {
func (x *index) placedHolders(seat, node string) []meshmoduleassigner.SeatHoldersHoldersItem {
if len(x.Placed) == 0 {
return nil
}
hs, err := delivery.HoldersOf(x.Placed, seat, node)
hs, err := assigner.HoldersOf(x.Placed, seat, node)
if err != nil || len(hs) > 0 || node != "" {
return hs
}
// A seat held per machine, asked without one: every node's key of it.
var all []delivery.SeatHolder
var all []meshmoduleassigner.SeatHoldersHoldersItem
for key := range x.Placed {
if s, n, ok := strings.Cut(key, "."); ok && s == seat {
if more, err := delivery.HoldersOf(x.Placed, seat, n); err == nil {
if more, err := assigner.HoldersOf(x.Placed, seat, n); err == nil {
all = append(all, more...)
}
}
+2 -2
View File
@@ -6,8 +6,8 @@ package console
import (
"context"
"encoding/json"
"git.novox.be/novox/mesh-contracts/placement/go/seats/meshmoduleassigner"
"git.novox.be/novox/mesh-sdk/go/catalogue"
"git.novox.be/novox/mesh-sdk/go/delivery"
"os"
"strings"
"sync"
@@ -78,7 +78,7 @@ func (s *Surface) seatsAnswer() map[string]any {
for _, st := range catalogue.Seats() {
holders := x.placedHolders(st.Name, "")
if holders == nil {
holders = []delivery.SeatHolder{}
holders = []meshmoduleassigner.SeatHoldersHoldersItem{}
}
tools := st.Serves
if tools == nil {
+11 -8
View File
@@ -8,7 +8,8 @@ import (
"testing"
"time"
"git.novox.be/novox/mesh-sdk/go/delivery"
assigner "git.novox.be/novox/mesh-contracts/placement/go/clients/meshmoduleassignerclient"
seatplacement "git.novox.be/novox/mesh-contracts/placement/go/seats/meshmoduleassigner"
"github.com/nats-io/nats.go/micro"
"github.com/novox/mesh-tools/node-tools/internal/announce"
@@ -61,13 +62,15 @@ func TestARuntimeThatAnswersLateIsFoundAndOneThatNeverDoesIsNamed(t *testing.T)
map[string][]string{"laptop": {"slack", "nextcloud-client"}, "sleeper": {"nap", "nextcloud-client"},
"desktop": {"nextcloud-client"}, "bench": nil})
// Who holds which seat, by placement (ADR 0571 clause 4), as the seat mesh-module-assigner's holder composes it.
placedKV := mesh.Bucket(t, delivery.SeatHoldersBucket)
for key, sh := range delivery.SeatHoldersOf(map[string]delivery.Placement{"bench": {Node: "bench",
Holds: []delivery.Holding{{Claim: "mesh-wants", Scope: "mesh", Module: "mesh-delivery-assigner"}}}}) {
raw, _ := json.Marshal(sh)
if _, err := placedKV.Put(key, raw); err != nil {
t.Fatal(err)
}
placedKV := mesh.Bucket(t, assigner.SeatHoldersBucket)
holdersKey, err := assigner.SeatHoldersKey("mesh-wants", "")
if err != nil {
t.Fatal(err)
}
raw, _ := json.Marshal(seatplacement.SeatHolders{V: assigner.Version, Seat: "mesh-wants", Scope: "mesh",
Holders: []seatplacement.SeatHoldersHoldersItem{{Module: "mesh-delivery-assigner", Node: "bench"}}})
if _, err := placedKV.Put(holdersKey, raw); err != nil {
t.Fatal(err)
}
consoleMembership := mt.MembershipOf("node-tools", "laptop-console", false, nil)
consoleMembership.State = mt.ConsoleReads()
+12 -4
View File
@@ -13,6 +13,7 @@ import (
"fmt"
conditions "git.novox.be/novox/mesh-contracts/health-and-repair/go/clients/meshconditionsclient"
condseat "git.novox.be/novox/mesh-contracts/health-and-repair/go/seats/meshconditions"
assigner "git.novox.be/novox/mesh-contracts/placement/go/clients/meshmoduleassignerclient"
"sort"
"sync"
"time"
@@ -25,7 +26,14 @@ import (
// The owners and their first-view tools (the tools' addresses are `<owner>.<tool>`).
const (
Indexer = "mesh-delivery-indexer"
Assigner = "mesh-delivery-assigner"
Assigner = assigner.Module
)
// The names the console reads the indexer's two states by (`<owner>.<state>`), as a manifest's `reads` names them; the
// assigner's two are its client's (assigner.PlacementRead, assigner.SeatHoldersRead).
const (
ModulesRead = Indexer + ".modules"
ManifestsRead = Indexer + ".manifests"
)
// Spec is one first view the runner holds.
@@ -39,7 +47,7 @@ var Specs = []Spec{
{Indexer, "modules", "modules"},
}
// Name is the name a state is read by, `<owner>.<state>`: delivery.PlacementRead, delivery.SeatHoldersRead and the indexer's.
// Name is the name a state is read by, `<owner>.<state>`: assigner.PlacementRead, assigner.SeatHoldersRead and the indexer's.
func (s Spec) Name() string { return s.Owner + "." + s.State }
// Views is the four followers.
@@ -207,8 +215,8 @@ func conditionOf(f views.Finding) (string, []byte, error) {
key := conditions.Key(scopeModule, f.ID, f.Kind)
v := condseat.FindingsByKeyValue{V: 1, Key: key, Kind: f.Kind, Observer: f.Observer, Severity: conditions.Warning,
Subject: condseat.Subject{Scope: scopeModule, ID: f.ID}, Summary: f.Summary, Headline: f.Headline,
Explanation: f.Explanation, Source: f.Observer + "." + f.Kind, At: f.At.UTC().Format(time.RFC3339),
Evidence: []condseat.Evidence{{At: f.At.UTC().Format(time.RFC3339), Said: f.Summary}}}
Explanation: f.Explanation, Source: f.Observer + "." + f.Kind, At: f.At.UTC(),
Evidence: []condseat.Evidence{{At: f.At.UTC(), Said: f.Summary}}}
if err := conditions.CheckFinding(v); err != nil {
return "", nil, err
}
@@ -44,7 +44,10 @@ func TestTheRunnersConsumerCarriesTheOwnersViewsFamiliesWhenTheOwnersAreDownThen
filters := map[string][]string{}
families := 0
for _, c := range manifest.Consumes {
emitter, event, _ := strings.Cut(c, ".views.")
emitter, event, isView := strings.Cut(c, ".views.")
if !isView { // the seat mesh-catalog's events: the seat list's, on EVENTS (cmd/node-tools/seatlist.go)
continue
}
stream := streamOf[emitter]
if stream == "" {
t.Fatalf("the manifest consumes %s, whose views stream the test does not know", c)
@@ -9,6 +9,7 @@ import (
"testing"
"time"
assigner "git.novox.be/novox/mesh-contracts/placement/go/clients/meshmoduleassignerclient"
"git.novox.be/novox/mesh-sdk/go/views"
"github.com/novox/mesh-tools/node-tools/internal/bus"
@@ -166,3 +167,18 @@ func TestTheRunnerHoldsTheFourStatesFromTheOwnersFirstViewsAndTheirEvents(t *tes
t.Errorf("the gap was not said in the log: %v", logs)
}
}
// The four first views are read by the names the seats' clients give the states, and the console reads the indexer's
// two by the names here.
func TestTheFirstViewsAreNamedAsTheClientsNameTheirStates(t *testing.T) {
want := map[string]bool{assigner.PlacementRead: true, assigner.SeatHoldersRead: true, ModulesRead: true, ManifestsRead: true}
for _, s := range Specs {
if !want[s.Name()] {
t.Errorf("the first view %s is read by no name a client gives", s.Name())
}
delete(want, s.Name())
}
if len(want) > 0 {
t.Errorf("no first view reads %v", want)
}
}
+32 -22
View File
@@ -13,8 +13,10 @@ package meshtest
import (
"context"
"encoding/json"
"git.novox.be/novox/mesh-sdk/go/buscompose"
"git.novox.be/novox/mesh-sdk/go/delivery"
assigner "git.novox.be/novox/mesh-contracts/placement/go/clients/meshmoduleassignerclient"
seatplacement "git.novox.be/novox/mesh-contracts/placement/go/seats/meshmoduleassigner"
meshcatalogclient "git.novox.be/novox/mesh-delivery/contracts/go/clients/meshcatalogclient"
meshcatalog "git.novox.be/novox/mesh-delivery/contracts/go/seats/meshcatalog"
"git.novox.be/novox/mesh-sdk/go/membership"
"os"
"path/filepath"
@@ -88,8 +90,8 @@ func New(t *testing.T) *Mesh {
js, _ := nc.JetStream()
_ = js.DeleteStream("EVENTS")
// The grants part's state memberships, where a runtime reads what is issued it (ADR 0571 clause 10).
_ = js.DeleteKeyValue(buscompose.GrantsMembershipsBucket)
if _, err := js.CreateKeyValue(&nats.KeyValueConfig{Bucket: buscompose.GrantsMembershipsBucket, History: 1}); err != nil {
_ = js.DeleteKeyValue(membership.GrantsBucket)
if _, err := js.CreateKeyValue(&nats.KeyValueConfig{Bucket: membership.GrantsBucket, History: 1}); err != nil {
t.Fatal(err)
}
if _, err := js.AddStream(&nats.StreamConfig{Name: "EVENTS", Subjects: []string{"mesh.mod.*.event.>"}}); err != nil {
@@ -100,7 +102,7 @@ func New(t *testing.T) *Mesh {
}
// Issue writes a membership where the grants part keeps it, its state memberships, key `<node>.<module>` (novox/hq ADR
// 0571 clause 7 and 10; mesh-sdk buscompose.GrantsMembershipsBucket), the one place a runtime reads it. It writes with
// 0571 clause 7 and 10; mesh-sdk membership.GrantsBucket), the one place a runtime reads it. It writes with
// mesh-sdk's encoder, the grants part's own, never json of this package's type: a value built here by hand agreed with
// the reader's mistake and hid that the part wrote another shape (issue 774).
func (m *Mesh) Issue(t *testing.T, mem bus.Membership) {
@@ -120,13 +122,13 @@ func (m *Mesh) IssueInGrantsWrapped(t *testing.T, mem bus.Membership, published
func (m *Mesh) putGrants(t *testing.T, mem bus.Membership, body []byte) {
t.Helper()
kv, err := m.js.KeyValue(buscompose.GrantsMembershipsBucket)
kv, err := m.js.KeyValue(membership.GrantsBucket)
if err != nil {
if kv, err = m.js.CreateKeyValue(&nats.KeyValueConfig{Bucket: buscompose.GrantsMembershipsBucket, History: 1}); err != nil {
if kv, err = m.js.CreateKeyValue(&nats.KeyValueConfig{Bucket: membership.GrantsBucket, History: 1}); err != nil {
t.Fatal(err)
}
}
if _, err := kv.Put(buscompose.MembershipKey(mem.Node, mem.Module), body); err != nil {
if _, err := kv.Put(membership.GrantsKey(mem.Node, mem.Module), body); err != nil {
t.Fatal(err)
}
}
@@ -134,7 +136,7 @@ func (m *Mesh) putGrants(t *testing.T, mem bus.Membership, body []byte) {
// DropGrants deletes the grants part's state memberships, as a bus that has not made it yet holds none; Issue makes it again.
func (m *Mesh) DropGrants(t *testing.T) {
t.Helper()
if err := m.js.DeleteKeyValue(buscompose.GrantsMembershipsBucket); err != nil {
if err := m.js.DeleteKeyValue(membership.GrantsBucket); err != nil {
t.Fatal(err)
}
}
@@ -150,14 +152,22 @@ func sdkMembership(t *testing.T, mem bus.Membership) membership.Membership {
return out
}
// The indexer's two states the console reads, and their buckets (the test bed's own names: the indexer's client names
// no holder).
const (
indexer = "mesh-delivery-indexer"
ModulesBucket = indexer + "_modules"
ManifestsBucket = indexer + "_manifests"
)
// ConsoleReads are the states a console's runtime reads to say what the mesh holds (novox/hq ADR 0571 clauses 4, 5):
// placement, the indexer's modules and manifests, and the seat holders.
func ConsoleReads() []bus.StateIssued {
return []bus.StateIssued{
{Name: delivery.PlacementRead, Bucket: delivery.PlacementBucket},
{Name: delivery.IndexerModule + ".modules", Bucket: delivery.ModulesBucket},
{Name: delivery.IndexerModule + ".manifests", Bucket: delivery.ManifestsBucket},
{Name: delivery.SeatHoldersRead, Bucket: delivery.SeatHoldersBucket},
{Name: assigner.PlacementRead, Bucket: assigner.PlacementBucket},
{Name: indexer + ".modules", Bucket: ModulesBucket},
{Name: indexer + ".manifests", Bucket: ManifestsBucket},
{Name: assigner.SeatHoldersRead, Bucket: assigner.SeatHoldersBucket},
}
}
@@ -173,20 +183,20 @@ func (m *Mesh) Placed(t *testing.T, tools map[string][]string, on map[string][]s
}
return b
}
modules, manifests, placement := kv(delivery.ModulesBucket), kv(delivery.ManifestsBucket), kv(delivery.PlacementBucket)
kv(delivery.SeatHoldersBucket)
modules, manifests, placement := kv(ModulesBucket), kv(ManifestsBucket), kv(assigner.PlacementBucket)
kv(assigner.SeatHoldersBucket)
for module, declared := range tools {
manifest, _ := json.Marshal(map[string]any{"module": module, "tools": declared})
digest := delivery.ManifestDigest(manifest)
raw, err := delivery.EncodeManifest(delivery.Manifest{Module: module, JSON: string(manifest)})
digest := meshcatalogclient.ManifestDigest(manifest)
raw, err := meshcatalogclient.EncodeManifest(meshcatalog.ManifestsByDigestValue{Module: module, Manifest: string(manifest), V: 1})
if err != nil {
t.Fatal(err)
}
if _, err := manifests.Put(digest, raw); err != nil {
t.Fatal(err)
}
raw, err = delivery.EncodeModule(delivery.Module{None: "not built here", Manifest: digest, Repository: "novox/" + module,
Commit: strings.Repeat("a", 40)})
raw, err = meshcatalogclient.EncodeModule(meshcatalog.ModulesByModuleValue{None: "not built here", Manifest: digest, Repository: "novox/" + module,
Commit: strings.Repeat("a", 40), V: 1})
if err != nil {
t.Fatal(err)
}
@@ -195,12 +205,12 @@ func (m *Mesh) Placed(t *testing.T, tools map[string][]string, on map[string][]s
}
}
for node, placed := range on {
p := delivery.Placement{V: delivery.Version, Node: node}
p := seatplacement.Placement{V: assigner.Version, Node: node}
for _, module := range placed {
p.Modules = append(p.Modules, delivery.PlacedModule{Module: module})
p.Modules = append(p.Modules, seatplacement.PlacedModule{Module: module})
}
// As the seat writes it: its node key and a key per module (research 072 row 37).
values, err := delivery.PlacementValues(p)
values, err := assigner.PlacementValues(p)
if err != nil {
t.Fatal(err)
}
+2 -2
View File
@@ -15,8 +15,8 @@ import (
"fmt"
"time"
"git.novox.be/novox/mesh-sdk/go/provider"
"git.novox.be/novox/mesh-sdk/go/provisions"
provisions "git.novox.be/novox/mesh-contracts/provisioning/go/clients/meshprovisionerclient"
"git.novox.be/novox/mesh-contracts/provisioning/go/clients/meshprovisionerclient/provider"
"github.com/novox/mesh-tools/node-tools/internal/bus"
)
+2 -2
View File
@@ -7,9 +7,9 @@ import (
"testing"
"time"
provisions "git.novox.be/novox/mesh-contracts/provisioning/go/clients/meshprovisionerclient"
"git.novox.be/novox/mesh-contracts/provisioning/go/clients/meshprovisionerclient/provider"
"git.novox.be/novox/mesh-sdk/go/catalogue"
"git.novox.be/novox/mesh-sdk/go/provider"
"git.novox.be/novox/mesh-sdk/go/provisions"
"github.com/novox/mesh-tools/node-tools/internal/bus"
mt "github.com/novox/mesh-tools/node-tools/internal/meshtest"
@@ -63,7 +63,7 @@ func TestALedgerIsWrittenOnlyOnItsModulesLedgerConnection(t *testing.T) {
t.Fatal(err)
}
}
for _, b := range []string{"m_records", buscompose.GrantsMembershipsBucket} {
for _, b := range []string{"m_records", membership.GrantsBucket} {
if _, err := js.CreateKeyValue(ctx, jetstream.KeyValueConfig{Bucket: b}); err != nil {
t.Fatal(err)
}
@@ -76,8 +76,8 @@ func TestALedgerIsWrittenOnlyOnItsModulesLedgerConnection(t *testing.T) {
raw, _ := json.Marshal(mem)
var sdk membership.Membership
_ = json.Unmarshal(raw, &sdk)
grants, _ := js.KeyValue(ctx, buscompose.GrantsMembershipsBucket)
if _, err := grants.Put(ctx, buscompose.MembershipKey("anchor", "m"), membership.EncodeGrantsMembership(sdk)); err != nil {
grants, _ := js.KeyValue(ctx, membership.GrantsBucket)
if _, err := grants.Put(ctx, membership.GrantsKey("anchor", "m"), membership.EncodeGrantsMembership(sdk)); err != nil {
t.Fatal(err)
}