Created on Friday, Registered on Wednesday
A bug I found while demoing to my son. It was a long commute.
Created on Friday, Registered on Wednesday
This morning, while eating breakfast, my son asked me.
“Dad, does this have a timetable feature?”
Fecit has a timetable feature. You register recurring tasks — daily, weekly, monthly — by time slot, and they get created automatically. It was the perfect thing to demo, so I opened it right away. Pulled up Weekly Routine, selected Friday, set a time, registered.
The saved routine said Wednesday.
I definitely tapped Friday. The screen showed Friday selected. But what got saved was Wednesday. I tried again in front of my son — “this is supposed to work…” — same result. It was time to leave for work, so I just left.
The commute didn’t feel great. It was the first time my son had shown interest in what I was building, and of all moments, that’s when the bug showed up. He didn’t say anything like “Dad, your app is kind of broken” — but somehow that made it worse.
The cause
I opened the code as soon as I got to the office. There was one obvious suspect: how the server stores the day when registering a Weekly Routine.
day = get_create_reservation_day(
to_local(ticket.start_reference_date, ticket.timezone)
) if ticket.period_type == CreateReservationPeriodType.WEEKLY else ticket.day
This single line was the whole problem.
The app sends the user’s selected day in ticket.day. Selecting Friday means FRI(4). But the server, when the type is Weekly, ignores that value entirely and calculates the day from start_reference_date.
start_reference_date is a Date object created when the user picks a time. Only the time matters — the date is just “today.” Today is Wednesday. Call weekday() and you get WED(2).
The user selected Friday, but the server decided “today is Wednesday, so Wednesday.”
Why it was written that way
About a month ago, I fixed a similar bug. Weekly notifications weren’t firing at all — the cause was the app failing to send the day value, leaving the server with empty fields.
The fix back then was “don’t trust what the app sends, let the server calculate it.” Derive the day from start_reference_date and the app not sending a value won’t matter. The notification job runs in UTC, start_reference_date is stored in UTC — no timezone issues either.
That fix was correct. For the notification job.
The problem was applying the same pattern to the registration endpoint. In the notification job, the date portion of start_reference_date is meaningful — it’s the actual date when the routine was created. But on the registration screen, start_reference_date only carries the time; the date is just today. Calculate the day from that and you always get “today’s day of the week.”
The previous fix had good intentions, but the wrong scope.
The fix
day = (
ticket.day if ticket.day is not None
else get_create_reservation_day(
to_local(ticket.start_reference_date, ticket.timezone)
)
) if ticket.period_type == CreateReservationPeriodType.WEEKLY else ticket.day
If the user selected a day, use it. If they didn’t, fall back to calculating from start_reference_date. Respect the app when it sends a value, let the server fill in when it doesn’t.
What I’ll tell him tonight
When I get home, I need to tell my son. The thing that was broken this morning — Dad fixed it. Friday goes in as Friday now.
And I should be honest with him. I only opened that screen because he asked about it. He’s the reason I found the bug. If he hadn’t been curious, this bug would have stayed hidden longer. Someone asking “does this work?” is the best test there is — I was reminded of that today.
The morning commute was heavy, but the ride home should be lighter.