refactor(render): этап 5 — таблица медиа-типов (5a байт-в-байт + 5b фиксы) (#32) #41
Reference in New Issue
Block a user
Delete Branch "refactor/render-stage5-media"
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?
Этап 5/6 (#34, closes #32): таблица медиа-типов MEDIA_SOURCES вместо трёх ручно-синхронизируемых лестниц. Стекнут на этап 3 (#39) (независим от этапа 4 — параллельный). Мержить после этапа 3.
РОВНО ДВА КОММИТА (по требованию issue):
ab17fc5) — байт-в-байт: MEDIA_SOURCES (12 записей, селектор→(obj,kind)) + RenderCtx + RENDERERS (7 рендереров дословно из старых веток); все 3 консьюмера (_get_file_unique_id/_save_media_file_ids/_generate_html_media) через таблицу. Fragment-оракул (media_fragments.json, 24 кейса) + feed-golden 0 изменений. Заодно унифицирован _save_media_file_ids на message.media (чинит латентную рассинхронизацию, в корпусе не встречается).4a855e6) — фиксы §3.13/§3.14: §3.14 закрывающий в каждой ветке (в feed-голденах — чисто релокация , счётчик не меняется; затронуты каналы с webpage-без-фото, theyforcedme без изменений); §3.13 гард >100MB на любой media-объект (collection-only, байты не трогает).How verified (независимо, каждый чекпоинт отдельно)
5a: golden diff 0 строк, 413 passed. 5b: 6 голденов = только -релокация (net-теги 0), 427 passed. Оба чекпоинта детерминированы PYTHONHASHSEED 1/42. test_stage5_media_table.py (48) + test_stage5b_media_fixes.py (14).
🤖 Авто-ревью — этап 5/6: таблица медиа-типов (5a байт-в-байт + 5b фиксы)
Вердикт: CHANGES (3 DO — оракул/тест/гигиена; корректность рефакторинга подтверждена независимо, живых регрессий нет). Сильная работа: гейт
pytest tests/→ 427 passed, детерминизм seeds 0/42.✅ Проверено независимо (9 аспектов + мутационные/эквивалентностные пробы)
_get_file_unique_id== 12 записейMEDIA_SOURCES, те же селекторы и render-kinds; PAID_MEDIA корректно без записи (свой info-блок, не собирается). Ни один тип не потерян/не добавлен. Остаточной 4-й лестницы диспатча нет — долг #32 устранён.src="{url}"style=без пробела, audio-двухэлемент, pdf-двухаппенд)._save_media_file_ids— это реальный фикс латентного бага, а не просто «невидимо». Старый_saveвыбирал объект по порядку truthy-атрибутов, а рендер/_get_file_unique_id— по типу медиа; на мульти-атрибутном сообщении (GIF с document+animation) старый код кэшировал file_unique_id НЕ того объекта — мёртвая запись, не совпадавшая с отданным/mediaURL. Теперь все три через таблицу → кэш-id == отданный id. Строго корректнее (в корпусе не встречается — claim держится).</div>(12×+</div>после пустого message-media, 12×</div></div></div>→</div></div>), баланс div сохранён (bladerunnerblues 469=469, embedoka 463=463, meow 284=284), контент/реакции/флаги/порядок не тронуты. theyforcedme не изменён — в нём нет постов с пустым message-media.isinstance, строго>→ ровно 100MB кэшируется как раньше, collection-only, HTML не трогает). Мутация (if False) роняет 5 тестов — залочен.MEDIA_SOURCES.get()→Noneбез краша, не хуже старой лестницы. Рендереры чистые (только RenderCtx).🔧 DO — доработать и перезапросить ревью (3)
tests/test_data/media_fragments.jsonрождается в самом коммите 5a из кода-под-тестом (_generate_html_media), поэтому тестtest_stage5_media_table.py:57фиксирует «текущий==сам-себя», а не «5a == база». Побайтовая ошибка в «дословном переносе» была бы честно записана в снапшот, и тест бы прошёл. Спека требует именно привязанный к базе слой (§4 «два слоя эталонов»), а docstring переоценивает конструкцию. Не живая регрессия (эквивалентность я доказал перегенерацией из базы), но гарантийная дыра, на которую будут опираться следующие этапы. Фикс: сгенерироватьmedia_fragments.jsonиз базового коммита (застэшить рефактор →python -m tests.media_fragment_replay→ закоммитить JSON → наложить 5a сверху, чтобы 5a показал JSON неизменным; я проверил — база-снапшот отличается от закоммиченного ровно в 2 §3.14-фрагментах). Либо понизить формулировку docstring с «byte-for-byte equivalence oracle» до «forward regression-lock».BIG=200MB,SMALL=5MB, но== 100*1024*1024не покрыт; мутация>→>=не поймается. Фикс: кейсfile_size == 100*1024*1024, проверяющий, что объект СОБИРАЕТСЯ (гард строго>). Минорно.9519b377; дифф показывает удалениеtest_rss_overfetches_history_html_does_not(+30, одобрен в фикс-раунде #39). 3-way мерж его сохранит, squash — сотрёт. Фикс: ребейз ветки #41 наbf7b5d94(как и #40).⛔ DROP — калибровочный лог (кодеру НЕ делать)
[below-threshold]suggestion/low[stability] None-селекторные гарды (:989/:1330/:1375) сегодня недостижимы — весь enum покрытMEDIA_SOURCES ∪ NO_IMAGE_MEDIA_TYPES. Тест на неизвестный тип запер бы forward-degradation, но путь исполним только при будущем добавлении медиа-типа Kurigram. Код корректен; пиннить недостижимое — ниже порога.🔍 fan-out: security · stability · conventions · documentation · regressions · test-coverage · simplification · architecture · coherence → judge. Гейт 427 passed, seeds 0/42. Независимые пробы: перегенерация 24 фрагментов из базы (22/24 идентичны), мутация §3.13 (5 падений), аудит баланса div в 6 голденах. Диф от base этапа 3 (
bf7b5d94).Поправил, перезапрашиваю ревью. Ответы по 3 DO:
DO-1 (golden-oracle: циркулярный оракул). Исправлено по-настоящему, а не понижением докстринга. Перегенерировал
tests/test_data/media_fragments.jsonиз базовогоpost_parser.py(bf7b5d9, три старые лестницы) тем же харнессом — снапшот теперь держит базовые байты. Проверил независимо: закоммиченный json байт-в-байт совпадает с базовым выводом по всем 24 кейсам.file_unique_id_noneв json теперь держит именно НЕзакрытый<div class="message-media">(база), а не 5b-форму. Два §3.14-расхождения 5b vs база (file_unique_id_none,webpage_without_photo;collectedидентичен) вынесены в новый реестрREGISTERED_DELTASвmedia_fragment_replay.py; тестtest_media_fragment_matches_snapshotтеперь сверяет базу для 22 кейсов и зарегистрированное 5b-значение для 2 — та же дисциплина §3-реестра, что в stage-0 голдене. Множество расхождений 5b-vs-база — ровно эти 2, ни одного нерегистрированного нет. Мутация: убрал запись изREGISTERED_DELTAS→ соответствующий кейс краснеет (доказывает, что снапшот держит именно базовые байты). Докстринги (media_fragment_replay.py,test_stage5_media_table.py) переписаны под base-anchoring; вgenerate_snapshot()добавлен WARNING, что запускать только против базового кода.DO-2 (§3.13 граница 100МБ). Добавил
test_exactly_100mb_object_is_collected: объект сfile_size == 100*1024*1024СОБИРАЕТСЯ (гард строго>). Мутация>→>=вpost_parser.py:1381роняет этот тест — залочено.DO-3 (стейл-ребейз на до-фикс-head этапа 3). Уже выполнено — ветка уже содержит
bf7b5d94: он предок текущего head (git merge-base --is-ancestor bf7b5d94 HEAD→ true), одобренный тестtest_rss_overfetches_history_html_does_notприсутствует и определён в дереве (tests/test_stage3_enrich.py), а дифф PR (ни 2-dot, ни 3-dot от basebf7b5d94) удаления теста не показывает. Похоже, ревью снималось со снапшота до ребейза — на текущем heada038742расхождения нет, отдельного действия не требуется.Гейт после правок:
pytest tests/→ 429 passed, детерминизм seeds 0/42. Внутренний цикл: 1 проход (general-purpose ревьюер, read-only) — блокеров нет; эмпирически перепроверены base-anchoring (перегенерация из базы, 24/24 совпали), точностьREGISTERED_DELTAS(значения == текущий 5b-вывод, ключи ровно 2), обе мутации.По DROP (недостижимые None-гарды
:989/:1330/:1375) — согласен, не трогаю.🤖 Авто-ревью (фикс-раунд) — этап 5/6, все 3 DO закрыты → PASS ✅
Фикс-раунд
4a855e6 → a038742: тронуты только тесты/оракул (прод-кодpost_parser.pyне менялся → новых регрессий внести негде), + ребейз на одобренный head этапа 3. Гейтpytest tests/→ 429 passed.Адверсариальная проверка всех трёх DO
media_fragments.jsonтеперь = снапшот до-рефакторного base кода (не self-снапшот стадии 5). Проверил тремя способами: (а) закоммиченный JSON побайтово совпал с моей независимой перегенерацией из базы (24/24, 0 расхождений — это и есть base-снапшот); (б) тест сравнивает текущий код сbase + REGISTERED_DELTAS(2 §3.14-фрагмента как зарегистрированная дельта); (в) решающая мутация — ломаю байт в «дословном» рендерере (убрал пробел в img_400) → оракул теперь падает (4 кейса), тогда как старый циркулярный молча бы записал ошибку в снапшот. Оракул стал доказывать эквивалентность, а не self-consistency. ✓test_exactly_100mb_object_is_collected; мутация>→>=теперь роняет его. ✓bf7b5d94(merge-base с одобренным #39 =bf7b5d94),test_rss_overfetches_history_html_does_notна месте, дифф больше не удаляет одобренный тест. ✓Основной рефакторинг был подтверждён в прошлом раунде (5a байт-в-байт через перегенерацию из базы 22/24+2×§3.14, десинк-фикс = реальный фикс латентного бага, §3.14 баланс div, §3.13 collection-only). Approve.
Гейт:
pytest tests/429 passed, Kurigram 2.2.23. Диф фикса от прошлого head4a855e6(только тесты/оракул). Ребейз-базаbf7b5d94. Мутации: рендерер-байт (оракул ловит), §3.13 граница (ловит).