# Исправленные проблемы проекта YOLO Train WebUI Дата исправления и повторной проверки: 2026-07-18 ## Итог Все 10 дефектов аудита от 2026-07-17 исправлены. WebUI снова проходит синтаксическую проверку, серверный обработчик события начала обучения не зависает, WebSocket-сообщения отправляются в event loop ASGI-сервера, а успешное завершение, отмена и ошибка представлены отдельными состояниями. Регрессионный набор расширен с 37 до 49 тестов. | ID | Приоритет | Статус | Исправление | |---|---|---|---| | BUG-001 | Критический | Исправлено | Закрыт `try/catch`, удалено повторное объявление `configForm`, добавлен `node --check` в тесты | | BUG-002 | Критический | Исправлено | Status broadcast вынесен за пределы `threading.Lock`; добавлен тест на отсутствие deadlock | | SEC-001 | Критический при сетевой публикации | Исправлено | Compose публикует loopback, URL запрещены, пути ограничены доверенными корнями, restricted checkpoint loading включён | | BUG-003 | Высокий | Исправлено | Все WebSocket send выполняются в ASGI loop через `run_coroutine_threadsafe`; ошибки логируются, сломанные сокеты удаляются | | BUG-004 | Высокий | Исправлено | Введены состояния `succeeded`, `cancelled`, `failed`; ошибка после stop больше не маскируется как отмена | | DOC-001 | Высокий | Исправлено | README полностью обновлён для WebUI, актуальных CLI-команд, Docker и модели безопасности | | BUG-005 | Средний | Исправлено | Провалидированные классы всегда записываются в итоговый YAML и имеют приоритет над случайным корневым YAML | | BUG-006 | Средний | Исправлено | Числа разбираются с проверкой `Number.isNaN`; нули сохраняются при чтении и восстановлении формы | | BUG-007 | Средний | Исправлено | Серии графика добавляются динамически и выравниваются по эпохам, включая новые ключи метрик | | BUILD-001 | Средний | Исправлено | Docker устанавливает frozen-набор из `uv.lock`; версия `uv` также зафиксирована | ## Жизненный цикл и WebSocket - Событие `started` меняет состояние под lock, но отправляет статус только после освобождения lock. - Event loop запоминается при подключении WebSocket. Вызовы из фонового потока передаются в него через `asyncio.run_coroutine_threadsafe()`. - Отправки сериализуются `asyncio.Lock`, поэтому сообщения одного запуска сохраняют порядок. Ошибка доставки попадает в журнал, а нерабочий клиент удаляется. - Финальная классификация учитывает return code, stop-флаг, последнее структурированное событие и факт принудительной остановки. - Штатная кооперативная остановка даёт `cancelled`; ненулевой код после stop без подтверждённой отмены даёт `failed`. ## Безопасность - `docker-compose.yml` публикует `127.0.0.1:8000:8000`. - Dataset, model и project не принимают URL. - Локальные пути ограничены `datasets`, `models` и `runs`; дополнительные доверенные корни задаются переменными `YOLO_WEBUI_DATA_ROOTS`, `YOLO_WEBUI_MODEL_ROOTS`, `YOLO_WEBUI_RUN_ROOTS`. - Проверка использует разрешённые абсолютные пути после `resolve()`, поэтому symlink/`..` не позволяют выйти из доверенного корня. - Имена профилей валидируются на сервере, а `last_run` нельзя перезаписать через публичный endpoint профилей. - `ULTRALYTICS_SAFE_LOAD=1` включён и в Python-процессе, и в Docker-образе. - Для намеренной удалённой публикации по-прежнему нужен аутентифицирующий reverse proxy; это явно указано в README. ## Frontend - `app.js` снова является валидным JavaScript. - `workers=0`, `patience=0` и `close_mosaic=0` проходят полный цикл form → JSON → localStorage → form без замены default-значениями. - График создаёт dataset при первом ключе метрики и добавляет новые серии в следующих эпохах. Пропущенные значения дополняются `null`, поэтому точки не сдвигаются. - UI и CSS отдельно отображают `succeeded`, `cancelled` и `failed`; старый `finished` оставлен только как frontend-совместимость. ## Датасеты, Docker и документация - Результат `read_classes()` безусловно становится `dataset_data["names"]`, сохраняя при этом остальные ключи выбранного YAML (`kpt_shape`, `flip_idx` и другие). - Docker копирует `pyproject.toml` вместе с `uv.lock` и выполняет `uv sync --locked --no-dev`; обход lock-файла удалён. - README описывает `uv run yolo-train-webui`, `uv run -m yolo_webui`, Compose, структуру датасетов, MLflow и ограничения доверенных путей. ## Добавленные регрессионные проверки Тесты теперь покрывают: 1. синтаксис browser JavaScript; 2. сохранение допустимых нулей и динамические серии Chart.js в Node smoke-test; 3. отсутствие deadlock на событии `started`; 4. доставку сообщения из background thread в loop WebSocket-сервера; 5. различие `succeeded` / `cancelled` / `failed`; 6. запрет URL и выходов за разрешённые корни; 7. защиту зарезервированного профиля `last_run`; 8. приоритет явно указанного `classes.txt` над корневым YAML. ## Выполненные проверки ```text uv run pytest -q -> 49 passed, 1 warning uv run python -m compileall -q src tests -> успешно node --check src/yolo_webui/static/app.js -> успешно node tests/frontend_smoke.js -> успешно uv lock --check -> успешно docker compose config -> успешно, host_ip=127.0.0.1 git diff --check -> успешно ``` Полная сборка Docker-образа локально не запускалась: Docker daemon недоступен. Конфигурация Compose проверена отдельно, а соответствие lock-файла — через `uv lock --check`. Оставшееся предупреждение pytest относится к deprecated-связке `fastapi.testclient`/`starlette.testclient` с `httpx`; оно не связано с исправленными дефектами и не ломает тесты.