The timeline showed late payment steps first
Events without a timestamp were sorted after every timed event, so a Paystack flow appeared with the webhook and verification before the PIN and OTP steps.
Symptoms
A lifecycle of initialize, send_pin, send_otp, webhook, verify was displayed with webhook and verify first.
Expected and observed behavior
- Expected
- Events without their own time stay where they occurred relative to the timed events around them.
- Observed
- All untimed events were placed after the last timed event.
Root cause
sortEvents ordered timed events and appended every untimed event at the end, discarding the position the event had in the input.
Resolution
Untimed events are now anchored to the timed event that precedes them in the input; untimed events before any timed one lead (pull request #47):
// An event without its own time stays right after the timed event that
// precedes it in the input; untimed events before any timed one lead.
for (const e of inInput) {
if (!Number.isNaN(timeOf(e))) anchor = e;
else if (anchor) after.set(anchor, [...(after.get(anchor) ?? []), e]);
else leading.push(e);
}
return [...leading, ...timed.flatMap((e) => [e, ...(after.get(e) ?? [])])];Validation
Thirteen adapter tests asserted the old order and were re-checked ("same events, same fields, only the order differs"). Two new core tests. Rule and scenario results were unchanged; 4,576 tests passed.