BG2, BG3: the three build modules check the asker against the seat list and pull the named worker

The runtime source is *steprun.SeatAsks (named worker not bound is said through the module's journal); the callers follow
the seat list (steprun.SeatListCallers).

Builds: design 47 G §543, §544, A-163, A-170

Claude-Session: https://claude.ai/code/session_01NcbgfGKaxw984XyAPfLm4h
This commit is contained in:
2026-11-12 05:44:46 +01:00
parent 51df346a23
commit 584fc94baa
10 changed files with 40 additions and 6 deletions
@@ -56,7 +56,10 @@ func (m *Module) askSteps(steps []StepTool) steprun.AskSteps {
// Puller is the module's pull of its seat's asks, on source (the runtime's seat pull when nil).
func (m *Module) Puller(steps []StepTool, source steprun.AskSource) *steprun.Puller {
if source == nil {
source = steprun.SeatAsks{Language: sdkstep.AskGo}
source = &steprun.SeatAsks{Language: sdkstep.AskGo, Logf: m.Say}
if m.Callers == nil {
m.Callers = steprun.SeatListCallers(sdkstep.AskGo, m.Say)
}
}
capacity := m.Capacity
// The capacity's own change wakes the puller (issue 1887): the runtime's watch of the config value as mesh-config
@@ -88,7 +91,7 @@ func (m *Module) Puller(steps []StepTool, source steprun.AskSource) *steprun.Pul
if m.SayEvent != nil {
say = steprun.SayOn(sdkstep.AskGo, m.Node, m.SayEvent)
}
return &steprun.Puller{Source: source, Language: sdkstep.AskGo, Say: say, Node: m.Node, Put: m.Steps, PausePut: m.Pauses, Load: load, ForgetPause: m.ForgetPause, WatchPauses: m.WatchPauses, PauseKeys: m.ReadPauses.Keys,
return &steprun.Puller{Source: source, Language: sdkstep.AskGo, Say: say, Callers: m.Callers, Node: m.Node, Put: m.Steps, PausePut: m.Pauses, Load: load, ForgetPause: m.ForgetPause, WatchPauses: m.WatchPauses, PauseKeys: m.ReadPauses.Keys,
Capacity: capacity, SettingsFile: settings, WatchConfig: watch, CoresPerStep: cores, BuildHours: hours, Logf: m.Say, Has: m.Has,
Run: func(ctx context.Context, a sdkstep.StepAsk) (any, error) {
if err := m.Check(ctx); err != nil {
@@ -52,7 +52,11 @@ func TestTheModuleTakesADeliveryAskBeforeAnEarlierCheck(t *testing.T) {
first := deliveryAsk()
for _, a := range []sdkstep.StepAsk{check, first} {
raw, _ := sdkstep.EncodeStepAsk(a)
// A build rides main's subject, any other kind a named asker's (design 47 G §543).
subject, _ := sdkstep.AskSubject(a.Language, a.Kind)
if a.Kind != sdkstep.AskDelivery {
subject, _ = sdkstep.AskSubjectBy(a.Language, a.Kind, "mesh-delivery-checker")
}
if _, err := js.Publish(ctx, subject, raw); err != nil {
t.Fatal(err)
}
@@ -11,11 +11,15 @@ import (
func TestPullerSaysTheSeatsEventsOnItsNodesSubject(t *testing.T) {
var subjects []string
m := &Module{Node: "ace", Capacity: func() int { return 0 },
Callers: func(kind string) ([]string, bool) { return []string{"mesh-pipeline-runner"}, kind == "step" },
SayEvent: func(subject string, _ any, _ string) error { subjects = append(subjects, subject); return nil }}
p := m.Puller(nil, steprun.NewFakeAsks())
if p.Say == nil {
t.Fatal("the puller says no event")
}
if got, ok := p.Callers("step"); !ok || len(got) != 1 {
t.Fatalf("the puller checks the callers of %v, %v, not the module's", got, ok)
}
seat, _ := sdkstep.BuildSeat(sdkstep.AskGo)
for _, event := range []string{"ask-taken", "step-progress", "step-ended"} {
if err := p.Say(event, nil, "id"); err != nil {
@@ -24,6 +24,9 @@ const CheckRound = 10 * time.Minute
// Module is the Go build module's one running state: the node it runs on, its recipe, the toolchain guard and the
// states it writes (toolchains, steps).
type Module struct {
// Callers says which seats the build seat's definition lists as callers of an accepted kind (steprun.SeatListCallers when
// the module pulls through its runtime; nil in a test checks no named asker): design 47 G §543, A-163.
Callers func(kind string) ([]string, bool)
// SayEvent publishes an event of the go build seat on a seat subject (stdio.SeatPublish; nil says none, a test's): the
// puller's ask-taken, step-progress and step-ended (design 47 G §496, §602).
SayEvent func(subject string, body any, id string) error
@@ -37,7 +37,10 @@ func (m *Module) askSteps(steps []StepTool) steprun.AskSteps {
// Puller is the module's pull of its seat's asks, on source (the runtime's seat pull when nil).
func (m *Module) Puller(steps []StepTool, source steprun.AskSource) *steprun.Puller {
if source == nil {
source = steprun.SeatAsks{Language: sdkstep.AskImage}
source = &steprun.SeatAsks{Language: sdkstep.AskImage, Logf: m.Say}
if m.Callers == nil {
m.Callers = steprun.SeatListCallers(sdkstep.AskImage, m.Say)
}
}
capacity := m.Capacity
// The capacity's own change wakes the puller (issue 1887): the runtime's watch of the config value as mesh-config
@@ -66,7 +69,7 @@ func (m *Module) Puller(steps []StepTool, source steprun.AskSource) *steprun.Pul
if m.SayEvent != nil {
say = steprun.SayOn(sdkstep.AskImage, m.Node, m.SayEvent)
}
return &steprun.Puller{Source: source, Language: sdkstep.AskImage, Say: say, Node: m.Node, Put: m.Steps, PausePut: m.Pauses, Load: load, ForgetPause: m.ForgetPause, WatchPauses: m.WatchPauses, PauseKeys: m.ReadPauses.Keys,
return &steprun.Puller{Source: source, Language: sdkstep.AskImage, Say: say, Callers: m.Callers, Node: m.Node, Put: m.Steps, PausePut: m.Pauses, Load: load, ForgetPause: m.ForgetPause, WatchPauses: m.WatchPauses, PauseKeys: m.ReadPauses.Keys,
Capacity: capacity, SettingsFile: settings, WatchConfig: watch, CoresPerStep: cores, BuildHours: hours, Eligible: m.Eligible, Logf: m.Say,
Run: func(ctx context.Context, a sdkstep.StepAsk) (any, error) {
if err := m.Check(ctx); err != nil {
@@ -11,11 +11,15 @@ import (
func TestPullerSaysTheSeatsEventsOnItsNodesSubject(t *testing.T) {
var subjects []string
m := &Module{Node: "ace", Capacity: func() int { return 0 },
Callers: func(kind string) ([]string, bool) { return []string{"mesh-pipeline-runner"}, kind == "step" },
SayEvent: func(subject string, _ any, _ string) error { subjects = append(subjects, subject); return nil }}
p := m.Puller(nil, steprun.NewFakeAsks())
if p.Say == nil {
t.Fatal("the puller says no event")
}
if got, ok := p.Callers("step"); !ok || len(got) != 1 {
t.Fatalf("the puller checks the callers of %v, %v, not the module's", got, ok)
}
seat, _ := sdkstep.BuildSeat(sdkstep.AskImage)
for _, event := range []string{"ask-taken", "step-progress", "step-ended"} {
if err := p.Say(event, nil, "id"); err != nil {
@@ -20,6 +20,9 @@ const CheckRound = 10 * time.Minute
// Module is the image build module's one running state.
type Module struct {
// Callers says which seats the build seat's definition lists as callers of an accepted kind (steprun.SeatListCallers when
// the module pulls through its runtime; nil in a test checks no named asker): design 47 G §543, A-163.
Callers func(kind string) ([]string, bool)
// SayEvent publishes an event of the image build seat on a seat subject (stdio.SeatPublish; nil says none, a test's): the
// puller's ask-taken, step-progress and step-ended (design 47 G §496, §602).
SayEvent func(subject string, body any, id string) error
@@ -47,7 +47,10 @@ func (m *Module) askSteps(steps []StepTool) steprun.AskSteps {
// Puller is the module's pull of its seat's asks, on source (the runtime's seat pull when nil).
func (m *Module) Puller(steps []StepTool, source steprun.AskSource) *steprun.Puller {
if source == nil {
source = steprun.SeatAsks{Language: sdkstep.AskNode}
source = &steprun.SeatAsks{Language: sdkstep.AskNode, Logf: m.Say}
if m.Callers == nil {
m.Callers = steprun.SeatListCallers(sdkstep.AskNode, m.Say)
}
}
capacity := m.Capacity
// The capacity's own change wakes the puller (issue 1887): the runtime's watch of the config value as mesh-config
@@ -76,7 +79,7 @@ func (m *Module) Puller(steps []StepTool, source steprun.AskSource) *steprun.Pul
if m.SayEvent != nil {
say = steprun.SayOn(sdkstep.AskNode, m.Node, m.SayEvent)
}
return &steprun.Puller{Source: source, Language: sdkstep.AskNode, Say: say, Node: m.Node, Put: m.Steps, PausePut: m.Pauses, Load: load, ForgetPause: m.ForgetPause, WatchPauses: m.WatchPauses, PauseKeys: m.ReadPauses.Keys,
return &steprun.Puller{Source: source, Language: sdkstep.AskNode, Say: say, Callers: m.Callers, Node: m.Node, Put: m.Steps, PausePut: m.Pauses, Load: load, ForgetPause: m.ForgetPause, WatchPauses: m.WatchPauses, PauseKeys: m.ReadPauses.Keys,
Capacity: capacity, SettingsFile: settings, WatchConfig: watch, CoresPerStep: cores, BuildHours: hours, Logf: m.Say,
Run: func(ctx context.Context, a sdkstep.StepAsk) (any, error) {
if err := m.Prepare(ctx); err != nil {
@@ -11,11 +11,15 @@ import (
func TestPullerSaysTheSeatsEventsOnItsNodesSubject(t *testing.T) {
var subjects []string
m := &Module{Node: "ace", Capacity: func() int { return 0 },
Callers: func(kind string) ([]string, bool) { return []string{"mesh-pipeline-runner"}, kind == "step" },
SayEvent: func(subject string, _ any, _ string) error { subjects = append(subjects, subject); return nil }}
p := m.Puller(nil, steprun.NewFakeAsks())
if p.Say == nil {
t.Fatal("the puller says no event")
}
if got, ok := p.Callers("step"); !ok || len(got) != 1 {
t.Fatalf("the puller checks the callers of %v, %v, not the module's", got, ok)
}
seat, _ := sdkstep.BuildSeat(sdkstep.AskNode)
for _, event := range []string{"ask-taken", "step-progress", "step-ended"} {
if err := p.Say(event, nil, "id"); err != nil {
@@ -25,6 +25,9 @@ const CheckRound = 10 * time.Minute
// Module is the Node build module's one running state: the node it runs on, its recipe, the toolchain guard, the
// toolchain directory and the states it writes (toolchains, steps).
type Module struct {
// Callers says which seats the build seat's definition lists as callers of an accepted kind (steprun.SeatListCallers when
// the module pulls through its runtime; nil in a test checks no named asker): design 47 G §543, A-163.
Callers func(kind string) ([]string, bool)
// SayEvent publishes an event of the node build seat on a seat subject (stdio.SeatPublish; nil says none, a test's): the
// puller's ask-taken, step-progress and step-ended (design 47 G §496, §602).
SayEvent func(subject string, body any, id string) error