16 KiB
Незакрытые задачи после аудита
Состояние на 10 сентября 2026. Всё перечисленное — то, что осталось после прохода по плану оптимизации. Что уже сделано, см. audit-report.md.
Тесты сейчас: 320 passed, 1 skipped, 174 subtests, полный прогон 11.85 с. Ничего не закоммичено — всё лежит в staging и рабочем дереве.
P0 — сломает сборку, если не сделать
mdexport/ не добавлен в git
Пакет mdexport/ (общий обходчик AST для md2latex и md2fodt) создан, но остался untracked, при этом на него уже завязаны:
pyproject.toml— перечислен в[tool.hatch.build.targets.wheel].packagesmd2latex/emitter.py,md2latex/escape.pymd2fodt/emitter.py,md2fodt/escape.py
На свежем клоне оба конвертера упадут с ModuleNotFoundError, сборка колеса тоже. Локально работает только потому, что файлы лежат на диске.
git add mdexport/blocks.py mdexport/inline.py mdexport/labels.py mdexport/__init__.py
git status --short mdexport
Скомпилированные .pyc внутри уже покрыты правилом __pycache__/, добавлять их не нужно.
P1 — найденный баг, теряет данные
word2md выбрасывает пункты списка при смене его типа
Найден при разборе _handle_paragraph. Баг существовал и до рефакторинга, его сохранили намеренно, чтобы правка осталась поведенчески нейтральной.
word2md/walker.py, строки 406-429. Оба обработчика списков заканчиваются на return [], выбрасывая накопленный out — притом что _flush_code(out) и _flush_list(out) внутри уже успели в него дописать:
def _as_numbered_list_item(self, para: _Para, out: list[Block]) -> list[Block] | None:
if not paragraph_has_numpr(para.paragraph):
return None
self._flush_code(out) # может дописать в out
...
self._append_list_item(ordered, body, out) # внутри вызывает _flush_list(out)
return [] # <- out выброшен
_append_list_item (строки 431-437) при смене типа списка вызывает _flush_list(out), который сбрасывает накопленные пункты в out. После чего return [] их теряет. Соседний _as_plain_paragraph (строка 439) в такой же ситуации корректно делает return out.
Воспроизведение: два упорядоченных пункта с numPr, за ними пункт-буллет. Оба упорядоченных пропадают из результата. Тот же механизм теряет и забуференный код, если он был.
Порядок работ: сначала красный тест на исчезающие пункты, потом замена return [] на return out в обоих обработчиках, потом проверка, что побайтовая сверка вывода на остальных документах не поехала (она поедет только там, где баг срабатывал).
P1 — решено, но не выполнено
Калибровка Courier New 10 пт
Ты выбрал вариант «10 пт канон по табл. 4.1, добавить калибровку и перевести тест-фикстуру». Не сделано — я не успел запустить задачу до конца сессии.
Что именно нужно, в md2gost/renderable/paragraph_sizer.py, метод Font.get_line_height (строки 78-83):
# TODO: make it work for all fonts
if "Times" in str(self._face.family_name) and self._freetypefont.size == 14:
return Pt(16.05)
if "Courier" in str(self._face.family_name) and self._freetypefont.size == 12:
return Pt(13.61)
Сейчас калиброванная ветка есть только для Courier 12 пт. Замеры, снятые в ходе аудита:
| Размер | Возвращает сейчас | Фактическая высота |
|---|---|---|
| Courier 10 пт | 11.000 | ≈ 11.34 |
| Courier 11 пт | 12.000 | — |
| Courier 12 пт | 13.610 (калибровка) | 13.61 |
| Courier 14 пт | 16.000 | — |
Целые числа выдаёт округление FreeType; калибровочные ветки существуют ровно затем, чтобы подменить округление реальным значением Word. Пропорция от 13.61 при переходе 12 → 10 пт даёт примерно 11.34.
Итог: пока ветки для 10 пт нет, каждая строка листинга меряется примерно на 3% короче, и на длинных листингах разъезжаются разрывы страниц.
Порядок работ:
- Добавить ветку
Courier+ размер 10 →Pt(11.34). Лучше сначала подтвердить число замером в Word через COM, а не принимать пропорцию на веру. - Перевести
tests/__init__.py(строка 27) сPt(12)наPt(10), чтобы фикстура совпадала сstyle_config.py:305и табл. 4.1. - Прогнать
tests/test_paragraph_sizer.py— серияtest_count_lines_courier1..10завязана на текущую высоту, ожидаемые значения поедут.
Не делай пункт 2 без пункта 1 — иначе калиброванная ветка перестанет срабатывать, и замер станет хуже, чем сейчас.
Other_Code/ — 59 файлов, 1158 КБ
Это была Фаза 4.2 плана, и я её просто не назначил ни одному исполнителю при раскладке работ. Каталог до сих пор полностью в git.
Ни одного импорта из md2gost, word2md, md2latex, md2fodt, tests/; не упоминается в .spec, .bat, .github/workflows/, pyproject.toml. Единственные ссылки — раздел 12 в PROJECT.md и внутренние перекрёстные ссылки самого каталога.
Команды и три варианта действий расписаны в git-cleanup.md, раздел 1.
Личные документы в корне
ТарасовИА_КР_v3.docx (2326 КБ) и Практическая_работа_6.docx (42 КБ) — ФИО прямо в имени файла. Ты сказал, что уберёшь руками; команды и предупреждение про ловушку с md2gost/Template.docx в git-cleanup.md, раздел 2.
P2 — открытые вопросы по методичке
«С новой страницы» для надписи листинга
Табл. 4.1 (docs/reference/method-mirea-2022.txt, строки 714-715) в блоке «Положение на странице» перечисляет и «Не отрывать от следующего», и «С новой страницы».
В md2gost/style_config.py у стиля Caption Listing (строки 278-291) есть keep_with_next=True, но нет page_break_before=True. Вопрос не праздный: в репозитории есть целая система режимов --listing-continuation, так что отсутствие разрыва может быть осознанным выбором. Плюс Caption.__init__ теперь явно ставит page_break_before = False, чтобы не плодить пустые страницы при сочетании с keep_with_next — то есть менять придётся согласованно в двух местах.
Решение нужно принять до того, как кто-то «починит» это по табл. 4.1 в лоб.
Правило heading.empty ложно срабатывает внутри листингов
Новое правило в md2gost/checker/__init__.py не вырезает fenced-блоки, поэтому одинокая строка # внутри блока кода будет засчитана как пустой заголовок. Поведение консистентно с уже существующим HEADING_RE в том же файле, то есть это общая для checker'а проблема, а не привнесённая. Чинить имеет смысл сразу для всех проверок заголовков.
P3 — не начатое из Фазы 6
Всё это помечено в плане как опциональное. Ничего из перечисленного не сделано, кроме общего обходчика AST и разбора word2md/_handle_paragraph.
Разбиение idef0.py
1935 строк (сейчас 74 КБ). God-функции: _parse_arrow_line (~177 строк), _draw_kit_form (~121), _route_icom (~110), _draw_arrow (~83), _layout_arrow_label (~80).
Предлагаемая раскладка в пакет idef0/: model.py, parse.py, layout.py, routing.py, scene.py, draw.py, render.py, с реэкспортом публичного API из __init__.py ради тестов. Выигрыша в скорости не даёт, только читаемость.
Отдельно там же: _Scene.to_png() и _Scene.to_svg() дважды обходят один и тот же список операций. Можно сгенерировать SVG и растеризовать его в PNG.
Разбиение gui.py
1695 строк (82 КБ) в одном классе Md2GostApp: главное окно, шесть диалогов, редактор UML-схем на ~270 строк, композер промптов, логика перезаписи файлов, потоки конвертации, загрузка ассетов.
Раскладка: gui/windows/, gui/widgets.py, gui/convert_runner.py, а Md2GostApp оставить тонкой оболочкой.
Ленивые импорты
md2gost/pipeline.py (строки 15-19) и md2gost/gui.py (строки 11-32) тянут весь конвейер на старте: docx, pygments, PIL, lxml. python -m md2gost --help платит за это полную цену. Matplotlib и playwright уже ленивые — сделать так же с остальным.
Общий сборщик ConvertRequest
gui.py (строки 1730-1760) и __main__.py (строки 272-317) дублируют маппинг примерно двадцати полей и уже разошлись: дефолт типа документа в GUI coursework, в CLI practice.
Флаг --open
__main__.py строки 315-316: open_when_done=bool(args.debug). Открытие готового файла привязано к дебагу, отдельного флага нет, хотя в GUI есть галочка.
Скачивание PlantUML блокирует Tk
gui.py строка 1537 — синхронный вызов fetch_plantuml_jar, тогда как Graphviz (1576) и Chromium (1622) рядом уже качаются в отдельном потоке.
P3 — документация не догоняет код
Таблицы модулей в PROJECT.md не знают про mdexport
Новый пакет mdexport не попал в разделы с картой репозитория и перечнем модулей — исполнитель не владел этим файлом и намеренно его не трогал. Заодно стоит убрать оттуда упоминания удалённых прототипов, если раздел 12 их ещё перечисляет.
P4 — замечания исполнителей, оставленные как есть
uv.lockв порядке.uv lockотработал с сетью, добавил matplotlib 3.11.1 с транзитивными зависимостями,uv lock --checkпроходит. Лок синхронен и по matplotlib, и поpywin32— пересобирать не нужно.- Playwright закрывается в конце
convert(). Это и было целью Фазы 3.4, но у GUI-сценария появилась плата: при каждой следующей конвертации браузер поднимается заново вместо переиспользования. Если mermaid-диаграммы конвертируются часто, стоит подумать про пул с таймаутом. - Кастомный
--plantuml-jarдругой версии не отражается в ключе кэша. Префикс использует прибитую константуPLANTUML_VERSION. Фингерпринт самого файла закрыл бы дыру, но заставлял бы кэш протухать при каждом появлении и исчезновении jar. - Версия jar в ключе кэша задевает и Kroki-рендеры, потому что не-mermaid типы делят один путь кэша между бэкендами. Бамп версии обесценит и записи, отрисованные через Kroki. Это лишняя перерисовка, не более.
- Если одна диаграмма роняет батч-JVM, отбрасывается вся пачка и каждая диаграмма уходит на свою JVM. Корректно, но стоит одной впустую потраченной JVM.
--syntax-highlighting --strict --checkтеперь завершается с кодом 1, потому что новое правилоlisting.syntax_highlightingпод--strictстановится ошибкой. Это ровно то поведение, которое закладывалось, но про него надо помнить в скриптах.- Playwright изредка печатает
Task was destroyed but it is pendingна выходе интерпретера при большом комбинированном прогоне. Не воспроизвелось повторно, все тесты проходят, тот же путь закрытия вызывался и до правок. - Правила игнора
/tmp_*.pngи/tmp_*.pumlзахватили рабочие черновикиtmp_org_full.*,tmp_org_uml.*,tmp_arch.*. Файлы на диске целы, но изgit statusпропали. todo.txtв корне остался нетронутым — это твой личный блокнот, я его не трогал и не сливал с этим файлом.
Что стоит сделать перед коммитом
git add mdexport/— иначе всё сломается на свежем клоне.- Просмотреть
git diff --cachedиgit diff— там 34 файла изменений плюс 8095 удалённых строк. - Прогнать
.venv\Scripts\python.exe -m pytest -qещё раз послеgit add. - Собрать exe одним из
build-exe*.bat— ни один из билд-скриптов в ходе аудита не проверялся, аpyproject.tomlи состав пакетов поменялись.