diff --git a/node-tools/go.mod b/node-tools/go.mod index 2b2f91b..485df09 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.20261029210043-32f5ce371268 + git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261029213215-4a967933b368 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 4495931..90dd3ce 100644 --- a/node-tools/go.sum +++ b/node-tools/go.sum @@ -2,6 +2,8 @@ git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261023150321-a2c813a6b468 h1:UcMee+IV git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261023150321-a2c813a6b468/go.mod h1:ouERNpZizzwZ0HLEtAypsY9FR20FyUgUYRni6J7kVCY= git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261029210043-32f5ce371268 h1:+jH77IJmxUiFDdbJljhynQRY0Cc5/5jtwmMV7UUqRI4= 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= 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 068ac59..90683d0 100644 --- a/node-tools/internal/provide/provide.go +++ b/node-tools/internal/provide/provide.go @@ -16,6 +16,7 @@ import ( "time" "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" ) @@ -38,13 +39,19 @@ 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 -// controller's assignments are the state it reads, `mesh-controller.assignments` (both declared in the manifest). +// 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. type busOf struct{ conn *bus.Conn } func (b busOf) state(bucket string) (string, error) { switch bucket { case provider.BucketOf(Module): return "bound", nil + case provisions.ProvisionsBucket: + return provisions.ProvisionsRead, nil + case provisions.PlansBucket: + return provisions.PlansRead, nil case provider.AssignmentsBucket: return "mesh-controller.assignments", nil } @@ -57,7 +64,8 @@ func (b busOf) Watch(ctx context.Context, bucket string, handle func(key string, return err } stop, err := b.conn.StateWatch(Module, name, "", func(ch bus.StateChange) error { - if ch.Op == "delete" { + if ch.Op != "put" { + // A delete, or an expiry (issue 1952): the key is gone. handle(ch.Key, nil) } else { handle(ch.Key, ch.Value) diff --git a/node-tools/internal/provide/provide_test.go b/node-tools/internal/provide/provide_test.go index 9f2b191..6798108 100644 --- a/node-tools/internal/provide/provide_test.go +++ b/node-tools/internal/provide/provide_test.go @@ -7,6 +7,9 @@ import ( "testing" "time" + "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" ) @@ -102,6 +105,8 @@ func TestTheOfferServesThePortTheManifestServes(t *testing.T) { var m struct { Serves map[string]map[string]any `json:"serves"` Moved bool `json:"moved"` + State []string `json:"state"` + Reads []string `json:"reads"` Provides []struct { Name string `json:"name"` AnsweredBy string `json:"answered-by"` @@ -138,6 +143,23 @@ func TestTheOfferServesThePortTheManifestServes(t *testing.T) { 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. + declared := map[string]bool{} + for _, n := range append(m.State, m.Reads...) { + declared[n] = true + } + for bucket, want := range map[string]string{ + 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] { + t.Errorf("the helper's bucket %s reaches state %q (%v), want %q declared in the manifest", bucket, got, err, want) + } + } } // Only the machine's runtime is the provider: a process on another credential, or with no machine, answers nobody. diff --git a/node-tools/module.json b/node-tools/module.json index 1daedcf..e8aad40 100644 --- a/node-tools/module.json +++ b/node-tools/module.json @@ -65,6 +65,8 @@ "bound" ], "reads": [ - "mesh-controller.assignments" + "mesh-controller.assignments", + "mesh-provisioner.provisions", + "mesh-provisioner.plans" ] }