(medium) trade_in_pdf._build_cover: «Срок действия данных» захардкожен today+30д, игнорирует estimate.expires_at (=now+24ч) #1530

Closed
opened 2026-06-15 05:59:21 +00:00 by bot-backend · 1 comment
Collaborator

Severity: medium · Категория: report · Файл: tradein-mvp/backend/app/services/exporters/trade_in_pdf.py:451-452, 549

trade_in_pdf.py:451-452 — today = dt.date.today(); expires = today + dt.timedelta(days=30), и на обложке (строка 549) печатается «Срок действия данных до {expires}», т.е. клиенту обещают валидность данных 30 дней. При этом estimator.py:2640 и :3931 задают expires_at = now + timedelta(hours=24), а схема AggregatedEstimate несёт это поле (trade_in.py:154 expires_at: datetime). Cover не использует переданное estimate.expires_at, а считает срок локально от даты генерации PDF. Импакт: в клиентском документе срок действия данных завышен в ~30 раз относительно собственного TTL системы; при повторной генерации PDF по старой (уже протухшей по 24ч) оценке «Дата отчета» = сегодня и «Срок до» = сегодня+30д, выдавая устаревшие данные за свежие. Чинить: использовать estimate.expires_atestimate.created_at для даты отчёта) вместо локального today+30д.

Почему баг: estimator.py задаёт TTL данных = 24 часа (expires_at = now + timedelta(hours=24)), а схема AggregatedEstimate несёт это поле (expires_at: datetime, trade_in.py:154). Cover не использует его, а печатает today+30д. Итог: в клиентском документе срок действия данных завышен в ~30 раз относительно того, что система сама считает протуханием. Дополнительно: при повторной генерации PDF по ?id= для старой (уже протухшей по 24ч) оценки «Дата отчета» = сегодня и «Срок действия до» = сегодня+30д, что выдаёт устаревшие данные за свежие.

Как чинить: Брать дату и срок из самой оценки: «Дата отчета» — из created_at/fetched_at оценки (а не today), «Срок действия данных» — из estimate.expires_at. Если решено показывать иной горизонт валидности отчёта, чем TTL кэша, — согласовать его с продуктом и не хардкодить 30д, противоречащих 24ч TTL.


deep-audit «армия ботов 2» · verify+harden, confidence 0.95 · unit U129

**Severity:** medium · **Категория:** report · **Файл:** `tradein-mvp/backend/app/services/exporters/trade_in_pdf.py:451-452, 549` trade_in_pdf.py:451-452 — `today = dt.date.today(); expires = today + dt.timedelta(days=30)`, и на обложке (строка 549) печатается «Срок действия данных до {expires}», т.е. клиенту обещают валидность данных 30 дней. При этом estimator.py:2640 и :3931 задают `expires_at = now + timedelta(hours=24)`, а схема AggregatedEstimate несёт это поле (trade_in.py:154 `expires_at: datetime`). Cover не использует переданное `estimate.expires_at`, а считает срок локально от даты генерации PDF. Импакт: в клиентском документе срок действия данных завышен в ~30 раз относительно собственного TTL системы; при повторной генерации PDF по старой (уже протухшей по 24ч) оценке «Дата отчета» = сегодня и «Срок до» = сегодня+30д, выдавая устаревшие данные за свежие. Чинить: использовать `estimate.expires_at` (и `estimate.created_at` для даты отчёта) вместо локального today+30д. **Почему баг:** estimator.py задаёт TTL данных = 24 часа (`expires_at = now + timedelta(hours=24)`), а схема AggregatedEstimate несёт это поле (`expires_at: datetime`, trade_in.py:154). Cover не использует его, а печатает today+30д. Итог: в клиентском документе срок действия данных завышен в ~30 раз относительно того, что система сама считает протуханием. Дополнительно: при повторной генерации PDF по `?id=` для старой (уже протухшей по 24ч) оценки «Дата отчета» = сегодня и «Срок действия до» = сегодня+30д, что выдаёт устаревшие данные за свежие. **Как чинить:** Брать дату и срок из самой оценки: «Дата отчета» — из created_at/fetched_at оценки (а не today), «Срок действия данных» — из estimate.expires_at. Если решено показывать иной горизонт валидности отчёта, чем TTL кэша, — согласовать его с продуктом и не хардкодить 30д, противоречащих 24ч TTL. --- <sub>deep-audit «армия ботов 2» · verify+harden, confidence 0.95 · unit U129</sub>
bot-backend added the
week ревью 1
label 2026-06-15 05:59:21 +00:00
bot-backend added the
scope/backend
label 2026-06-15 11:02:19 +00:00
Owner

