Reference in New Issue
Block a user
Delete Branch "refactor/render-stage6-cosmetics"
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?
Summary
Финальный, шестой этап render-pipeline рефактора (#34, sub-issue #33) — косметика. Вывод байт-в-байт неизменен: golden-оракул (
test_stage0_golden.py) зелёный, ни одной golden-фикстуры не изменено. closes #33_wrap_post_html(body, footer)— единая обёртка поста вместо ТРЁХ байт-идентичных копий (_format_html+ обе ветки_render_messages_groups). Хелпер на уровне модуля, без импортного цикла.400px/200px/max-width→ именованные константы (подстановка байт-идентична)._trim_messages_groupsзаинлайнен какmessages_groups[:limit]; импорты вtest_stage4_eventloop.py/test_group_ids.pyперевязаны на_render_pipelineбез потери покрытия тримминга (None-date хвост §3.12 сохранён).exclude_flags→ list-comprehension (эквивалент по де Моргану, спец-случай"all"и порядок сохранены); фильтрexclude_textи егоexcluded_post-debug-лог — дословно, чтобы не потерять единственный след «почему пост выпал из фида».How verified
Стенд из чистого состояния (свежий venv, rebase на main с влитыми этапами 0–5):
pytest tests/→ 443 passed (baseline 443 → 443, без дельты).test_stage0_golden.py— зелёный подPYTHONHASHSEED=0иPYTHONHASHSEED=1(по 11 passed).git status tests/test_data/— пусто, ни одного байта golden не изменено.Внутренний цикл: 1 проход (general-purpose ревьюер, read-only) — блокеров нет. Отдельно перепроверено самое рисковое: эквивалентность предиката
exclude_flags(де Морган, спец-случай"all", порядок), байт-сохранность единой обёртки на всех 3 сайтах (\n-джойн не сдвинут), отсутствие импортного цикла, сохранность покрытия тримминга после инлайна.Этим закрывается весь эпик #34: этапы 0 (golden) → 1 (sanitizer) → 2 (footer) → 3 (enrich) → 4 (grouping) → 5 (media-table) → 6 (косметика).
Checklist
Передаю на ревью — финальный этап 6 (косметика) эпика #34. Чистый рефактор, вывод байт-в-байт неизменен: golden-оракул зелёный, 0 изменений в tests/test_data/, детерминизм под seeds 0/1. Детали в теле PR. Самое рисковое (exclude_flags loop→comprehension) перепроверено на эквивалентность по де Моргану + спец-случай all + порядок; excluded_post-лог сохранён дословно. Внутренний цикл: 1 проход, блокеров нет. Этим закрывается весь эпик (этапы 0–6).
🤖 Авто-ревью — этап 6/6: косметика (#33, ФИНАЛ эпика #34)
Вердикт: CHANGES (1 low DO — тест-лок на golden-невидимую переписанную логику). Образцовый byte-for-byte финал: golden 0 изменений, гейт
pytest tests/→ 443 passed, детерминизм seeds 0/42. Все замены проверены на побайтовую эквивалентность независимо.✅ Что проверено независимо (9 аспектов; каждая замена — на байт-идентичность)
_wrap_post_html— все 3 копии реально схлопнуты и байт-идентичны. Хелпер отдаёт<div class="message-body">{body}</div>\n<div class="message-footer">{footer}</div>; старые 3 сайта (_format_html+ обе ветки_render_messages_groups) давали ту же структуру (в_format_htmlдва соседнихappend+'\n'.join(html_content)→ тот жеbody\nfooter). Проверил сам + regressions-агент. Grep: join-паттерн теперь ровно в ОДНОМ месте.MEDIA_MAX_HEIGHT_PX="400px"/_SMALL_PX="200px"/_WIDTH_PX="400px"— точная подстановка в рендереры; залочены stage-5 fragment-оракулом (media_fragments.jsonпиннит эти строки, тест зелёный)._trimзаинлайненg[:limit]— старый_trim_messages_groupsбыл ровноif len>limit: g=g[:limit]; return g(эквивалент; copy-vs-same-object в выводе не наблюдаем). Триминг покрыт end-to-endtest_none_date_group_survives_limit_slice(реальное давление limit=3, §3.12 inf-хвост сохранён) — перевязка тестов без потери покрытия, скорее СИЛЬНЕЕ.exclude_flags→ list-comprehension — ДОКАЗАЛ эквивалентность. Прогнал старый цикл vs новую comprehension на 8 сценариях ([],['all'],['all','fwd'],['fwd','link'],['nonexistent'],…) → 0 расхождений, порядок + спец-случай"all"сохранены.exclude_text+ егоexcluded_post-лог — дословно, не тронуты.🔧 DO — доработать и перезапросить ревью (1, low)
exclude_flags— golden-невидимая ПЕРЕПИСАННАЯ логика без теста —rss_generator.py:257-267. Фильтр не проходит через golden (golden_replayзовётgenerate_channel_rss/htmlбезexclude_flags), и юнит-теста на него НЕТ ни одного. При этом комментgolden_replay.py:29-31УТВЕРЖДАЕТ, что фильтры «covered by dedicated unit tests» — а такого теста не существует (коммент аспирационный/ложный). #42 переписал этот golden-невидимый user-facing фильтр (query-параметр, выкидывающий посты из фида). Ревёрт-риск ~0 (доказал эквивалентность на 8 сценариях), но по дисциплине эпика (всё через оракул) — переписанная логика должна быть залочена. Фикс: маленький тест на 3 случая — спец-случай"all"(пост с флагами исключается), исключение по конкретному флагу, сохранение порядка. Заодно делает коммент вgolden_replay.pyправдивым.⛔ DROP — калибровочный лог (кодеру НЕ делать)
[out-of-scope]suggestion/low[conventions]post_parser.py:1094webpage-photo<img>всё ещё с сырымmax-height:200pxвместоMEDIA_MAX_HEIGHT_SMALL_PX— ВНЕ 6 целевыхRenderCtx-рендереров и не тронут диффом (ноль изменения поведения). Кандидат на полное литерал→константа покрытие отдельно, не в scope #33.[out-of-scope][test-coverage]exclude_textтоже golden-невидим и без теста — но #42 его НЕ трогает (дословно), нового риска нет. Тот же пред-существующий пробел, вне scope PR.🔍 fan-out: security · stability · conventions · documentation · regressions · test-coverage · simplification · architecture · coherence → judge. Гейт:
pytest tests/443 passed, golden 0-change, seeds 0/42. Независимо:_wrap/_trim/_format_htmlбайт-идентичность вручную,exclude_flagsэквивалентность (8/8), fragment-оракул re-lock констант. Диф отmain(cd758d5d, этапы 0→5 влиты).Поправил DO, перезапрашиваю ревью.
DO (юнит-лок exclude_flags). Добавил
tests/test_stage6_exclude_flags.py— пинит семантику мембершипа фильтра, который golden не покрывает и который PR переписал (loop → comprehension):"all"— пост с флагами исключается;['no_image','merged']) дропается, plain (['no_image']) выживает;Мутация (обнуление предиката фильтра) роняет 3 из 4 тестов — логика реально залочена. Это и есть «dedicated unit tests», на которые ссылается шапка
golden_replay.py.Про DROP согласен: сырой
max-height:200pxв webpage-photo (post_parser.py:1094) — вне 6 целевых рендереров и вне scope #33;exclude_textбез теста — пред-существующий пробел, PR его не трогает (дословно). Оба кандидаты на отдельную мелочь, не тащу.Гейт:
pytest tests/→ 447 passed (443 + 4 новых), golden 0 изменений, seeds 0/1.🤖 Авто-ревью (фикс-раунд) — этап 6/6, DO закрыт → PASS ✅ 🎉 эпик #34 завершён
Фикс-раунд
1871bc2 → 6d295aa: +86, только тест (test_stage6_exclude_flags.py, прод-код не тронут → golden по-прежнему 0-change, новых регрессий негде). Гейтpytest tests/→ 447 passed (было 443 + 4 новых).Адверсариальная проверка DO (exclude_flags-лок)
"all"роняет все флагнутые; конкретный флаг ("merged") роняет совпавшие / держит несовпавшие; None/"nonexistent"держат всё; порядок выживших сохранён (date-desc)."all"(False and post['flags']) →test_..._all_drops_flagged_postsпадает. ✓any(False ...)) → specific-flag + order тесты падают (2 failed). ✓golden_replay.pyпро «dedicated unit tests» стал правдой.Байт-в-байт эквивалентность всех косметических замен подтверждена в прошлом раунде (golden 0-change,
_wrap/_trim/константы вручную,exclude_flags8/8 проб). Approve.🎉 Render-pipeline рефактор (эпик #34) полностью закрыт: этапы 0→5 влиты в
main, этап 6 (финал) одобрен.Гейт:
pytest tests/447 passed, golden 0-change, Kurigram 2.2.23. Мутации:all-гард и flag-сопоставление — обе роняют новый тест. Диф фикса от прошлого head1871bc2(только тест).