The spec says that readers may only send an ACKNACK message in response to a HEARTBEAT, but there is no guarantee that a writer will actually send that HEARTBEAT for historical data and in case of reconnecting after an asymmetric disconnection.
The sensible thing to do is to not sit idle as a reader, but always eventually send an ACKNACK if data is known to be missing (or if no HEARTBEAT has been received yet). This has been a design choice in this stack since the very beginning, but it turns out that there is a case where the ACKNACK event doesn't get rescheduled even though data is missing because what would ordinarily have been a NACK gets generated as an ACK, and then potentially never sent out.
This changes the ACKNACK generation logic to always distinguish the case where a NACK would have been generated if only circumstances allowed it, then ensures that the event is always scheduled if a NACK is generated or would have been generated.
The spec says that readers may only send an ACKNACK message in response to a HEARTBEAT, but there is no guarantee that a writer will actually send that HEARTBEAT for historical data and in case of reconnecting after an asymmetric disconnection.
The sensible thing to do is to not sit idle as a reader, but always eventually send an ACKNACK if data is known to be missing (or if no HEARTBEAT has been received yet). This has been a design choice in this stack since the very beginning, but it turns out that there is a case where the ACKNACK event doesn't get rescheduled even though data is missing because what would ordinarily have been a NACK gets generated as an ACK, and then potentially never sent out.
This changes the ACKNACK generation logic to always distinguish the case where a NACK would have been generated if only circumstances allowed it, then ensures that the event is always scheduled if a NACK is generated or would have been generated.