assigner: a reads statement older than a reads-changed heard does not stand (issue 1975)
The assigner keeps each reads-changed event it hears beside its statement (enginereads.Keeper.HeardChanged), reads a node as the event says while its statement is behind it, and asks again until the statement is as new. Builds: issue 1975 note 4 (the lead's handover; no design line) Claude-Session: https://claude.ai/code/session_01NcbgfGKaxw984XyAPfLm4h
This commit is contained in:
@@ -569,6 +569,10 @@ func hearReadsChanged(ctx context.Context, js jetstream.JetStream, hub *process.
|
||||
logf("%s holds what is not %s, and %s is asked again all the same: %v", m.Subject(), enginereads.Event, node, err)
|
||||
reads.AskNode(node, enginereads.Event+" that does not read")
|
||||
default:
|
||||
// What the event says is kept first: a statement older than it does not stand while the node is asked again.
|
||||
if e, derr := enginereads.DecodeChanged(m.Data()); derr == nil {
|
||||
reads.HeardChanged(e)
|
||||
}
|
||||
reads.AskNode(node, enginereads.Event)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -317,6 +317,25 @@ func TestAnAnswerCountsOnlyForTheAskingItAnswered(t *testing.T) {
|
||||
if asked["ace"] != 2 {
|
||||
t.Errorf("ace, back online, was asked %d times, want 2", asked["ace"])
|
||||
}
|
||||
// Issue 1975: ace's engine answered its bootstrapped seats, then stated the full list and said so; an answer older
|
||||
// than that event does not stand: the rules read what the event says, and the node is asked until it is as new.
|
||||
stale := true
|
||||
bootstrapped := func(node, _ string, _ any) (json.RawMessage, error) {
|
||||
if stale {
|
||||
stale = false
|
||||
return json.Marshal(nodeengine.ManifestReadsAnswer{V: 1, Node: node, ManifestReads: []string{"seat:a"}, StatedAt: "2026-11-12T01:14:36.498Z"})
|
||||
}
|
||||
return json.Marshal(nodeengine.ManifestReadsAnswer{V: 1, Node: node, ManifestReads: []string{"seat:a", "seat:b"}, StatedAt: "2026-11-12T01:14:39.001Z"})
|
||||
}
|
||||
rk := &enginereads.Keeper{Call: bootstrapped, Sync: true}
|
||||
rk.AskNode("ace", "the assigner started")
|
||||
rk.HeardChanged(nodeengine.ManifestReadsChangedEvent{V: 1, Node: "ace", Why: enginereads.ReadsStarted, At: "2026-11-12T01:14:39.002Z", ManifestReads: []string{"seat:a", "seat:b"}})
|
||||
rp := &passer{w: w, reads: rk, online: map[string]bool{"ace": true}}
|
||||
rn := w.nodes(nil, nil)
|
||||
rp.engineReads(rn)
|
||||
if !slices.Equal(rn.Reads["ace"], []string{"seat:a", "seat:b"}) {
|
||||
t.Errorf("the rules read the statement older than the event heard: %v", rn.Reads["ace"])
|
||||
}
|
||||
// ADR 0668 §3 (review round 1): a node whose engine answers nothing while its machine is heard is asked again at each
|
||||
// pass once its ask ended, and past five minutes is the finding call-unanswered, cleared once it answers; none is
|
||||
// written while its machine is away.
|
||||
|
||||
Reference in New Issue
Block a user