refactor(render): #28 этап 1 ревью раунд 1 — тест изоляции §3.4 + актуализация комментов
Docker Image CI / build (pull_request) Has been cancelled

Do 1 [test-coverage]: залочил security-инвариант §3.4 (per-post изоляция
фрагмента) именованным тестом test_unbalanced_post_does_not_swallow_next_post_html_feed
(в test_stage4_eventloop.py — гоняет реальный per-post HTML-пайплайн на истории из
2 сообщений). Пост A несёт висячий `<div><b>DANGLING_A` без закрывашек, пост B
целый с маркером. Ассертит: фид бьётся на 2 фрагмента по `<hr post-divider>`;
теги A сбалансированы В ПРЕДЕЛАХ фрагмента A; маркер B в фрагменте B и НЕ в A
(не заглочен). Проверено, что тест краснеет на регрессии «join-before-sanitize»:
при склейке raw-постов до единого whole-feed bleach.clean невайтлистнутый `<hr>`
стрипается (strip=True) → 0 разделителей → 1 фрагмент → первый ассерт падает.
То есть будущий этап, вернувший склейку до санитайза, ловится этим тестом.

Do 2 [documentation]: 4 устаревших коммента про удалённый «whole-feed sanitize
для HTML» обновлены на «per-post в _render_pipeline для обоих (RSS и HTML)»
(post_parser.py process_message docstring / _generate_html_body NOTE /
generate_html_footer coverage-map; rss_generator.py feed-path коммент). Вывод
«санитайзится ровно один раз» сохранён. Исполняемый код не менялся.

Полный сюит 347 passed (+1 тест изоляции); оракул этапа 0 — 11 passed, golden не менялся.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-07-06 17:01:00 +03:00
parent 0963c140a3
commit c2d9adc45f
3 changed files with 60 additions and 8 deletions
+3 -2
View File
@@ -220,8 +220,9 @@ def _render_messages_groups(messages_groups: list[list[Message]],
try:
if len(group) == 1: # Single message - simple case
one_message = group[0]
# Feed path: raw_message not needed and sanitize deferred to the final
# whole-feed pass, so each fragment is sanitized exactly once.
# Feed path: raw_message not needed and sanitize deferred to the per-post
# pass in _render_pipeline (both RSS and HTML), so each fragment is
# sanitized exactly once.
message_data = post_parser.process_message(one_message, include_raw=False, sanitize=False)
html_parts = [
f'<div class="message-body">{message_data["html"]["body"]}</div>',