chore: promote staging to staging-promote/4b6d52e5-25011988667 (2026-04-27 20:31 UTC) - #2998
Conversation
* fix(engine): make mission threads_today reset timezone-aware The daily-budget reset added in #2570 compared `last_fire_at.date_naive()` against `now.date_naive()`, both in UTC. Cron missions configured with a non-UTC timezone (e.g. `America/Los_Angeles`) expect their budget to refresh at the user's local midnight, not at 00:00 UTC — under the old logic such a mission could stay stuck at "exhausted" for up to ~17 hours into the new local day. Extract the staleness check into `threads_today_is_stale(&mission)` and use the mission's cron timezone (when set) for the day boundary; UTC remains the fallback for manual / event-driven cadences and for cron missions without a configured timezone. Tests: - cron_mission_threads_today_resets_via_tick locks in the tick + cron path; the existing reset test only covered fire_on_system_event. - threads_today_resets_at_cron_local_midnight uses Pacific/Auckland to produce a `last_fire_at` that is yesterday-local but same UTC day, which the old logic would not have reset. - threads_today_is_stale_predicate covers the boundary helper directly. Fixes #1945 * review: address reviewer feedback on threads_today_is_stale - Inject `now: DateTime<Utc>` into `threads_today_is_stale` so the predicate is unit-testable against fixed instants and so the call site can pin a single timestamp across the staleness check and the cooldown check (Gemini, Copilot). - Capture `now` once at the top of the staleness/cooldown block in `fire_mission` and reuse it for the cooldown comparison so the two cannot disagree across a midnight tick. - Reword the helper doc to drop the hard-coded "5 PM local" claim, which varies under DST (Copilot). - Consolidate the prior wall-clock-based Auckland integration test into deterministic synthetic-instant cases inside `threads_today_is_stale_predicate`. The previous test could pass even when the timezone branch was disabled, depending on when of day it ran (Copilot). The new case asserts: same UTC date, but Auckland local dates straddle the boundary — exactly the regression the timezone branch fixes. - Document why `last_fire_at = None` with a non-zero counter must return `true` (recovery direction), not `false` — `false` would re-introduce the permanent-exhaustion bug this helper exists to fix.
Code reviewFound 2 minor issues:
Strengths:
|
Auto-promotion from staging CI
Batch range:
7fb41555a9e55677d1aaea29ca567a5b369c2b05..e7d9922ce0885081f28373109da28953ad1d5decPromotion branch:
staging-promote/e7d9922c-25016769392Base:
staging-promote/4b6d52e5-25011988667Triggered by: Staging CI batch at 2026-04-27 20:31 UTC
Commits in this batch (95):
onboardfails with "Failed to save settings to database", butironclawstarts successfully and applies migrations #846) (fix(setup): run migrations during onboard when DATABASE_URL preset (#846) #2309)Current commits in this promotion (1)
Current base:
staging-promote/4b6d52e5-25011988667Current head:
staging-promote/e7d9922c-25016769392Current range:
origin/staging-promote/4b6d52e5-25011988667..origin/staging-promote/e7d9922c-25016769392Auto-updated by staging promotion metadata workflow
Waiting for gates:
Auto-created by staging-ci workflow