# Классификация застряла на 68/84: диагностика 2026-08-27 ## Наблюдение На экране классификация остаётся на `68/84`, хотя контейнер продолжает работать. Проверка через ВМ: ```text GET /api/batch-progress?batch=acbdffe5-e3ec-43f4-ab61-84861cac35bd {"counts":{"classified":68,"garbage":16},"ok":true,"total":84} ``` Повторный запрос вернул то же значение. Kubernetes показывает pod `pythonk8s-574b5cf9b4-z4wxz` в состоянии `Running`, `Ready 1/1`, `RESTARTS 0`. Событий Kubernetes нет. На ВМ `contracts.service` активен, `convert_server.py` запущен в одном экземпляре. ## Причина в коде `site/routes/api_bp.py` возвращает раздельные счётчики `classified`, `failed` и `garbage`, а `total` равен числу всех документов батча. `site/static/app.js` в `runClassify()` считает завершённые документы так: ```javascript var done = (d.counts.classified || 0) + (d.counts.failed || 0); ``` `garbage` в эту сумму не включён. Для текущего батча: ```text done = 68 classified + 0 failed = 68 total = 84 garbage = 16 фактически завершено = 68 + 0 + 16 = 84 ``` Поэтому условие `done >= total` никогда не выполняется, polling не останавливается, а кнопка остаётся на `68/84`. Это ошибка фронтендового подсчёта прогресса, а не зависание Kubernetes или LLM на 68-м файле. ## Исправление В `site/static/app.js` к числу завершённых документов добавлен конечный статус `garbage`: ```javascript var done = (d.counts.classified || 0) + (d.counts.failed || 0) + (d.counts.garbage || 0); ``` Версия приложения повышена с `2.0.17` до `2.0.18`; cache-buster статических скриптов обновлён в `site/templates/index.html`. Kubernetes проверялся только командами чтения через ВМ: `kubectl get`, `kubectl describe`, `kubectl top`, `kubectl logs`. ## Дополнительная проверка загрузки ZIP При проверке загрузки разными способами обнаружен отдельный дефект связи файлов с архивом. `expandZipClient()` создаёт для каждого распакованного файла поле `zip_source`, а `uploadFile(file, onProgress, zipSource)` умеет передавать его в `/api/upload_refs`. Однако вызов `uploadFile()` в цикле `onFilesSelected()` передавал только два аргумента. Поэтому backend получал `zip_source=null`, и связь с исходным ZIP терялась. Проверены архивы: - `testgen/out/zips/duplicates_inside.zip` — целый ZIP, два файла с одинаковым именем; - `testgen/out/zips/mixed_with_error.zip` — целый ZIP, корректный и повреждённый DOCX. Исправление применено в `site/static/files.js`: третьим аргументом передаётся `entry.zip_source`. Для обычных файлов значение `null`, поэтому их поведение не изменяется. Версия приложения повышена с `2.0.18` до `2.0.19`, cache-buster обновлён в `site/templates/index.html`. ## Проверки исправления - `node --check site/static/files.js` — успешно; - frontend upload-тесты — успешно; - layer 2 upload-тесты — успешно; - архивы `duplicates_inside.zip` и `mixed_with_error.zip` прошли `unzip -t`.