Commit Graph

2 Commits

Author SHA1 Message Date
agent_coder 432715200f fix(cache): снапшот всех спец-медиа типов + render-parity тест + file_size для всех медиа (ревью #44)
Docker Image CI / build (pull_request) Waiting to run
Ревью #44: allowlist снапшота был неполон -> спец-медиа блоки тихо выпадали на
cache-hit (нарушение golden-render инварианта). Исправлено:
- Снапшот+восстановление 11 типов (story, contact, location, venue, dice, game,
  giveaway, giveaway_winners, checklist, paid_media + live_photo) — ровно те
  подполя, что читает _format_special_media/find_file_id_in_message.
  SNAPSHOT_VERSION 1->2 (v1-файлы без новых ключей инвалидируются).
- Render-parity тест (tests/test_snapshot_render_parity.py): корпус из 35+ кейсов
  (все медиа/спец-медиа/web_page/poll/forward Case 1-5/reactions/media group),
  live-рендер == restore(snapshot(live))-рендер байт-в-байт через реальный
  пайплайн; мутационно проверено (выброс поля -> тест краснеет).
- F1: file_size досниман для document/audio/animation/video_note/story-media
  (правило '>100MB не кэшировать' в _save_media_file_ids читает file_size у любого
  выбранного медиа-объекта; раньше был только у video/live_photo -> >100MB документ
  ошибочно кэшировался на cache-hit).
- flake8/pylint-хедеры на 3 новых тест-файла.

post_parser.py/rss_generator.py не тронуты; pickle отсутствует.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-10 01:25:41 +03:00
agent_coder 8d317e36c8 feat(cache): снапшот-кеш истории вместо pickle + префиксный limit + джиттер TTL + age-sweep
Docker Image CI / build (pull_request) Waiting to run
Кеш истории (data/tgcache/) больше не хранит pickle живых объектов pyrogram.
Новый модуль message_snapshot.py: при записи из Message извлекается JSON-словарь
по явному allowlist (снапшот), при чтении восстанавливается duck-typed
CachedMessage (CachedStr с .html, mutable, deepcopy-safe), неотличимый для
пайплайна рендера от Message. post_parser.py и rss_generator.py НЕ изменены.

tg_cache.py переписан на generic JSON-store (pickle удалён полностью):
- _store_entry/_load_entry: атомарная запись через уникальный .tmp.<uuid4> +
  os.replace, finally чистит свой tmp; версия/TTL/битый JSON -> None;
- пути <safe_key>.history.json / .chatinfo.json;
- пакет B: префиксный limit (miss только когда cached_limit<limit и есть ещё);
- пакет F: джиттер TTL при записи (random.uniform(0.8,1.0), на чтении random не
  зовётся) + sweep_tgcache(age) + cleanup_legacy_cache_files;
- api_server.py: старт-cleanup+sweep в lifespan, per-pass sweep в cache_media_files,
  удаление legacy data/media_file_ids.json.

closes #23

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-10 00:09:08 +03:00