Take the catalogue's composition rules into the node-engine

ADR 0593 §7: the composer with its refusals leaves mesh-sdk, so mesh-sdk
carries no composition rule. The catalogue functions only the
node-engine's composition reaches (Resolve, Resolution's Compose,
Declaration, DataItems, LeftOut, Rules and the rest, the settings,
placeholder and template refusals, the rendering helpers) are copied
with their tests into internal/compose/resolution; a method of a
mesh-sdk shape becomes a function taking it first. The composition
calls its own copies, and the captured catalogue its tests read lives
here now, shared by mesh-compose's tests.

Claude-Session: https://claude.ai/code/session_01NcbgfJ9Gum47zkFKWRaovL
This commit is contained in:
2026-11-02 19:15:55 +01:00
parent be0226b624
commit d68e241724
686 changed files with 35703 additions and 80 deletions
+7 -6
View File
@@ -11,6 +11,7 @@ import (
"strings"
"git.novox.be/novox/mesh-sdk/go/catalogue"
"github.com/novox/mesh-host/internal/compose/resolution"
)
// Mode says what a composition does about what a send would make. Both modes read what the Input holds and make nothing; they
@@ -64,7 +65,7 @@ func (c *composer) grantsFor(node string) ([]catalogue.Grant, []catalogue.Overfl
return nil, nil, nil, nil, fmt.Errorf("what %s asked of %s cannot be read: %w", s.Consumer, s.Provision, err)
}
plan := resolved.Plan
values, asks, err := plan.ContributionsFrom(s.Provision, s.ConsumerModule, resolved.Settings)
values, asks, err := resolution.ContributionsFrom(plan, s.Provision, s.ConsumerModule, resolved.Settings)
if err != nil {
return nil, nil, nil, nil, err
}
@@ -73,13 +74,13 @@ func (c *composer) grantsFor(node string) ([]catalogue.Grant, []catalogue.Overfl
if err != nil {
return nil, nil, nil, nil, err
}
values = catalogue.AtPublishedPort(values, s.ConsumerModule, consumer.Ports[s.ConsumerModule])
values = resolution.AtPublishedPort(values, s.ConsumerModule, consumer.Ports[s.ConsumerModule])
from := s.ConsumerModule
if !asks {
// That module no longer wants this: left empty, which is how a login is withdrawn rather than kept working for ever.
from = ""
}
if bound := plan.BindsFrom(s.Provision, s.ConsumerModule, s.Local); from != "" && !slices.Contains(bound, node) {
if bound := resolution.BindsFrom(plan, s.Provision, s.ConsumerModule, s.Local); from != "" && !slices.Contains(bound, node) {
// It still asks, and not of this node: withdrawn exactly as a credential nobody asks for, and said.
from = ""
unbound = append(unbound, catalogue.Unbound{Provision: s.Provision, Provider: node,
@@ -294,7 +295,7 @@ func (c *composer) ownSecretsFor(node Node, plan catalogue.Resolution, handing c
foreseen[module][name] = true
}
for _, m := range plan.Modules {
if handing.Handing(m) {
if resolution.Handing(handing, m) {
continue
}
// A secret family is never made (novox/hq ADR 0283): each member a person gave on this machine is placed, and one not
@@ -391,7 +392,7 @@ type CoreBoxWanted struct {
func coreModulesOf(modules []catalogue.Manifest, handed func(catalogue.Manifest) bool) map[string][]string {
out := map[string][]string{}
for _, m := range modules {
if !catalogue.CarriesVaultSealed(m.Module) || (handed != nil && handed(m)) {
if !resolution.CarriesVaultSealed(m.Module) || (handed != nil && handed(m)) {
continue
}
var names []string
@@ -424,7 +425,7 @@ func sealingKeyValid(raw string) error {
// sealing key, or one whose key is not a key, leaves its module out, said.
func (c *composer) coreBoxesFor(node Node, modules []catalogue.Manifest, handing catalogue.Rendering) (
sealed map[string]map[string]json.RawMessage, notPlaced map[string]string, wanted []CoreBoxWanted) {
core := coreModulesOf(modules, func(m catalogue.Manifest) bool { return handing.Handing(m) })
core := coreModulesOf(modules, func(m catalogue.Manifest) bool { return resolution.Handing(handing, m) })
sealed, notPlaced = map[string]map[string]json.RawMessage{}, map[string]string{}
mods := make([]string, 0, len(core))
for m := range core {