From 24d0bae7939f19eaad7fe71b8f9a8171aa755453 Mon Sep 17 00:00:00 2001 From: jochen Date: Thu, 12 Nov 2026 13:02:03 +0100 Subject: [PATCH] Item 2 (join 11): the builder's bed declares no build-seat worker beside the SDK's, and answers the seat mesh-builds MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The SDK's DeclareAskWorkers now declares each queue's two workers, main's and the named asks' (accept..), and the puller takes from both; the bed declared main's worker again filtering both forms, which overlaps the named worker and the work queue refused ("filtered consumer not unique", 15 tests). The kind is a bed declaring by hand what the SDK declares: the builder's bed was the only one whose own consumer overlaps the SDK's, and now declares none. Behind it, the builder's seat server admits no caller of mesh-builds.reserved until the seat list holds mesh-builds' definition (A-278); the bed's seat-definitions answers it from the contracts module's own file. Builds: design 47 G §544, §600, A-115, A-278 Claude-Session: https://claude.ai/code/session_01NcbgfGKaxw984XyAPfLm4h --- .../catalogholder_integration_test.go | 17 +++++++++++++++++ .../mesh-delivery-builder/integration_test.go | 18 +++++------------- 2 files changed, 22 insertions(+), 13 deletions(-) diff --git a/modules/mesh-delivery-builder/cmd/mesh-delivery-builder/catalogholder_integration_test.go b/modules/mesh-delivery-builder/cmd/mesh-delivery-builder/catalogholder_integration_test.go index 6461d173..8c541bac 100644 --- a/modules/mesh-delivery-builder/cmd/mesh-delivery-builder/catalogholder_integration_test.go +++ b/modules/mesh-delivery-builder/cmd/mesh-delivery-builder/catalogholder_integration_test.go @@ -6,6 +6,8 @@ import ( "context" "encoding/json" "fmt" + "os" + "path/filepath" "strings" "sync" "testing" @@ -116,6 +118,21 @@ func (h *catalogHolder) buildSeats(t *testing.T, nc *nats.Conn, holders map[stri defs[d.Seat] = d } } + // A seat of this repository's contracts module that the SDK's copy does not hold (mesh-builds) is read from its own file. + for seat := range holders { + if _, ok := defs[seat]; ok { + continue + } + raw, err := os.ReadFile(filepath.Join("..", "..", "..", "mesh-delivery-contracts", "seats", seat, "seat.json")) + if err != nil { + t.Fatalf("the definition of the seat %s: %v", seat, err) + } + d, err := seatdef.Parse(raw) + if err != nil { + t.Fatalf("the definition of the seat %s: %v", seat, err) + } + defs[seat] = d + } for seat, on := range map[string]string{"node-build-go": "go", "node-build-node": "typescript", "node-build-image": seatdef.OnKindImage} { d := defs[seat] d.Acts = []seatdef.ActingRule{{Step: seatdef.StepBuild, On: on}} diff --git a/modules/mesh-delivery-builder/cmd/mesh-delivery-builder/integration_test.go b/modules/mesh-delivery-builder/cmd/mesh-delivery-builder/integration_test.go index 7a264025..2e15f614 100644 --- a/modules/mesh-delivery-builder/cmd/mesh-delivery-builder/integration_test.go +++ b/modules/mesh-delivery-builder/cmd/mesh-delivery-builder/integration_test.go @@ -165,18 +165,9 @@ func (f *fakeBuildModules) serve(t *testing.T, module string, nodes ...string) { if err := runner.DeclareAskWorkers(f.ctx, f.js, language, 30*time.Second); err != nil { t.Fatal(err) } - // Design 47 G §600: each queue's worker takes an ask in both forms, main's and the builder's (accept..builder); the - // build modules' helper above filters main's alone, so the worker is declared again with both. - stream, _ := sdkstep.AskStream(language) - for _, kind := range sdkstep.AskKinds { - worker, _ := sdkstep.AskWorker(language, kind) - main, _ := sdkstep.AskSubject(language, kind) - byBuilder, _ := sdkstep.AskSubjectBy(language, kind, sdkstep.AskerBuilder) - if _, err := f.js.CreateOrUpdateConsumer(f.ctx, stream, jetstream.ConsumerConfig{Durable: worker, FilterSubjects: []string{main, byBuilder}, - AckPolicy: jetstream.AckExplicitPolicy, AckWait: 30 * time.Second, MaxDeliver: 5}); err != nil { - t.Fatal(err) - } - } + // Design 47 G §544, §600: the build modules' helper declares each queue's two workers, main's and the named asks' + // (accept..), and the puller takes from both; the bed declares none of its own, since a worker filtering + // both forms overlaps the named worker, which a work queue refuses. put := func(key string, value any) (uint64, error) { raw, _ := value.(json.RawMessage) return kv.Put(f.ctx, key, raw) @@ -289,7 +280,8 @@ func startBedWith(t *testing.T, closed bool) *bed { // each have their durable consumer. b.catalog = newCatalogHolder(t, ctx, js, ctl) b.catalog.buildSeats(t, ctl, map[string]string{"node-build-go": testGo, "node-build-node": testNode, "node-build-image": testImage, - "git": "mesh-delivery-forge-bridge", "mesh-catalog": "mesh-delivery-indexer"}) // the floor's sources are the holders of git and mesh-catalog + "git": "mesh-delivery-forge-bridge", "mesh-catalog": "mesh-delivery-indexer", // the floor's sources are the holders of git and mesh-catalog + "mesh-builds": builds.BuilderModule}) // the builder's own seat, whose verb reserved it answers once its definition is read (A-115, A-278) readers := []string{"n1_" + builds.BuilderModule, "n2_" + builds.BuilderModule} // The seat mesh-module-assigner's holder is read from the seat's verb assignments, as the builder finds it at run time (A-119). assignerSub, err := ctl.Subscribe("mesh.seat.mesh-module-assigner.call.assignments.>", func(m *nats.Msg) {