refactor(render): #28 этап 1 ревью раунд 1 — тест изоляции §3.4 + актуализация комментов

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 3f4c7f0f68
commit 711cb2cd31
3 changed files with 60 additions and 8 deletions
+7 -6
View File
@@ -637,10 +637,10 @@ class PostParser:
serializing every post.
sanitize: when True, run the html body and footer through a single
bleach pass each. Single-post HTML and JSON need this (there is no
whole-feed pass on those paths). Feed generation passes False and
relies on the final sanitize in rss_generator (per-post for RSS,
whole-feed for HTML), so no
fragment is sanitized more than once.
feed-level pass on those paths). Feed generation passes False and
relies on the per-post sanitize in rss_generator._render_pipeline
(per-post for BOTH RSS and HTML), so no fragment is sanitized more
than once.
"""
# Compute html body once — avoids triple _generate_html_body calls.
# The internal per-fragment sanitize passes were removed (4.4); sanitize
@@ -799,7 +799,7 @@ class PostParser:
# NOTE: sanitize is NOT applied here. Sanitization happens exactly once per
# output boundary (process_message for single-post/JSON; in rss_generator the
# per-post pass for RSS and the whole-feed pass for HTML). See the map (4.4).
# per-post pass in _render_pipeline for BOTH RSS and HTML). See the map (4.4).
html_body = '\n'.join(content_body)
return html_body
@@ -1004,7 +1004,8 @@ class PostParser:
content_footer.append('<br>' + flags_html)
# Not sanitized here — sanitized once at the output boundary (4.4 coverage map):
# process_message for single-post/JSON; per-post (RSS) / whole-feed (HTML) for feeds.
# process_message for single-post/JSON; per-post in _render_pipeline for feeds
# (both RSS and HTML).
html_footer = '\n'.join(content_footer)
return html_footer