A consumer beside a held provider is told what it serves without the names it does not compose, never their placeholders (issue 1921, milestone 47/G)
The provider held on its machine is composed apart, so no module of the composed set serves the provision; its
manifest's served values reached the consumer's binding raw and the binding refused the consumer for a
${bound:route:name-web} it does not require (the group check of 8a80e8e86858 on novox, mesh-build-node beside a held
gitea). Each such key is now left out and said on the need, as a provider elsewhere leaves it out (ADR 0346).
Claude-Session: https://claude.ai/code/session_01NcbgfFSnn24M3GcqttoU7i
This commit is contained in:
@@ -4,6 +4,8 @@ import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"maps"
|
||||
"slices"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
@@ -240,7 +242,14 @@ func resolutionCompose(r mcat.Resolution, with mcat.Rendering, owner map[string]
|
||||
}
|
||||
if answered {
|
||||
r.Needs[i].Serves = serves
|
||||
continue
|
||||
}
|
||||
// No module of the composed set serves it: its provider is held on this machine (composed apart, as what runs of
|
||||
// it), and offers what its manifest serves. None of its own names is composed here, so a key that names one is
|
||||
// left out and said on the need, as a provider elsewhere leaves it out (ServedLeftOut, novox/hq ADR 0346 §3),
|
||||
// never handed to the consumer as a placeholder its binding then refuses (issue 1921, novox: "mesh-build-node has
|
||||
// a file that says ${bound:route:name-web}, and mesh-build-node does not require route").
|
||||
r.Needs[i].Serves, r.Needs[i].LeftOut = withoutOwnNames(r.Needs[i], r.Node)
|
||||
}
|
||||
|
||||
// Once, from every module's listens -- not per module. A module receiving only its own ports
|
||||
@@ -2526,3 +2535,26 @@ func resolutionGeneratedHere(r mcat.Resolution, with mcat.Rendering) (map[string
|
||||
}
|
||||
return generated, nil
|
||||
}
|
||||
|
||||
// withoutOwnNames is what a need's provider serves without each key whose value names one of the provider's own composed
|
||||
// names (${bound:…}), and the need's left-out keys with each such key said: a provider not composed in this set
|
||||
// composes none of its names here.
|
||||
func withoutOwnNames(n mcat.Needed, node string) (map[string]any, []string) {
|
||||
var asking []string
|
||||
for _, key := range sortedAnyKeys(n.Serves) {
|
||||
if text, ok := n.Serves[key].(string); ok && bound.MatchString(text) {
|
||||
asking = append(asking, key)
|
||||
}
|
||||
}
|
||||
if len(asking) == 0 {
|
||||
return n.Serves, n.LeftOut
|
||||
}
|
||||
out := maps.Clone(n.Serves)
|
||||
said := slices.Clone(n.LeftOut)
|
||||
for _, key := range asking {
|
||||
delete(out, key)
|
||||
said = append(said, fmt.Sprintf("%s serves %s without %q: it names %s, and %s composes no names of %s, which it "+
|
||||
"holds (novox/hq ADR 0346)", n.Module, n.Name, key, bound.FindString(n.Serves[key].(string)), orHere(node), n.Module))
|
||||
}
|
||||
return out, said
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package resolution
|
||||
|
||||
import (
|
||||
"slices"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
@@ -75,6 +76,29 @@ func TestAConsumerBesideTheProviderIsServedItsName(t *testing.T) {
|
||||
if strings.Contains(binding, "${bound:") {
|
||||
t.Fatalf("a placeholder reached the consumer:\n%s", binding)
|
||||
}
|
||||
// Issue 1921 (the group check of 8a80e8e86858, novox): the provider held on this machine (composed apart, as what runs
|
||||
// of it) is not in the composed set, so none of its own names is composed here. The consumer beside it is told
|
||||
// what it serves without the keys that name them, each said on the need, never the placeholder: its binding refused
|
||||
// the consumer with "has a file that says ${bound:route:name-web}, and lab does not require route".
|
||||
held, err := Resolve(shelf(minimalRouteProxy(), m, consumer), []string{"route-proxy", "forge", "lab"}, node, mcat.World{})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
held.Modules = slices.DeleteFunc(slices.Clone(held.Modules), func(m mcat.Manifest) bool { return m.Module == "forge" })
|
||||
out, err = Declaration(held, mcat.Rendering{})
|
||||
if err != nil {
|
||||
t.Fatalf("a consumer beside a held provider: %v", err)
|
||||
}
|
||||
for _, r := range out {
|
||||
if c, _ := r["content"].(string); r["path"] == "/var/lib/lab/package-registry.json" && (strings.Contains(c, "${bound:") || !strings.Contains(c, "npm-path")) {
|
||||
t.Fatalf("the binding beside a held provider:\n%s", c)
|
||||
}
|
||||
}
|
||||
for _, n := range held.Needs {
|
||||
if n.Name == "npm-package-registry" && (len(n.LeftOut) != 1 || !strings.Contains(n.LeftOut[0], `"public-root"`)) {
|
||||
t.Fatalf("the need beside a held provider says not what was left out: %+v", n)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// From another machine, the provider's served values carry what that machine composed, and a key it
|
||||
|
||||
Reference in New Issue
Block a user