Skip to content

test: reproduce #74 — rrule skips the occurrence at dtstart - #324

Open
sibson wants to merge 1 commit into
mainfrom
claude/triage-issue-74
Open

sibson wants to merge 1 commit into
mainfrom
claude/triage-issue-74

Conversation

@sibson

@sibson sibson commented Jul 27, 2026

Copy link
Copy Markdown
Owner

Adds a failing regression test for #74, reproduced on main (2f96d0a).

The mechanism

An rrule built without an explicit dtstart defaults it to the creation time
(redbeat/schedules.py:53), and celery's ScheduleEntry defaults last_run_at
to the same instant. remaining_estimate then asks dateutil for
rrule.after(last_run_at) (redbeat/schedules.py:93), which is exclusive
so the occurrence sitting exactly on dtstart is passed over and the first run
is delayed by a full interval.

For rrule('MINUTELY', interval=3, count=4) created at 21:19:58, due_at is
21:22:58 rather than 21:19:58:

AssertionError: datetime.datetime(2017, 12, 9, 21, 22, 58, tzinfo=datetime.timezone.utc)
             != datetime.datetime(2017, 12, 9, 21, 19, 58, tzinfo=datetime.timezone.utc)

This is the first of the two problems @concreted separated out in
#74 (comment).

What's in here

tests/test_issue_74.py holds two tests:

  • test_first_occurrence_is_due_at_dtstart — the bug, marked
    @unittest.expectedFailure so CI stays green. unittest reports an
    unexpected success as a failure, so the day this is fixed the suite says so.
  • test_first_occurrence_is_delayed_by_one_interval — pins today's behaviour, so
    a fix can't pass the first test without also having to touch this one
    deliberately.

At fix time

This is a triage artifact, not a permanent home. Whoever fixes this should move
the first test into tests/test_schedules.py, drop the expectedFailure
marker, rename it for the behaviour it checks rather than the issue number,
delete test_first_occurrence_is_delayed_by_one_interval, and delete this file.
The same note is in the class docstring.

Not addressed here: the second problem in #74 — an rrule whose occurrences are
all in the past is never scheduled at all (due_at is None, score is
-1). That one is a design question about whether missed occurrences should
fire, not a clear defect, so I left it for the maintainer.

An rrule created without an explicit dtstart defaults it to the creation
time, and celery's ScheduleEntry defaults last_run_at to the same instant.
remaining_estimate asks dateutil for rrule.after(last_run_at), which is
exclusive, so the occurrence sitting exactly on dtstart is skipped and the
first run is delayed by a full interval.

Marked expectedFailure so CI stays green.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WWqTCzv8BkUkgVg11xpgqQ
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants