From 9d67b0995f0748a0f554ba059b51ac1c47293005 Mon Sep 17 00:00:00 2001 From: jochen Date: Thu, 29 Oct 2026 22:43:58 +0100 Subject: [PATCH] Bind node-tools' consumers by mesh-provisioner's plans and provisions alone, dropping the read of the controller's assignments the sdk's helper no longer makes (issue 1954 L6-T1) Pins mesh-sdk 692dbf9 (L6-P3). --- node-tools/go.mod | 2 +- node-tools/go.sum | 2 + node-tools/internal/provide/provide.go | 5 +-- node-tools/internal/provide/provide_test.go | 41 +++++++++++++++++---- node-tools/module.json | 1 - 5 files changed, 37 insertions(+), 14 deletions(-) diff --git a/node-tools/go.mod b/node-tools/go.mod index 485df09..2072c65 100644 --- a/node-tools/go.mod +++ b/node-tools/go.mod @@ -8,7 +8,7 @@ require ( ) require ( - git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261029213215-4a967933b368 + git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261029214150-692dbf9a1791 github.com/antithesishq/antithesis-sdk-go v0.7.0-default-no-op // indirect github.com/google/go-tpm v0.9.8 // indirect github.com/klauspost/compress v1.20.0 // indirect diff --git a/node-tools/go.sum b/node-tools/go.sum index 90dd3ce..498f046 100644 --- a/node-tools/go.sum +++ b/node-tools/go.sum @@ -4,6 +4,8 @@ git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261029210043-32f5ce371268 h1:+jH77IJm git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261029210043-32f5ce371268/go.mod h1:ouERNpZizzwZ0HLEtAypsY9FR20FyUgUYRni6J7kVCY= git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261029213215-4a967933b368 h1:LaBxsyU3HeTIPKYmvpJuw+Wm2plpf6O7qHO91O+mAi0= git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261029213215-4a967933b368/go.mod h1:ouERNpZizzwZ0HLEtAypsY9FR20FyUgUYRni6J7kVCY= +git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261029214150-692dbf9a1791 h1:HVKR7kENzltQVkfBN+2zhU9JOPZme7MjDkTvr/oiJ24= +git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261029214150-692dbf9a1791/go.mod h1:ouERNpZizzwZ0HLEtAypsY9FR20FyUgUYRni6J7kVCY= github.com/antithesishq/antithesis-sdk-go v0.7.0-default-no-op h1:Z/MZK75wC/NSrkgqeNIa7jexam9uWzhLmFTSCPI/kn0= github.com/antithesishq/antithesis-sdk-go v0.7.0-default-no-op/go.mod h1:FQyySiasQQM8735Ddel3MRojmy4dA1IqCeyJ5jmPMbI= github.com/google/go-tpm v0.9.8 h1:slArAR9Ft+1ybZu0lBwpSmpwhRXaa85hWtMinMyRAWo= diff --git a/node-tools/internal/provide/provide.go b/node-tools/internal/provide/provide.go index 90683d0..e51e5c7 100644 --- a/node-tools/internal/provide/provide.go +++ b/node-tools/internal/provide/provide.go @@ -40,8 +40,7 @@ func Offers() map[string]provider.Offer { // busOf is the helper's bus over the runtime's own state: the provider's bucket is its state `bound`, and the // provisions and plans of the seat mesh-provisioner are the states it reads, by mesh-sdk's names (novox/hq ADR 0570, -// issue 1954 L6-T1). The controller's assignments stay readable while the sdk's helper still reads its plans there -// (until L6-P3 moves it); the constant's removal from the sdk then fails this build, so the read goes with it. +// issue 1954 L6-T1). The controller's assignments are read no more (mesh-sdk 692dbf9, L6-P3). type busOf struct{ conn *bus.Conn } func (b busOf) state(bucket string) (string, error) { @@ -52,8 +51,6 @@ func (b busOf) state(bucket string) (string, error) { return provisions.ProvisionsRead, nil case provisions.PlansBucket: return provisions.PlansRead, nil - case provider.AssignmentsBucket: - return "mesh-controller.assignments", nil } return "", fmt.Errorf("%s is not a bucket this provider keeps or reads", bucket) } diff --git a/node-tools/internal/provide/provide_test.go b/node-tools/internal/provide/provide_test.go index 6798108..89fd480 100644 --- a/node-tools/internal/provide/provide_test.go +++ b/node-tools/internal/provide/provide_test.go @@ -7,6 +7,7 @@ import ( "testing" "time" + "git.novox.be/novox/mesh-sdk/go/catalogue" "git.novox.be/novox/mesh-sdk/go/provider" "git.novox.be/novox/mesh-sdk/go/provisions" @@ -44,19 +45,39 @@ func fill(t *testing.T, template string, entry map[string]any) string { func TestTheRuntimeAnswersAHandedConsumersMcpEndpointThroughTheHelper(t *testing.T) { mesh := mt.New(t) bound := mesh.Bucket(t, "node-tools_bound") - assignments := mesh.Bucket(t, "mesh-controller_assignments") + plans := mesh.Bucket(t, provisions.PlansBucket) + provs := mesh.Bucket(t, provisions.ProvisionsBucket) mem := mt.MembershipOf("node-tools", "anchor", false, nil) mem.State = []bus.StateIssued{ {Name: "bound", Bucket: "node-tools_bound", Writes: true}, - {Name: "mesh-controller.assignments", Bucket: "mesh-controller_assignments"}, + {Name: provisions.PlansRead, Bucket: provisions.PlansBucket}, + {Name: provisions.ProvisionsRead, Bucket: provisions.ProvisionsBucket}, } mesh.Issue(t, mem) - // claude-code, handed on this machine, is bound to node-tools here for mcp-endpoint (issue 788's plan entry). - plan := `{"node":"anchor","module":"claude-code","provisioning":{"provisions":[{"provision":"mcp-endpoint",` + - `"provider":"anchor","provider-module":"node-tools","at":"127.0.0.1","from":"anchor","as":"mesh_anchor_claude_code"}]}}` - if _, err := assignments.Put("anchor.claude-code", []byte(plan)); err != nil { + // claude-code, handed on this machine, is bound to node-tools here for mcp-endpoint: its plan and its provision + // key, written as mesh-provisioner writes them, with mesh-sdk's encoders (ADR 0570 clauses 1-3, issue 1954). + plan, err := provisions.EncodePlan(provisions.Plan{Node: "anchor", Module: "claude-code", Plan: catalogue.Plan{ + Provisions: []catalogue.PlanProvision{{Provision: "mcp-endpoint", Provider: "anchor", ProviderModule: "node-tools", + At: "127.0.0.1", From: "anchor", As: "mesh_anchor_claude_code"}}}}) + if err != nil { + t.Fatal(err) + } + if _, err := plans.Put("anchor.claude-code", plan); err != nil { + t.Fatal(err) + } + key, err := provisions.Key("anchor", "claude-code", "mcp-endpoint", "") + if err != nil { + t.Fatal(err) + } + asked, err := provisions.Encode(provisions.Provision{Provision: "mcp-endpoint", State: provisions.Asked, + Consumer: provisions.End{Node: "anchor", Module: "claude-code"}, Provider: provisions.End{Node: "anchor", Module: "node-tools"}, + At: time.Now()}) + if err != nil { + t.Fatal(err) + } + if _, err := provs.Put(key, asked); err != nil { t.Fatal(err) } @@ -138,13 +159,18 @@ func TestTheOfferServesThePortTheManifestServes(t *testing.T) { t.Error("the manifest still carries a consumers file the helper does not need") } } + for _, r := range m.Reads { + if r == "mesh-controller.assignments" { + t.Error("the manifest still reads mesh-controller.assignments, which the sdk's helper no longer reads (issue 1954)") + } + } for _, a := range m.Build.Artifacts { if a.Name == "files" || len(a.Env) > 0 { t.Errorf("the build still carries %+v, which only a moved module needs", a) } } // Every bucket the sdk's helper reaches is a state the manifest keeps or reads, by the sdk's names: the provider's - // own, the seat mesh-provisioner's provisions and plans (issue 1954 L6-T1), and the assignments the helper still reads. + // own and the seat mesh-provisioner's provisions and plans (issue 1954 L6-T1); the controller's assignments no more. declared := map[string]bool{} for _, n := range append(m.State, m.Reads...) { declared[n] = true @@ -153,7 +179,6 @@ func TestTheOfferServesThePortTheManifestServes(t *testing.T) { provider.BucketOf(Module): "bound", provisions.ProvisionsBucket: "mesh-provisioner.provisions", provisions.PlansBucket: "mesh-provisioner.plans", - provider.AssignmentsBucket: "mesh-controller.assignments", } { got, err := (busOf{}).state(bucket) if err != nil || got != want || !declared[got] { diff --git a/node-tools/module.json b/node-tools/module.json index e8aad40..14eb712 100644 --- a/node-tools/module.json +++ b/node-tools/module.json @@ -65,7 +65,6 @@ "bound" ], "reads": [ - "mesh-controller.assignments", "mesh-provisioner.provisions", "mesh-provisioner.plans" ]