From 9a3ead8fcd0e4dea55dd3d900da585087211dd6f Mon Sep 17 00:00:00 2001 From: jochen Date: Mon, 2 Nov 2026 12:18:38 +0100 Subject: [PATCH] Carry the plan entry only on a key no plan names A reader on an older mesh-sdk refuses a provision field it does not know, so a key a plan names carries no entry: such readers skip only a key ahead of its consumer's want, which they could never bind (issue 1126 review 1). Claude-Session: https://claude.ai/code/session_01NcbgfJ9Gum47zkFKWRaovL --- .../mesh-provisioner/cmd/mesh-provisioner/holder.go | 12 +++++++----- .../cmd/mesh-provisioner/holder_test.go | 7 ++++--- 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/modules/mesh-provisioner/cmd/mesh-provisioner/holder.go b/modules/mesh-provisioner/cmd/mesh-provisioner/holder.go index c1ddc169..fb00bf2b 100644 --- a/modules/mesh-provisioner/cmd/mesh-provisioner/holder.go +++ b/modules/mesh-provisioner/cmd/mesh-provisioner/holder.go @@ -203,21 +203,23 @@ func (h *Holder) ComposeNode(ctx context.Context, node string) (out Composed, er for _, p := range plan.Provisions { consumer := provisions.End{Module: module, Node: node} provider := provisions.End{Module: p.ProviderModule, Node: p.Provider} - // The key carries the plan entry it is composed from (issue 1126): the wanted build's where its plan names - // it, the newest's otherwise, so its provider binds it whichever plan the seat keeps. - entry := p pv := provisions.Provision{Provision: p.Provision, Local: p.Local, Consumer: consumer, Provider: provider, - DependsOn: provisions.DependsOn(consumer, p, h.providerPlan(p, node, atWants)), Plan: &entry} + DependsOn: provisions.DependsOn(consumer, p, h.providerPlan(p, node, atWants))} key, err := pv.Key() if err != nil { out.Problems = append(out.Problems, err.Error()) continue } if _, seen := needed[key]; !seen { - needed[key] = pv if i == 1 { + // A key no plan names carries the newest build's entry, so its provider binds it (issue 1126). Only + // it: a reader on an older mesh-sdk refuses a field it does not know, and skips then only a key it + // could never bind anyway. + entry := p + pv.Plan = &entry ahead[key] = module } + needed[key] = pv } // Its credential is a provision of its own, the vault's (clause 6): on the consumer's node for a value of the // consumer's own, on the provider's for the provider's one shared value. diff --git a/modules/mesh-provisioner/cmd/mesh-provisioner/holder_test.go b/modules/mesh-provisioner/cmd/mesh-provisioner/holder_test.go index 30a7a8bc..d737cc94 100644 --- a/modules/mesh-provisioner/cmd/mesh-provisioner/holder_test.go +++ b/modules/mesh-provisioner/cmd/mesh-provisioner/holder_test.go @@ -544,7 +544,7 @@ func TestAProvidersOutcomeIsReadPerOffer(t *testing.T) { // Issue 1126 review 1 (mcp-endpoint asked on ace and shanks, 2026-11-02 11:56): a requirement the consumer's newest build // adds is keyed before its want, and the plan the seat keeps is its wanted build's, which names it not; the key carries // the plan entry it was composed from, so the provider binds it, and its why says no plan names it yet. A key its -// wanted plan names carries that plan's entry. +// wanted plan names carries none. func TestAKeyAheadOfItsWantCarriesItsPlanEntryAndSaysWhy(t *testing.T) { m := newMesh() m.atWant["g14"] = map[string]catalogue.Plan{"gitea": planOf(pgDB)} @@ -559,8 +559,9 @@ func TestAKeyAheadOfItsWantCarriesItsPlanEntryAndSaysWhy(t *testing.T) { if kc.State != provisions.Asked || !strings.Contains(kc.Why, "no plan names it") { t.Errorf("the key ahead of its want: %s %q", kc.State, kc.Why) } - if pg := m.state(t, "g14.gitea.postgres-database"); pg.Plan == nil || pg.Plan.ProviderModule != "postgres" || - strings.Contains(pg.Why, "no plan names it") { + // A key a plan names carries no entry: a reader on an older mesh-sdk, which refused a field it did not know, reads it + // still, and skips only a key ahead of its want, which it could never bind (review 1). + if pg := m.state(t, "g14.gitea.postgres-database"); pg.Plan != nil || strings.Contains(pg.Why, "no plan names it") { t.Errorf("the planned key: %+v", pg) } }