The file it learned from had the same bug
The nudge that burned seventeen weeks learned its rules from an older file. That file had it too, found with one shift on the rota and nothing lost.
Yesterday's post was about the availability nudge that stamped a week as asked before checking whether it could send anything, and burned seventeen weeks on the live venue while the text provider was unconfigured. The header of that file says it learned its three rules from an older file, the one that chases staff about a shift they have not confirmed. The obvious next question was whether the parent had the same fault. It did.
The parent looked safer
It had one real advantage. When texts are not set up, it falls back to email, so the stamp sits in front of a two-channel attempt, and the documented rule, that a send that fails is better than one that repeats every minute, genuinely applies. But the send function has a third answer, and it is the one that matters. If texts are not configured and the person has no email address, it returns: nothing sent, nowhere to send.
The code knew there was nowhere to send. The stamp had already gone down. A staff member with no phone number and no linked account, which is the ordinary shape for someone who only ever uses the till, had their shift marked as chased, once and for ever, with nothing sent by either channel. When the keys arrive, that shift is still burnt.
Latent, and said as such
This one was caught before it had anything to spoil. The live estate held one rota shift and zero chase stamps, against yesterday's seventeen of seventeen. The message log was empty, and that is the whole evidence that nothing was sent, because one shared ladder is the only thing that writes that table, for every channel. Same bug, found before it bit, which is the best time to find one.
The fix is the same shape as yesterday's. Ask whether there is anywhere at all to send before stamping; nowhere means skip without stamping. The check for whether texts are ready moved to one read per sweep, since it was being asked once per person, and the resolved address is passed down so the account lookup still happens exactly once.
A test that had been watching the wrong moment all along
Three tests failed, and one of them had been measuring the wrong thing since it was written. It asserts the anti-spam guarantee, that the stamp precedes the send, and it located the send by finding the lookup of the person's details in the statement log. That was never the send. It was the lookup of the address to send to, which merely sat inside the send function. Moving the reachability question ahead of the stamp moved that lookup with it, and the test failed, reporting a guarantee broken that was entirely intact.
It now stubs the mail transport and asserts against the outbound call itself, which is strictly stronger. Reverting the fix leaves that test green, which is the proof that the two are independent.
The second failure gave itself away in its own comment. A test titled a send that fails still leaves the person stamped seeded somebody with no phone and no account, and the comment beside it said nothing to send to. That is not a failed send. It now seeds somebody reachable and a transport that refuses, which is what the title claims, and the impossible case has become its own test, the one that catches this finding.
Two lessons for anyone running a venue on software. When one of your reminders is found to misfire, go and look at its older sibling the same day, because that is where it learned its habits. And a test can pass for a year while watching the wrong moment; it is worth asking what, exactly, yours are looking at.