ЭПИК: рефакторинг пайплайна рендера (спека v5, этапы 0–6) #34
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?
Зонтичное ишью рефакторинга рендер-пайплайна фидов (RSS/HTML). Источник истины — спека
plans/2026-07-05-render-pipeline-refactor.md(v6, пять раундов адверсариального ревью; журнал — §8 спеки).СТАТУС (2026-07-07): этапы 0–5 влиты в main, зелёные
main tip
cd758d5— полный сюит 443 passed, включая golden-оракул. Мёрж-верификация архитектором: стек собран (4∪5 без конфликтов), суммарная дельта golden по 4 реальным каналам = ровно §3.1 (<s>/del), §3.3 (<hr>), §3.6 (реакции-span), §3.8 (порядок флагов); всё прочее NET-0 (переверстка). Поэтапная атрибуция сошлась: этап 3 golden-дельта 0 (чистый рефактор), этап 4 — 0 на реальных каналах (None-date в корпусе нет), ни один media-URL не изменился.Осталось: этап 6 (косметика, #33) — PR ещё нет.
Чеклист этапов
Живые баги, закрытые по пути (в main)
<hr>-разделители, fail-open санитайз (stored-XSS путь), незакрытый media-div — этапы 1/5.Дальше по общему плану (см. коммент с порядком реализации)
После этапа 6 — кэш-эпик (#23–#26). Кросс-зависимость: аллоулист снапшота #23 обязан совпасть с таблицей
MEDIA_SOURCES(теперь она в main, этап 5) — иначе cache-hit ломает рендер новых медиа-типов. #24 (lowercase channel key) при мёрже переснимает render-golden. Детали — комментарии к #23/#24.Правила для исполнителя (дублируются в каждом ишью)
pytestполностью зелёный.История: #22 (этап 1 по v1 спеки) закрыто как superseded этим набором.
Обновление: спека → v6 (golden-корпус — записанные реальные сообщения вместо синтетики; #27 переписано соответственно).
Статус предусловий этапа 0 — уже выполнены вне ишью:
data/tgcache_prod_2026-07-05/(90.cache+ 89.chatinfo, 53 МБ, вне git);Кодеру в #27 остаётся: отбор каналов из снапшота →
tests/test_data/recorded/→ реплей-загрузчик → снятие golden.Кросс-зависимость с эпиком оптимизации кешей (#23–#26, спека
plans/cache-optimization-spec.md)Эпики независимы по коду, но пересекаются в 4 точках. Координация зафиксирована комментариями в #23/#24.
#23 (pickle→
CachedMessage) ↔ #27 golden + #32 MEDIA_SOURCES — КОРРЕКТНОСТЬ. После #23 прод-путь cache-hit кормит рендерCachedMessage, а неMessage. Аллоулист снапшота #23 сейчас НЕ покрывает новые медиа-типы (story/live_photo/paid_media/giveaway/checklist/… + poll.description_media), которые читает рендер → на cache-hit они молча пропадают. Контракт «поля, которые трогает рендер» = таблицаMEDIA_SOURCES(#32). Детали и рекомендация по сиквенсингу (#23 после #32) — в комментарии #23.#23 Package B (префиксный limit) ЧИНИТ то, что §7 спеки рендера объявлял «отложенным». Вечный miss-цикл dual-consumer каналов (RSS
limit*2/ HTMLlimit) закрывается префиксной выдачей истории в #23 — механизм лучше, чем «limit в имени файла» из §7. §7 спеки рендера поправлен: не «отложено», а «делается в #23».#24 (lowercase channel key) → переснять feed-golden рендера (#27). Меняет подписанные media-URL и футер-ссылки. Кто мёржится вторым — ребейзит golden. Детали — в #24.
#25/#26 (Package D/E, /media hot path) ↔ #32 инвариант-тест. Инвариант-тест этапа 5a вызывает
api_server.find_file_id_in_message. Package E рефакторит /media — НЕ переименовывать/не удалятьfind_file_id_in_messageбез правки #32, иначе тест краснеет.Сводно по порядку: идеальная последовательность — сначала PR #21 (kurigram) в main, затем эпик рендера (особенно #32, фиксирующий MEDIA_SOURCES), затем кэш-эпик (#23 выводит аллоулист из MEDIA_SOURCES). При параллельной работе пункты 1 и 3 — обязательные точки синхронизации.
Порядок реализации для одного кодера (канонический)
Макро: весь рендер-эпик → влить в main → кэш-эпик. Так снимаются все кросс-зависимости, golden пересматривается ровно один раз, кросс-эпик merge-конфликтов нет.
Старт:
refactor/render-pipelineот актуальногоmain(88ac436+).Блок 1 — рендер (этап = коммит, между ними
pytestзелёный):→ влить в main.
Блок 2 — кэш (ветки от обновлённого main, каждый PR-юнит отдельно):
8. #23 Package A+B+F — аллоулист снапшота выводится из готовой
MEDIA_SOURCES(#32)9. #24 Package C — строго после #23; переснять render-golden в этом же PR (lowercase меняет media-URL)
Свободно: #25 (D), #26 (E) — ни от чего не зависят, можно в любой момент отдельными PR. Ограничение: не переименовывать
find_file_id_in_message(инвариант-тест #32).Обоснование «рендер раньше кэша»: #23 выводит аллоулист из финальной
MEDIA_SOURCESвместо ручного переоткрытия (иначе тихо ломает cache-hit-рендер новых типов); #24 переснимает golden, который уже в main; оба эпика правят post_parser/api_server — последовательность на main убирает merge-ад.