Commit Graph

3 Commits

Author SHA1 Message Date
agent_coder 0963c140a3 refactor(render): этап 1 — sanitizer.py + санитайз per-post в пайплайне (#28)
Часть эпика рефакторинга рендер-пайплайна (#34). Один bleach-конфиг на весь
проект, один санитайз на пост, ноль thread-hop'ов в циклах (раньше конфиг был
скопирован трижды и разъехался; RSS-путь делал to_thread + новый CSSSanitizer +
вложенную функцию НА КАЖДЫЙ пост, хотя _render_pipeline уже в worker-треде).

Новый sanitizer.py — единственная bleach-конфигурация: ALLOWED_TAGS (union трёх
старых копий, вкл. s/del), ALLOWED_PROTOCOLS=['http','https','tg'],
sanitize_html() зовёт bleach.clean(..., protocols=..., strip=True) (оба не-дефолт),
fail-CLOSED (html.escape при любом исключении), единое имя лога
html_sanitization_error + log_context. _render_pipeline санитайзит каждый пост
после рендера (в своём worker-треде); rss_generator −71 строка.

Реестр §3:
- §3.1 s/del теперь в фидах (раньше выживали только в одиночном посте);
- §3.2 fail-open → fail-closed (вкл. single-post/JSON путь);
- §3.3 <hr class="post-divider"> реально виден (join ПОСЛЕ санитайза; hr не в
  whitelist, поэтому раньше вырезался strip=True);
- §3.4 несбалансированный фрагмент нормализуется в границах своего поста;
- §3.5 гранулярный fail-closed HTML-фида (падает один пост, не весь фид);
- §3.16 три имени санитайз-логов объединены в html_sanitization_error+log_context.

Golden-эталоны обновлены: КАЖДЫЙ изменённый байт привязан к пункту §3 (net-diff
тегов: только +<s>/§3.1 и +<hr>/§3.3; <div> сбалансирован +/- = §3.4;
после снятия этих токенов + нормализатора все 6 голденов побайтово old==new).
Оракул этапа 0 зелёный. Полный сюит 346 passed (+14 sanitizer-тестов).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-06 17:05:53 +03:00
agent_coder dc9a23f801 test(render): этап 0 — golden-эталоны фидов как оракул эквивалентности (#27)
Docker Image CI / build (pull_request) Has been cancelled
Первый этап эпика рефакторинга рендер-пайплайна (#34): снимает полные
snapshot'ы выходов generate_channel_rss (RSS XML) и generate_channel_html
(HTML) на записанном РЕАЛЬНОМ корпусе (4 канала: bladerunnerblues, embedoka,
meow_design, theyforcedme) и закрепляет тестом сравнения. Оракул для всех
последующих этапов: изменение байтов фида без ссылки на пункт реестра §3
спеки = регрессия. Никакой продакшн рендер-код не тронут — только тест-инфра.

- tests/golden_replay.py: реплей-загрузчик (распикливает recorded/*.cache|
  *.chatinfo, monkeypatch tg_cache.cached_get_chat_history/cached_get_chat —
  буквально прод-путь cache-hit) + генератор goldens + нормализаторы.
- tests/test_stage0_golden.py: оракул (11 тестов — RSS×4, HTML×4 + guards).
- tests/test_data/golden/: 8 замороженных snapshot'ов (~1.9 МБ).
- tests/conftest.py: пин TZ=UTC (naive-даты kurigram интерпретируются в
  локальной tz → без пина pubDate дрейфует между машинами).

Нормализации (симметрично golden+actual, минимальные, каждая с источником
недетерминизма): strip <lastBuildDate> (feedgen now()), strip <generator>
(страховка), сортировка <div class="message-flags"> (merged-флаги —
list(set(...)), hash-порядок; убирается коммитом этапа 2 по §3.8).

Детерминизм подтверждён 3 способами: двойной in-process захват, разные
PYTHONHASHSEED, регенерация в отдельном процессе — нормализованный вывод
байт-идентичен. Полный сюит 332 passed.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-06 07:39:40 +03:00
vvzvlad 9a0df8d8c9 docs(plans): add recorded cache fixtures for render pipeline
Docker Image CI / build (push) Has been cancelled
Add binary `.cache` and `.chatinfo` files for four public channels to
`tests/test_data/recorded/` to serve as a frozen test corpus. Update the
render pipeline refactor plan to reflect the completed snapshot,
selection, and inventory steps.
2026-07-05 21:10:52 +03:00