🔍 week ревью 1 — верификация (ПОДТВЕРЖДЕНО)

Текущее состояние кода: tradein-mvp/backend/app/services/exporters/trade_in_pdf.py:451-452, 548-549 (cover). Строки совпадают с issue.

Корень: _build_cover (450) считает срок локально: today = dt.date.today() (451), expires = today + dt.timedelta(days=30) (452), и печатает «Дата отчета {today}» (548) + «Срок действия данных до {expires}» (549). Схема AggregatedEstimate несёт expires_at: datetime (schemas/trade_in.py:154), а estimator задаёт TTL = 24ч: expires_at = now + timedelta(hours=24) (estimator.py:2640 и :3931; SQL UPSERT тоже использует NOW() + ttl_hours interval на :694, и фильтр expires_at > NOW() на :631). Cover игнорирует переданный estimate.expires_at → клиенту обещают валидность 30 дней против собственного 24ч TTL (завышение ~×30). При повторной генерации PDF по ?id= для протухшей оценки «Дата отчета» = сегодня и «Срок до» = сегодня+30д, выдавая устаревшее за свежее.

Что править:

  • «Срок действия данных» брать из estimate.expires_at (поле есть в схеме, :154), не из локального today+30д.
  • «Дата отчета» — из времени самой оценки. NB: на схеме AggregatedEstimate поля created_at НЕТ; есть fetched_at: datetime | None (schemas/trade_in.py:263) — использовать его (с фолбэком, т.к. Optional). Если нужно показывать created_at — сначала добавить поле в схему/выборку.
  • Если продукт хочет горизонт валидности отчёта, отличный от 24ч TTL кэша, — согласовать явно и не хардкодить 30д.

Что посмотреть:

  • Код: trade_in_pdf.py:450-452, 548-549 (_build_cover), schemas/trade_in.py:154 (expires_at), :263 (fetched_at), estimator.py:2640, 3931, 694, 631 (TTL=24ч). Тест: рендер cover с заданным expires_at (now+24ч) → на обложке печатается именно он, не today+30д.
  • Vault: релевантных заметок не найдено (запрос по cover/expires_at — пусто).
**🔍 week ревью 1 — верификация (ПОДТВЕРЖДЕНО)** **Текущее состояние кода:** `tradein-mvp/backend/app/services/exporters/trade_in_pdf.py:451-452, 548-549` (cover). Строки совпадают с issue. **Корень:** `_build_cover` (450) считает срок локально: `today = dt.date.today()` (451), `expires = today + dt.timedelta(days=30)` (452), и печатает «Дата отчета {today}» (548) + «Срок действия данных до {expires}» (549). Схема `AggregatedEstimate` несёт `expires_at: datetime` (schemas/trade_in.py:154), а estimator задаёт TTL = 24ч: `expires_at = now + timedelta(hours=24)` (estimator.py:2640 и :3931; SQL UPSERT тоже использует `NOW() + ttl_hours interval` на :694, и фильтр `expires_at > NOW()` на :631). Cover игнорирует переданный `estimate.expires_at` → клиенту обещают валидность 30 дней против собственного 24ч TTL (завышение ~×30). При повторной генерации PDF по `?id=` для протухшей оценки «Дата отчета» = сегодня и «Срок до» = сегодня+30д, выдавая устаревшее за свежее. **Что править:** - «Срок действия данных» брать из `estimate.expires_at` (поле есть в схеме, :154), не из локального today+30д. - «Дата отчета» — из времени самой оценки. NB: на схеме `AggregatedEstimate` поля `created_at` НЕТ; есть `fetched_at: datetime | None` (schemas/trade_in.py:263) — использовать его (с фолбэком, т.к. Optional). Если нужно показывать `created_at` — сначала добавить поле в схему/выборку. - Если продукт хочет горизонт валидности отчёта, отличный от 24ч TTL кэша, — согласовать явно и не хардкодить 30д. **Что посмотреть:** - Код: `trade_in_pdf.py:450-452, 548-549` (`_build_cover`), `schemas/trade_in.py:154` (`expires_at`), `:263` (`fetched_at`), `estimator.py:2640, 3931, 694, 631` (TTL=24ч). Тест: рендер cover с заданным `expires_at` (now+24ч) → на обложке печатается именно он, не today+30д. - Vault: релевантных заметок не найдено (запрос по cover/expires_at — пусто).
bot-backend added the
needs-human
label 2026-06-15 16:44:15 +00:00
Sign in to join this conversation.
No milestone
No project
No assignees
2 participants
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference: lekss361/gendesign#1530
No description provided.