Unles the verification routine (eg. garage) keeps some state somewhere it has no way to prevent replays.
But even that need not be true. here is how you could design that dongle to require no persistent state on RX and still not allow simple replay.
TX code:
static u8 counter = 0;
tmp = randU12() * 16 + (counter++);
tmp2 = sha256(secret + tmp) & 0xffff;
send32((tmp << 16) + tmp2)
RX code:
static u16 prevSeenCodes[16];
static u8 idx = 0; tmp = recv32();
tmp2 = tmp & 0xffff;
tmp >>= 16;
if (sha256(secret + tmp) & 0xffff != tmp2)
fail();
if (tmp in prevSeenCodes)
fail();
prevSeenCodes[15 & idx++] = tmp;
now you need to replay at least a sequence of 16 codesthat array is in ram and need not persist across program runs. dongle can be powered off or can be left on. all will work