Рефакторинг рендера [этап 3/6]: слияние generate_channel_rss/html вокруг _prepare_feed_posts #30
Reference in New Issue
Block a user
Delete Branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Часть эпика «Рефакторинг пайплайна рендера». Спека:
plans/2026-07-05-render-pipeline-refactor.md(v5), раздел «Этап 3». Зависимость: этап 2 (#29). Line-refs действительны дляf9550d8.Цель
generate_channel_rssиgenerate_channel_html— близнецы на ~80% (branch:347–527 и 578–717): валидация, get_chat с одинаковой обработкой ошибок, история, вызов_render_pipeline, flush — скопированы построчно. Выделить общий препроцессинг; форматтеры становятся тонкими. Поведенческие различия путей (глубина истории, reply-enrichment) сохраняются как ЯВНЫЕ параметры.Пункты реестра §3, фиксируемые этим этапом
except Exceptionоборачивает его в ValueError → 400; маппинги в api_server.py: ValueError→400 — :1334–1337, FloodWait→429 — уже есть и работает для get_chat-пути).detailв 400-ответах унифицируются (исчезает суффикс «in HTML generation»).Конструкция
Форматтеры:
generate_channel_rss:history_limit=limit*2, enrich_replies=False, log_prefix="rss"(RSS over-fetches so merging still yields ~limit posts) → fg-метаданные + entries (rss_date_range-лог сохраняется) →to_thread(fg.rss_str).generate_channel_html:history_limit=limit, enrich_replies=True, log_prefix="html"(enrichment is HTML-only to keep RSS polling cheap — deliberate) → join с<hr>.except ChannelNotFound as e: return create_error_feed(str(e.channel_identifier), base_url)— байт-эквивалентно текущему (prepared-значение используется и сегодня; int/str интерполируются одинаково).generate_channel_rss: …— branch:526,html_generation_error: …— :716): каждый форматтер сохраняет собственный внешний try/except.Тесты
Golden БЕЗ изменений — главный критерий эквивалентности этапа. Новые: ChannelNotFound → error feed в обоих путях; FloodWait из get_chat → 429; FloodWait из истории → 429 (новый, §3.9); прочие ошибки истории → ValueError → 400.
DoD
Один блок get_chat/get_history/render вместо двух; diffstat rss_generator отрицательный; pytest + golden зелёные (golden-дифф пустой).
Общие правила эпика
Ветка
refactor/render-pipelineот f9550d8; один этап = один коммит; комментарии — English; точечные правки.Известный пробел golden-оракула: reply-enrichment не покрыт (учесть при реализации этапа 3)
Обнаружено на этапе 0 (#27 / PR #35):
_reply_enrichment(HTML-путь) делает ЖИВОЙclient.get_messages, минуя tg_cache. В golden-харнессе корпус реплеится через monkeypatchcached_get_chat_history, ноclient.get_messagesтам no-op'ит → enrichment фактически ничего не делает, в HTML-golden рендерятся только shallow-reply, записанные в корпусе. Фабриковать синтетику в golden осознанно НЕ стали (правильно — golden должен оставаться реальными данными).Следствие для этого этапа: этап 3 переносит
_reply_enrichmentв_prepare_feed_posts(enrich_replies=Trueдля HTML). Golden эту ветку НЕ проверяет — значит регрессию в enrichment он не поймает. Поэтому этап 3 ОБЯЗАН нести отдельный unit-тест на enrichment:client.get_messages(chat_id, ids)возвращает сообщение с заполненным.reply_to_message;reply_to_messageпроставляется в исходные сообщения по ключу(chat_id, message.id), (в) отрендеренный reply-блок содержит текст reply-таргета;Без него перенос enrichment в этап 3 окажется вообще непроверенным.