Node-engine: the whole seat-list case proves a fresh node asks the seat over its own grant while its own composition and web are held, no part needs letting through (ruling 15:1x b, ADR 0636 §1; issue 1966)

Claude-Session: https://claude.ai/code/session_01NcbgfFSnn24M3GcqttoU7i
This commit is contained in:
2026-11-05 14:57:50 +01:00
parent df44d21c82
commit cdd428a7d8
@@ -60,6 +60,8 @@ type itBed struct {
mu sync.Mutex
// seatSilent makes the stand-in of the seat mesh-catalog refuse the seat list (it is served from the start otherwise).
seatSilent atomic.Bool
// seatAsked counts the node's asks of the stand-in seat, answered or refused: the node reached the bus and asked.
seatAsked atomic.Int32
findings nats.KeyValue
}
@@ -904,6 +906,7 @@ func (b *itBed) standInSeat() {
Seat string `json:"seat"`
}
_ = json.Unmarshal(m.Data, &q)
b.seatAsked.Add(1)
var result any
switch {
case b.seatSilent.Load():
@@ -979,6 +982,17 @@ func TestNatsANodeThatCannotReadTheSeatListActsOnNothingNew(t *testing.T) {
defer clock.mu.Unlock()
return len(clock.fire) > 0
})
// A fresh node, nothing applied, reaches the bus and asks the seat while its own composition is held: the read needs
// the bus the node composes from and the grant it has from its start, nothing of what the hold keeps back.
if b.seatAsked.Load() == 0 {
t.Fatal("the fresh node did not ask the seat for its list while its own composition was held")
}
within(t, 5*time.Second, "the fresh node did not say it holds web and its own composition for the unread list", func() bool {
b.mu.Lock()
defer b.mu.Unlock()
said := strings.Join(b.said, "\n")
return strings.Contains(said, selfcompose.WaitsForTheSeatListOwn) && strings.Contains(said, selfcompose.WaitsForTheSeatList)
})
if b.file("web") != "" {
t.Fatalf("the node applied web before it read the seat list: %q", b.file("web"))
}