6 Commits

Author SHA1 Message Date
Andrey Epifancev
e8453159e8 Срез 0 [7.1]: горячие папки — набор *.json ответа, готовность по settle, служебный каталог Tmp
- HotFolder.poll(job_id) -> list[AnswerFile] | None: все *.json каталога <output>/<job_id>/ по возрастанию
  имени, когда набор не пуст и имена/размеры не менялись SCAN_SETTLE_SECONDS (SettleTracker: состояние по
  job_id, внедряемые часы, сброс при выдаче/опустении, предел 1024 задания, потокобезопасно);
- put: временный .<name>.part в <корень>/<SCAN_TMP_DIR>/ (создаётся), rename в Input (Local и SMB);
- настройки SCAN_TMP_DIR (Tmp) и SCAN_SETTLE_SECONDS (2, >= 0); в .env.test settle = 0 (R-23);
- воркер: переходная прослойка — берётся первый файл набора (склейка всех — Task 3, R-22).

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-04 14:01:39 +04:00
Andrey Epifancev
d288d19622 Срез 0 [fix T12.4]: тест суррогата в original_name назван по фактическому поведению
Запрос с одиночным суррогатом в `original_name` отвергается схемой (pydantic `string_unicode`), а не «не ломает
публикацию»: тест переименован в `..._is_schema_mismatch` и проверяет код SCHEMA_MISMATCH, отсутствие ack и `put`.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-04 05:02:43 +04:00
Andrey Epifancev
0420c85219 Срез 0 [fix T12.1]: SCHEMA_MISMATCH для задания в работе/обработанного не публикуется
Конверт `result:<job_id>:<attempt>` битого запроса совпадал по Nats-Msg-Id с настоящим результатом, и ядро
(дедуп по result_msg_id) отбросило бы настоящий итог. `_reject` нормализует job_id (`uuid.UUID`, нижний регистр)
и при `_seen` только пишет предупреждение. Тест: битый запрос с тем же job_id во время ожидания ИС и после итога,
в том числе UUID в верхнем регистре — опубликованы только ack и настоящий итог.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-04 05:02:28 +04:00
Andrey Epifancev
d74b56a0d1 Срез 0 [5.4]: тест параллелизма воркера (test_worker_concurrency.py), отметка задачи
Сценарий spec «Пять заданий подряд» переписан детерминированно: паузы опроса горячей
папки управляются тестом (SteppedSleep), ожидания — по событиям с тайм-аутом. Проверяется:
пять ack'ов до освобождения слота, ровно четыре файла и четыре чтения S3 при занятых слотах,
пятый файл — только после итога освобождённого задания, у всех пяти — итоговый конверт.
Добавлены строгая очерёдность при SCAN_MAX_INFLIGHT = 1 и остановка воркера при очереди
на слот (T12.9): задачи отменены, утечек задач и слотов нет, новых файлов нет.
Прежний test_five_jobs_with_four_slots удалён из test_worker.py (без дублирования).

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-04 04:07:38 +04:00
Andrey Epifancev
d199414e9c Срез 0 [5.4]: обвязка тестов воркера — в tests/worker_helpers.py и tests/unit/conftest.py
Фейки S3/NATS, шпион горячей папки, Env, эмулятор ИС и eventually вынесены из test_worker.py
без изменения логики, чтобы ими пользовался отдельный тест параллелизма. make_env получил
подмену sleep (пауза между опросами горячей папки).

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-04 04:03:47 +04:00
Andrey Epifancev
ea49abd03b Срез 0 [5.3]: воркер шлюза (src/core/worker.py) и unit-тесты сценариев spec
on_request проверяет тело (SCHEMA_MISMATCH без ack, R-16), дедуплицирует по job_id
(задания в работе + LRU DONE_CACHE_SIZE, R-17) и запускает задачу: ack до чтения S3 и
до ожидания слота, семафор SCAN_MAX_INFLIGHT, handle. handle: S3 (один бакет, R-19) ->
горячая папка через asyncio.to_thread (R-15) -> опрос до min(reply_deadline, старт +
SCAN_TIMEOUT_SECONDS) (R-14, R-20) -> raw/{job_id}.json до нормализации (R-18) ->
нормализатор -> results/{file_id}/{job_id}/result.json -> конверт. Таблица ошибок D-7,
публикация через NatsGateway с повторами, PublishFailed логируется. Текст ошибки
очищается от одиночных суррогатов и ограничен 4000 символами (T10.1, T10.2).

Тесты: фейки S3/NATS с общим журналом событий, настоящий LocalHotFolder и process_once
эмулятора; каждый конверт проверяется JSON Schema контракта. Фикстура log_lines в
conftest перехватывает loguru. src.core.worker и src.core.health — в строгом mypy.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-04 03:48:37 +04:00