No client names the holder of the seat mesh-provisioner: each reader keeps its own constant, held to its manifest (ADR 0625 section 4, issue 1966)

Claude-Session: https://claude.ai/code/session_01NcbgfFSnn24M3GcqttoU7i
This commit is contained in:
2026-11-05 19:36:21 +01:00
parent e1eb98fcbc
commit db50239373
6 changed files with 45 additions and 9 deletions
@@ -26,7 +26,7 @@ func main() {
if node == "" {
say("MESH_NODE is not set; answering no consumers")
} else {
p := newProvider(node, provider.StateBus(ModuleName), say)
p := newProvider(node, provider.StateBus(ModuleName, provisionerModule), say)
go func() {
// The helper's watches go through the runtime's channel, which Serve holds: one asked before it does is
// refused ("before Serve"), Run returns and the helper stays stopped until the process restarts.
@@ -43,3 +43,7 @@ func main() {
os.Exit(1)
}
}
// provisionerModule is the holder of the seat mesh-provisioner, named from this module's manifest (its `reads` of plans and
// provisions; TestTheProvisionerIsTheManifests).
const provisionerModule = "mesh-provisioner"
@@ -27,7 +27,7 @@ const (
func newProvider(node string, bus provider.Bus, logf func(string, ...any)) *provider.Provider {
return provider.New(provider.Options{
Node: node,
Module: ModuleName,
Module: ModuleName, Provisioner: provisionerModule,
Offers: map[string]provider.Offer{ProvisionName: {
Credential: provider.NoCredential,
Serves: map[string]any{},
@@ -63,7 +63,7 @@ func TestAConsumerOfARouteIsToldItsNamesFromItsPlanEntry(t *testing.T) {
t.Fatal(err)
}
key := "g14." + module
if err := bus.Put(context.Background(), meshprovisionerclient.PlansBucket, key, plan); err != nil {
if err := bus.Put(context.Background(), meshprovisionerclient.PlansBucketOf(provisionerModule), key, plan); err != nil {
t.Fatal(err)
}
asked, err := json.Marshal(meshprovisionerclient.Provision{V: meshprovisionerclient.Version, Provision: ProvisionName,
@@ -72,7 +72,7 @@ func TestAConsumerOfARouteIsToldItsNamesFromItsPlanEntry(t *testing.T) {
if err != nil {
t.Fatal(err)
}
if err := bus.Put(context.Background(), meshprovisionerclient.ProvisionsBucket, key+"."+ProvisionName, asked); err != nil {
if err := bus.Put(context.Background(), meshprovisionerclient.ProvisionsBucketOf(provisionerModule), key+"."+ProvisionName, asked); err != nil {
t.Fatal(err)
}
}
@@ -0,0 +1,28 @@
package main
import (
"encoding/json"
"os"
"slices"
"testing"
)
// The module holding the seat mesh-provisioner, which this provider reads the plans and provisions of, is the one its manifest's
// `reads` name: no client names a holder (novox/hq ADR 0625 §4).
func TestTheProvisionerIsTheManifests(t *testing.T) {
raw, err := os.ReadFile("../../module.json")
if err != nil {
t.Fatal(err)
}
var m struct {
Reads []string `json:"reads"`
}
if err := json.Unmarshal(raw, &m); err != nil {
t.Fatal(err)
}
for _, state := range []string{"plans", "provisions"} {
if !slices.Contains(m.Reads, provisionerModule+"."+state) {
t.Errorf("the provider reads %s.%s, its manifest's reads are %v", provisionerModule, state, m.Reads)
}
}
}
+5 -3
View File
@@ -11,7 +11,6 @@ import (
"github.com/nats-io/nats.go"
"git.novox.be/novox/mesh-contracts/placement/go/clients/meshmoduleassignerclient"
"git.novox.be/novox/mesh-contracts/provisioning/go/clients/meshprovisionerclient"
stdio "git.novox.be/novox/mesh-sdk/go"
"git.novox.be/novox/mesh-sdk/go/announce"
"git.novox.be/novox/mesh-sdk/go/process"
@@ -23,6 +22,9 @@ import (
// client names a holder (novox/hq ADR 0625 §4), so the name is kept here and held to the manifest by TestTheReadIsTheManifests.
const placementRead = "mesh-delivery-assigner.placement"
// plansRead is the seat mesh-provisioner's state plans as this module's manifest reads it (`reads`; TestTheReadIsTheManifests).
const plansRead = "mesh-provisioner.plans"
// keptStates is every state route-proxy keeps, as both its halves write them: the routes and the refusals this
// proxy writes, readable by others, and the bound entries the provider helper writes.
func keptStates() []announce.State {
@@ -81,7 +83,7 @@ func followOnce(path string, held *table) error {
if err := followInside(conn.Read(placementRead), held); err != nil {
log.Printf("cannot follow %s, so an internal name is served to this machine alone: %v", placementRead, err)
}
if err := followPlans(conn.Read(meshprovisionerclient.PlansRead), newPlanned(account.Node, say), held, say); err != nil {
if err := followPlans(conn.Read(plansRead), newPlanned(account.Node, say), held, say); err != nil {
conn.Close()
return err
}
@@ -108,7 +110,7 @@ func followPlans(plans planWatch, given *planned, held *table, say func(string,
return nil
})
if err != nil {
return fmt.Errorf("watching %s: %w", meshprovisionerclient.PlansRead, err)
return fmt.Errorf("watching %s: %w", plansRead, err)
}
read.Store(true)
serve(given, held, say)
@@ -19,7 +19,9 @@ func TestTheReadIsTheManifests(t *testing.T) {
if err := json.Unmarshal(raw, &m); err != nil {
t.Fatal(err)
}
if !slices.Contains(m.Reads, placementRead) {
t.Errorf("the proxy follows %s, its manifest reads %v", placementRead, m.Reads)
for _, read := range []string{placementRead, plansRead} {
if !slices.Contains(m.Reads, read) {
t.Errorf("the proxy follows %s, its manifest reads %v", read, m.Reads)
}
}
}