Join 11: the merged heads compile where no area's fix is owed

The join's importers name the delivery repository's moved contracts and sdk
(MV1), node-tools' tests use mesh-sdk's gate, the duplicate node-engine claim
rule of the reader release gives way to G's, and the assigner names its first
watched branch, never a constant. The seat holders' AnswerSeat callers are
area 6's.

Builds: design 47 G join 11 (merge of fix round 11)

Claude-Session: https://claude.ai/code/session_01NcbgfGKaxw984XyAPfLm4h
This commit is contained in:
2026-11-12 10:41:44 +01:00
parent 6457cf1eba
commit a1fbd5dfa7
6 changed files with 14 additions and 30 deletions
@@ -36,15 +36,15 @@ func candidateKeyOf(run meshwants.StepRun) (string, error) {
}
// machinesFor are the machines of a step (A-252): the nodes whose placement of the module names the step's branch (a placement
// naming none is the trunk's); a branch that is not watched takes the nodes placing the module on the trunk. In name order.
func machinesFor(placed map[string]map[string]string, module, branch string, watched bool) []string {
// naming none is the trunk's, trunk the first watched branch); a branch that is not watched takes the nodes placing the module on the trunk. In name order.
func machinesFor(placed map[string]map[string]string, module, branch, trunk string, watched bool) []string {
if branch == "" || !watched {
branch = trunkBranch
branch = trunk
}
var out []string
for node, b := range placed[module] {
if b == "" {
b = trunkBranch
b = trunk
}
if b == branch {
out = append(out, node)
@@ -56,7 +56,7 @@ func machinesFor(placed map[string]map[string]string, module, branch string, wat
// machinesOf are the machines of a composition step in the world's assignments.
func (w *world) machinesOf(module, branch string) []string {
return machinesFor(w.placedBranches(), module, branch, w.holdsBranch(branch))
return machinesFor(w.placedBranches(), module, branch, w.trunkName(), w.holdsBranch(branch))
}
// nodeInput is one machine's input: its bytes, or why the node gave none, or that it is away.
@@ -43,11 +43,11 @@ func TestTheMachinesOfAStep(t *testing.T) {
{"gone", false, "ace novox"},
{"", true, "ace novox"},
} {
if got := strings.Join(machinesFor(placed, "m", c.branch, c.watched), " "); got != c.want {
if got := strings.Join(machinesFor(placed, "m", c.branch, trunkBranch, c.watched), " "); got != c.want {
t.Errorf("branch %q watched %v: %q, want %q", c.branch, c.watched, got, c.want)
}
}
if got := machinesFor(placed, "none", "main", true); len(got) != 0 {
if got := machinesFor(placed, "none", "main", trunkBranch, true); len(got) != 0 {
t.Errorf("a module placed nowhere has machines %v", got)
}
}
@@ -476,13 +476,14 @@ func heardPresence(a *awayNodes, away bool, m jetstream.Msg, logf func(string, .
}
}
// trunkOf is the trunk's catalog half the assigner's views hold, or false while none is held.
func trunkOf(iv *catalogViews) func() (mcc.Half, bool) {
// trunkOf is the trunk's catalog half the assigner's views hold, trunk naming the first watched branch, or false while none is
// held.
func trunkOf(iv *catalogViews, trunk func() string) func() (mcc.Half, bool) {
return func() (mcc.Half, bool) {
if iv == nil || iv.h == nil {
return mcc.Half{}, false
}
h, ok := iv.h.views()[trunkBranch]
h, ok := iv.h.views()[trunk()]
return h, ok
}
}
@@ -662,7 +662,7 @@ func follow(ctx context.Context, js jetstream.JetStream, nc process.Subscriber,
// The composition step (design 47 G §22, §354): the seat mesh-wants' accepted kind step, run by one run ask per machine.
if bus != nil && js != nil && inputs != nil && p.publishWants != nil {
run := &compositionRun{inputs: &compositionInputs{machines: w.machinesOf, call: bus.CallKeptOn}, keeper: inputs, call: bus.CallKept,
trunk: trunkOf(iv), running: w.runningOf, away: away, put: runAskPublisher(js), ends: ends, ask: bus.Call, now: time.Now, logf: logger.Printf}
trunk: trunkOf(iv, w.trunkName), running: w.runningOf, away: away, put: runAskPublisher(js), ends: ends, ask: bus.Call, now: time.Now, logf: logger.Printf}
steps := &compositionSteps{node: thisNode, say: p.publishWants, run: run.run, now: time.Now, logf: logger.Printf, asker: stepAsker}
if err := serveCompositionSteps(ctx, nc, steps); err != nil {
logger.Printf("the composition step is not heard, so no composition step runs until the assigner starts again: %v", err)
@@ -8028,22 +8028,3 @@ func ObjectsCatalogueProblems(shelf catalogue.Shelf) []string {
}
return problems
}
// NodeEngineSeat is the seat the node-engine's module claims as one module (design 47 G §508).
const NodeEngineSeat = "node-engine"
// nodeEngineClaimProblems refuses a revision in which more than one module claims the seat node-engine, naming them: one
// module claims it, the node-engine's own (design 47 G §508), in place of refusing every claim.
func nodeEngineClaimProblems(shelf catalogue.Shelf) []string {
var holders []string
for module, m := range shelf {
if slices.ContainsFunc(m.Claims, func(c catalogue.Claim) bool { return c.Name == NodeEngineSeat }) {
holders = append(holders, module)
}
}
if len(holders) < 2 {
return nil
}
slices.Sort(holders)
return []string{fmt.Sprintf("%s claim the seat %s, which one module claims (design 47 G §508)", strings.Join(holders, " and "), NodeEngineSeat)}
}
@@ -3,7 +3,9 @@ package main
import (
"encoding/json"
"errors"
"fmt"
"git.novox.be/novox/mesh-sdk/go/buscalls"
"strings"
"testing"
"time"