0.31.0

Added

  • P2-A1: Cron catch-up пропущенных тиковrecalcAllJobs пересчитывает не только nil next_run_at, но и просроченные. Для every — сдвиг на now + duration; для cronsched.Next(now); для at — оставляет для немедленного исполнения. Унификация формата времени на RFC3339 для корректного SQL-сравнения next_run_at <= now(). Логирование catch-up событий.
  • P2-A2: Schedule-kind "at" парсинг и валидацияValidateScheduleExpr(kind, expr) — общая функция валидации (at → RFC3339/ISO, every → duration ≥ 1s, cron → robfig parser). Вызывается в CronTool.addAction, CronHandler.Create/Update. Невалидные строки типа «вечером» отклоняются. Мёртвый код parseTime удалён.
  • P2-A3: saveCheckpoint — восстановление после рестарта — таблица actor_checkpoints (миграция 030). SessionActor.busy (atomic bool) выставляется при handleInbound. saveCheckpoint пишет busy-флаг при shutdown. При старте AgentLoop.recoverBusyCheckpoints находит прерванные сессии и очищает. Checkpoint удаляется при idle timeout. Store-методы SaveActorCheckpoint, ListBusyCheckpoints, ClearActorCheckpoint (SQLite, PostgreSQL, DualStore).
  • P2-A4: Heartbeat tick неблокирующий — каждый tickAgent запускается в отдельной горутине с sync.WaitGroup. Context timeout 2 минуты на каждый агент. recover() в каждой горутине — защита от panic.

Fixed

  • Формат времени cron: переход с "2006-01-02 15:04:05" на time.RFC3339 для совместимости с store.Now() → корректное сравнение next_run_at <= now() в SQL.
  • ComputeNextRunAt для "at" — теперь парсит выражение через parseFlexibleTime вместо возврата сырой строки.