Суть
Класс бага «naive vs aware datetime на границе row→model» (повторяющийся в проекте, ср. #1234/pool_dialogs). Расчёт возраста кэша диалогов вычитает cached_at из aware-времени; если строка в dialog_cache получила cached_at через схемный DEFAULT, дата придёт naive и вычитание упадёт.
Корень (origin/main)
src/telegram/pool_dialogs.py:402 — age_sec = (datetime.now(timezone.utc) - cached_at).total_seconds().
cached_at приходит из src/database/repositories/dialog_cache.py → parse_datetime (src/utils/datetime.py), который не форсит tzinfo.
- Обычный путь записи пишет aware-строку (
.isoformat() c +00:00), но schema DEFAULT — datetime('now') (src/database/schema.py:316), дающий naive-строку без офсета.
Сценарий отказа
Любая строка dialog_cache, вставленная без явного cached_at (DEFAULT сработал), при следующем чтении возраста кэша даёт TypeError: can't subtract offset-naive and offset-aware datetimes → путь warm/refresh диалогов падает.
Направление фикса
Нормализовать на границе чтения: parse_datetime (или repo-хелпер _to_model) добавляет tzinfo=timezone.utc для naive-значений. Регресс-тест: строка с naive cached_at в БД → расчёт возраста не падает.
Найдено аудитом (находка «за бортом» ревью #1234); латентный — в обычном пути записи не проявляется.
Суть
Класс бага «naive vs aware datetime на границе row→model» (повторяющийся в проекте, ср. #1234/pool_dialogs). Расчёт возраста кэша диалогов вычитает
cached_atиз aware-времени; если строка вdialog_cacheполучилаcached_atчерез схемный DEFAULT, дата придёт naive и вычитание упадёт.Корень (origin/main)
src/telegram/pool_dialogs.py:402—age_sec = (datetime.now(timezone.utc) - cached_at).total_seconds().cached_atприходит изsrc/database/repositories/dialog_cache.py→parse_datetime(src/utils/datetime.py), который не форсит tzinfo..isoformat()c+00:00), но schema DEFAULT —datetime('now')(src/database/schema.py:316), дающий naive-строку без офсета.Сценарий отказа
Любая строка
dialog_cache, вставленная без явногоcached_at(DEFAULT сработал), при следующем чтении возраста кэша даётTypeError: can't subtract offset-naive and offset-aware datetimes→ путь warm/refresh диалогов падает.Направление фикса
Нормализовать на границе чтения:
parse_datetime(или repo-хелпер_to_model) добавляетtzinfo=timezone.utcдля naive-значений. Регресс-тест: строка с naivecached_atв БД → расчёт возраста не падает.Найдено аудитом (находка «за бортом» ревью #1234); латентный — в обычном пути записи не проявляется.