From 24dd2ec29acdffd6e4661ff9f6ab70461ce974f8 Mon Sep 17 00:00:00 2001 From: jochen Date: Wed, 4 Nov 2026 14:22:31 +0100 Subject: [PATCH] DLV-F5r (assigner's case): the indexer's runtime answering after the assigner asked is followed within the bound MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A case of the assigner's existing whole-module test: the indexer's first views are held until the assigner has started, and the wants are written from what they answer (ADR 0621 §3). Claude-Session: https://claude.ai/code/session_01JG73KJNrH5EgFXMKKYSrig --- .../mesh-delivery-assigner/integration_test.go | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/modules/mesh-delivery-assigner/cmd/mesh-delivery-assigner/integration_test.go b/modules/mesh-delivery-assigner/cmd/mesh-delivery-assigner/integration_test.go index 54a3106d..d37e5243 100644 --- a/modules/mesh-delivery-assigner/cmd/mesh-delivery-assigner/integration_test.go +++ b/modules/mesh-delivery-assigner/cmd/mesh-delivery-assigner/integration_test.go @@ -354,6 +354,11 @@ func (b *bed) get(t *testing.T, bucket, key string) []byte { // raises the condition naming g14, web and the canary rule; once ace runs F healthy, g14's first want names F and the condition is // cleared. func TestWantsAreWrittenAndNoDifferenceIs(t *testing.T) { + // DLV-F5r (ADR 0621 §3): the indexer's runtime starts together with the assigner and answers its first views only + // after the assigner asked; within the bound the assigner writes the wants from what they answer. + up := make(chan struct{}) + indexerLate = up + t.Cleanup(func() { indexerLate = nil }) b := startBed(t, "") fNew, fOld := delivery.SourcePrefix2+strings.Repeat("b", 64), delivery.SourcePrefix2+strings.Repeat("a", 64) digest := b.manifest(t, "web", `{"module":"web","version":"1"}`) @@ -381,6 +386,7 @@ func TestWantsAreWrittenAndNoDifferenceIs(t *testing.T) { } b.compose(t, "shanks", 'a') b.start(t) + close(up) wkey, _ := delivery.WantKey("ace", "web") want, err := delivery.DecodeWant(b.get(t, delivery.AssignerWantsBucket, wkey)) @@ -1269,6 +1275,10 @@ func placementSubjects() []string { return out } +// indexerLate, when set before the bed is made, holds every answer of the indexer's first views until it is closed: the +// indexer's runtime started together with the assigner's, answering after the assigner asked (DLV-F5r). +var indexerLate chan struct{} + // serveIndexer is the indexer as the owner of its manifests and modules (ADR 0615, ADR 0621): its buckets, which a test // fills as the indexer writes them; its views family said by the views emitter onto INDEXER_VIEWS, read by the // assigner's durable consumer; and its first-view tools manifests and modules answered from the buckets at their marks. @@ -1295,7 +1305,15 @@ func serveIndexer(t *testing.T, b *bed, nc *nats.Conn) { if err := em.Start(b.ctx, state, kv, nil); err != nil { t.Fatal(err) } + late := indexerLate sub, err := nc.Subscribe("mesh.mod.mesh-delivery-indexer.call."+state+".>", func(m *nats.Msg) { + if late != nil { // its runtime comes up after the assigner started (DLV-F5r) + select { + case <-late: + case <-b.ctx.Done(): + return + } + } var args struct { After string `json:"after"` }