diff --git a/frontend/today-timer.js b/frontend/today-timer.js index d1200c3..935a3ff 100644 --- a/frontend/today-timer.js +++ b/frontend/today-timer.js @@ -117,16 +117,17 @@ function createTodayTimer({ storage, getLogin, now = () => Date.now(), onChange } if (!ledger[identity] || ledger[identity].elapsed_ms !== Math.floor(Number(elapsedMs))) return false; const state = read(); + const keepBreak = validBreak(state)?.identity === identity; state.active_identity = identity; state.entries = ledger; - state.entries[identity].started_at = running ? now() : null; - state.entries[identity].running = Boolean(running); + state.entries[identity].started_at = running && !keepBreak ? now() : null; + state.entries[identity].running = Boolean(running) && !keepBreak; state.away_at = null; state.pending_interruption = null; state.attention_interruption = null; state.search_interruption = null; state.detour_interruption = null; - if(running || validBreak(state)?.identity !== identity) state.timed_break=null; + if (!keepBreak) state.timed_break = null; return write(state); }, activate(identity) { diff --git a/tests/test_today_break.py b/tests/test_today_break.py index e53bb83..82c7f2f 100644 --- a/tests/test_today_break.py +++ b/tests/test_today_break.py @@ -122,6 +122,35 @@ process.stdout.write(JSON.stringify({adopted,snapshot:timer.snapshot(),pending:t } +def test_reload_running_checkpoint_cannot_restart_item_during_valid_local_break(): + script = TIMER.read_text() + r""" +const values = new Map(); +const storage = {getItem:key=>values.get(key)||null,setItem:(key,value)=>values.set(key,value)}; +const timer = createTodayTimer({storage,getLogin:()=> 'timmy',now:()=>100000}); +timer.activate('issue:r:42:'); +timer.startBreak(5); +const adopted = timer.adopt('issue:r:42:', 12000, true, [ + {identity:'issue:r:42:',elapsed_ms:12000}, +]); +process.stdout.write(JSON.stringify({adopted,snapshot:timer.snapshot(),pending:timer.breakSnapshot()})); +""" + + assert run_node(script) == { + "adopted": True, + "snapshot": { + "identity": "issue:r:42:", + "elapsed_ms": 12000, + "running": False, + "break_deadline_at": 400_000, + }, + "pending": { + "identity": "issue:r:42:", + "deadline_at": 400_000, + "expired": False, + }, + } + + def test_break_expiry_never_restarts_time_and_resume_is_explicit_and_idempotent(): script = TIMER.read_text() + r""" const values = new Map();