Skip to content

fix(idle): exclude paused timers from the idle auto-stop sweep - #752

Merged
evilguy4000 merged 1 commit into
DRYTRIX:mainfrom
MacJediWizard:upstream-fix/idle-skip-paused-timers
Sep 8, 2026
Merged

evilguy4000 merged 1 commit into
DRYTRIX:mainfrom
MacJediWizard:upstream-fix/idle-skip-paused-timers

Conversation

@MacJediWizard

Copy link
Copy Markdown
Contributor

Problem

check_idle_timers() selects every open time entry (end_time IS NULL) whose last heartbeat is older than the idle window, then idle-notifies it, flags it needs_review, and — with the safety cap enabled — auto-stops it.

A paused timer is also an open entry with a stale heartbeat: it is intentionally accumulating no time and sends no heartbeats while paused. So the sweep treats a deliberately-paused timer exactly like an abandoned running one — it fires the "Still working?" push, flags it for review, and can auto-stop a timer the user chose to pause.

Root cause

paused_at was added with the pause/resume feature but never wired into the idle-sweep query. The WHERE clause guards only end_time and the heartbeat cutoff, so paused rows fall straight through.

Fix

Add TimeEntry.paused_at.is_(None) to the idle query so paused timers are excluded from notify / flag / auto-stop. Four added lines, no behavioral change for running timers.

Tests

New tests/test_idle_timer_skips_paused.py:

  • test_idle_sweep_skips_paused_timer — a paused, stale timer is neither notified, flagged, nor stopped.
  • test_idle_sweep_still_notifies_running_timer — control: a genuinely idle, non-paused timer is still swept, guarding against over-correction.

Full timer test suite green locally.

A paused timer stops heartbeating, so its last_heartbeat_at goes stale and
check_idle_timers() treats it as idle: it sends a "Still working?" push,
then after the grace period flags it needs-review and, once the optional
safety cap elapses, auto-stops it. But a paused timer is intentionally
accumulating no time, so notifying, flagging, or stopping it is wrong.

Guard the idle query on TimeEntry.paused_at.is_(None). paused_at shipped
with the pause/resume feature but was never wired into this query.

Adds a regression test: a stale paused timer must be skipped, while a
stale non-paused timer is still notified.
@evilguy4000
evilguy4000 merged commit 2141b42 into DRYTRIX:main Sep 8, 2026
10 of 13 checks passed
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