train_utility/.agents/PROJECT_ISSUES.md
2026-07-21 14:57:01 +04:00

105 lines
8.3 KiB
Markdown
Executable file
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Исправленные проблемы проекта 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`; оно не связано с исправленными
дефектами и не ломает тесты.