68 Commits

Author SHA1 Message Date
Andrey Epifancev
94ab9e90d1 openspec: архив hotfolder-direct-write (#26)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-09 17:23:21 +04:00
Andrey Epifancev
7d8a506f4d fix(hotfolder): ошибка открытия входящего файла не удаляет файл прошлой доставки (#26, I-1)
Открытие вынесено из блока снятия недописанного файла: при SCAN_CLEANUP=true
удаляется только файл, сбойнувший после открытия. Решения R-5…R-8 — в design.md.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-09 16:54:54 +04:00
Andrey Epifancev
3413328f02 docs: прямая запись в Input, SCAN_TMP_DIR только у эмулятора, таймаут 1200 с (#26)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-09 16:41:32 +04:00
Andrey Epifancev
85f4e9c847 openspec: change hotfolder-direct-write — запись прямо в Input, как в старом АРМ (#26)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-09 16:22:07 +04:00
Andrey Epifancev
89c14542bc openspec: архив nats-files-subjects (#22)
Change слит PR #23; спеки обновлены (subject'ы files.tabular_uploaded,
files.img_uploaded, files.tabular_parsed).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012vJkmBGKKqMoEMzvsXG3y2
2026-10-08 23:50:30 +04:00
Andrey Epifancev
6c287ef4bc nats: subject'ы как в старом АРМ — files.*_uploaded, files.tabular_parsed (#22)
Решение владельца 08.10.2026: recognition.tabular.request → files.tabular_uploaded,
recognition.image.request → files.img_uploaded, recognition.result →
files.tabular_parsed (общий subject ack и результатов; files.img_parsed не
используется). Тела сообщений, Nats-Msg-Id, queue group'ы и schema_version не
меняются. Константы api/src/contract/subjects.py, докстринги, тесты, README,
CLAUDE.md; копии схем api/contracts/ из docs/contracts/ побайтно; change
nats-files-subjects с дельтой спеки. Сквозной change — RSHB/arm-ka-docs#74.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012vJkmBGKKqMoEMzvsXG3y2
2026-10-08 23:46:19 +04:00
Andrey Epifancev
c81ec9a66c feat(normalizer): разлеплять склеенные строки ИС «1500\n1700» (#16, OQ-156)
ИС возвращает соседние строки формы одной строкой: в ячейке кода несколько
целых кодов через перевод строки, суммы — тоже. Раньше строка пропускалась как
нечисловой код, и в ББ РБ и Счастливочной за 1 кв. 2025 не было 1500 и 1700.

- rows.split_merged_row: N ≥ 2 целых кодов и ровно N частей в каждой непустой
  ячейке значений → N строк до классификации; наименование делится так же или
  остаётся целым; уверенность — исходной ячейки. Иначе — поведение прежнее.
- Предупреждение таблицы «строк с несколькими кодами разлеплено: N».
- Решение №36 в design.md Среза 3a (отклонение от источника), README.

Эталоны нормализатора — отдельный PR в arm-ka-fixtures; правило — §11.1 п. 4.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 12:59:22 +04:00
Andrey Epifancev
f5cd47870d openspec/config.yaml: источник истины DBML v5.13 → v5.17 (#13)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012vJkmBGKKqMoEMzvsXG3y2
2026-10-07 23:42:03 +04:00
Andrey Epifancev
98f21297bb openspec: архив change slice-3a-ocr-normalizer (2026-10-07), спеки image-recognition-gateway и scan-emulator
Ссылки README и CLAUDE.md переведены на архив.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012vJkmBGKKqMoEMzvsXG3y2
2026-10-07 05:07:07 +04:00
Andrey Epifancev
1c39ca1b73 docs(scan-gateway): README и спека — запись .part по №32/№35
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012vJkmBGKKqMoEMzvsXG3y2
2026-10-07 04:05:35 +04:00
Andrey Epifancev
b411b7e128 docs(openspec): решение №35 — повтор put при существующем назначении
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012vJkmBGKKqMoEMzvsXG3y2
2026-10-07 03:43:35 +04:00
Andrey Epifancev
22025ecabe docs(openspec): решения №30–34 по итогам финального ревью (Money, длина дат, .part, дубли yaml, дубли кодов), уточнение №29
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012vJkmBGKKqMoEMzvsXG3y2
2026-10-07 03:24:56 +04:00
Andrey Epifancev
02c6bc8762 docs(openspec): решения №28–29 — статус при ошибочном файле набора, предупреждение о пропущенных строках
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012vJkmBGKKqMoEMzvsXG3y2
2026-10-07 03:06:52 +04:00
Andrey Epifancev
140ec5b713 docs(openspec): спека — schema_version результата 1.0 (№14), cleanup удаляет всё содержимое Output/<job_id>/
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012vJkmBGKKqMoEMzvsXG3y2
2026-10-07 02:51:53 +04:00
Andrey Epifancev
bef8441ca8 docs(scan-gateway): README/CLAUDE.md под Срез 3a, roundtrip с документами, tasks.md
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012vJkmBGKKqMoEMzvsXG3y2
2026-10-07 02:42:49 +04:00
Andrey Epifancev
a12a603657 docs(openspec): решение №27 — при выключенной очистке сирот .part не логируем
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012vJkmBGKKqMoEMzvsXG3y2
2026-10-07 01:45:41 +04:00
Andrey Epifancev
6b2087f57f docs(openspec): решение №26 — снятие .part при публикации не зависит от SCAN_CLEANUP
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012vJkmBGKKqMoEMzvsXG3y2
2026-10-07 01:08:40 +04:00
Andrey Epifancev
37b36047fe docs(openspec): решения №21–25 (Task 8: values по колонкам, лукалайки только для дат, пустая редакция, form_name)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012vJkmBGKKqMoEMzvsXG3y2
2026-10-07 00:36:20 +04:00
Andrey Epifancev
81081a90c7 docs(openspec): решения №17–20 без обсуждения (Срез 3a, Task 1–5)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012vJkmBGKKqMoEMzvsXG3y2
2026-10-07 00:16:38 +04:00
Andrey Epifancev
86fa779c0c openspec/plan: Срез 3a приведён к DBML и 2b — повтор кода (№15), string_value только для нечисла (№16)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012vJkmBGKKqMoEMzvsXG3y2
2026-10-06 23:27:42 +04:00
Andrey Epifancev
b1da9b8774 plan: Срез 3a — Task 0 выполнена (main с v1.2 влит, 749 passed), OQ с 144, CONTRACT_VERSION 1.0 (решение №14)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012vJkmBGKKqMoEMzvsXG3y2
2026-10-06 22:48:40 +04:00
Andrey Epifancev
ec916aee3f plan: Срез 3a — план реализации (18 задач), решение №13 в design.md
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012vJkmBGKKqMoEMzvsXG3y2
2026-10-06 19:19:24 +04:00
Andrey Epifancev
0894d2b89b openspec: решение №12 (скобка как }) — в открытые вопросы, follow-up в docs OQ (решение владельца)
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012vJkmBGKKqMoEMzvsXG3y2
2026-10-06 18:59:07 +04:00
Andrey Epifancev
a15fe65d52 openspec: спека Среза 3a — горячие папки как у armka_file_worker, нормализатор OCR → statementDocument v1.2 (#6)
proposal, design (D-1…D-9, решения без обсуждения №1–12), дельты спек image-recognition-gateway
(папки, очистка под флагом, нормализация, справочники с редакциями, статусы) и scan-emulator (пара по sha256,
набор по умолчанию). tasks.md заполняется планом.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012vJkmBGKKqMoEMzvsXG3y2
2026-10-06 18:39:52 +04:00
Andrey Epifancev
7cec4596d9 chore(openspec): архив change slice-0-skeleton
Срез 0 реализован и влит (PR #3), change перенесён в openspec/changes/archive, спеки — в openspec/specs.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012vJkmBGKKqMoEMzvsXG3y2
2026-10-04 19:44:47 +04:00
Andrey Epifancev
5b16a53a99 Срез 0 [7.5]: M-1 — TIMEOUT при чередующихся ошибках опроса несёт описание последней ошибки (R-39, design #80)
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-04 16:02:48 +04:00
Andrey Epifancev
b127c02422 Срез 0 [7.5]: финальная волна, документы — T5.1, T5.3, T6.1, T6.3, T6.6, M-3
- README: верхняя граница задержки settle, шаг 5 «Полного круга»; критерии ошибочного файла (корень не объект)
- CLAUDE.md: по одному json на каждый распознанный документ; критерии ошибочного файла
- design.md: D-5 — оговорка про нестроковый error.code отдельным предложением; №79 — источник указания, SQL уборки в порядке FK
- open-questions-proposal.md п.20: замены ../docs/dev/README.md (185–187, 224–226, 252–253) и комментарий docker-compose.yml:184
- план: Task 6 — пометка про замену down -v (R-27)

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-04 16:01:13 +04:00
Andrey Epifancev
ed5622374e Срез 0 [7.5]: сквозная проверка в реальном compose — aep_3/aep_6/aep_5.PDF прошли; R-27, R-37, R-38 (design #77–79)
Профиль services (arm-core, scan-gateway из этого worktree, scan-emulator): aep_3.pdf → error NOT_IMPLEMENTED
с metrics.warnings про <job_id>_ofr.json, aep_6.pdf → error NOT_IMPLEMENTED без metrics, aep_5.PDF →
error INVALID_DOCUMENT; raw/<job_id>.json — склейка набора, тела совпадают с фикстурами; Tmp пуст, .part нет.
Compose правки не требует (умолчания Tmp/settle 2 с). Устаревшие места ../docs/dev/README.md — точными
заменами в open-questions-proposal.md, пункт 20. Уборка — rm -sfv своих сервисов и том hotfolder вместо
down -v (R-27). Отметки: tasks 7.5, план Task 6.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-04 15:30:46 +04:00
Andrey Epifancev
877541db10 Срез 0 [7.4]: README и CLAUDE.md — набор ответа, Tmp, settle, склеенный raw; уточнение D-5, отметки 7.4
Раскладка Output/<job_id>/*.json (склеиваются все файлы), SCAN_TMP_DIR, SCAN_SETTLE_SECONDS, структура raw/{job_id}.json,
успех = error.code == "", ошибочные файлы в metrics.warnings, правило набора эмулятора. D-5: не строковый error.code
тоже ошибка (UNKNOWN_ERROR, R-32). Решения R-36 (design #76). Тест TestAnswerSet на реальных фикстурах помечен fixtures.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-04 15:08:07 +04:00
Andrey Epifancev
24af6f1b9a Срез 0 [7.3]: эмулятор — набор файлов ответа на задание
Для `<uuid>_<name>.<ext>` эмулятор собирает все `<name>.json` и `<name>_*.json` из SCAN_FIXTURES_DIR (не префикс
`<name>*`) и кладёт их в `Output/<uuid>/` как `<uuid>.json` / `<uuid>_<suffix>.json` с `file_uid = <uuid>`. Набор
пишется в `<root>/<SCAN_TMP_DIR>/.<uuid>.answer` и переименовывается в каталог ответа целиком (R-26). Ответ «нет пары» —
`data_ocr` объектом с пустыми полями (R-28). Решения исполнителя — design №75 (R-35).

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-04 14:48:57 +04:00
Andrey Epifancev
2a0d0a8939 Срез 0 [7.2]: спека и design — R-29 (settle от первого опроса), D-5 с warnings, решения №67–74
- spec «Ответ из одного файла»: набор передаётся не позднее SCAN_SETTLE_SECONDS +
  SCAN_POLL_SECONDS после первого опроса, увидевшего окончательный набор (R-29).
- design D-5: сигнатура NormalizeOutcome с warnings; воркер дописывает их в metrics.warnings.
- Decisions made without discussion: №67 R-29, №68 решения исполнителя Task 2, №69–72
  R-30..R-33 (предел warnings, склейка в src/gateway/merge.py, крайние случаи NullNormalizer,
  слияние warnings с metrics), №73 T2.1/T2.2/T2.4, №74 R-34 (адаптация test_roundtrip.py).
- Отметки: Task 3 в плане, 7.2 в tasks.md.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-04 14:28:26 +04:00
Andrey Epifancev
a0ab13d3d9 docs: поправка человека — убрана формулировка про части одного документа; в одном json несколько таблиц разных форм
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-04 14:13:32 +04:00
Andrey Epifancev
ee4359d535 Срез 0 [7.1]: отметка выполнения Task 2 в плане и задачи 7.1 в tasks.md
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-04 14:01:39 +04:00
Andrey Epifancev
52c032a308 Срез 0 [fix T1.1-T1.11]: согласованность артефактов change после решений человека
Заменённые решения помечены в design.md (№32, 35, 43, 48), добавлены №63-66 (R-22, R-23, R-25, R-28),
маркеры R-n (design #m); уточнены правила результата (UNKNOWN_ERROR, не-объект, коды в warnings),
сценарии таймаута по settle, имена файлов <job_id>*.json, ответ эмулятора «нет пары» с data_ocr-объектом.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-04 13:46:09 +04:00
Andrey Epifancev
65ae419ee5 docs: поправка человека — соответствие «таблица ↔ документ» не взаимно однозначно (план, предложение по OQ-77)
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-04 13:39:16 +04:00
Andrey Epifancev
5dbb4dab20 Срез 0 [7.0]: change обновлён под решения человека 04.10.2026
Склейка всех json каталога ответа (settle), SCAN_TMP_DIR вне Input, успех = error.code == "",
per-file ошибки в metrics.warnings, набор файлов в эмуляторе; решения №54-62 в design.md;
OQ-76/77/78/79 отмечены решёнными; группа 7 в tasks.md.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-04 13:38:48 +04:00
Andrey Epifancev
842f7a69e4 docs: README про усечение длинных имён, решения финальной волны (R-21, C-1, I-1, T12.1, T7.3) в design.md
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-04 05:14:14 +04:00
Andrey Epifancev
d91c025f73 Срез 0 [fix proposal]: предложения для docs дополнены итогами финального ревью
open-questions-proposal.md: SCAN_GATEWAY_PORT=8002 для `../docs/dev` (T16.1); проверки после применения
compose-фрагмента — `up -d --wait scan-gateway scan-emulator` с кодом 0 и строки лога эмулятора в формате `run()`
(T16.2, I-2); пометка, что фрагмент рабочий только после C-1 (проверено `docker run`, код 2); I-3 — replay
с `attempt + 1` для задания из LRU; `make up` в tabular-parser без `minio-init` (только сообщить); в «Что осталось
человеку» — не архивировать до проверки фрагмента, решение по I-3, приоритет T12.5.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-04 05:06:28 +04:00
Andrey Epifancev
17e334f556 Срез 0 [fix docs]: README, CLAUDE.md и design.md #32 сверены с кодом
README: настройки шлюза читаются при импорте `src.app`, пакет `src` и эмулятор их не читают (после C-1);
`data_ocr` реальных фикстур — объект с пустыми полями и `table_structure: []`; непустой `data_ocr` в `ok_doc.json` —
требование тестовой фикстуры, не NullNormalizer; в «Ограничения Среза 0» — зависший вызов SMB и поздний TIMEOUT
(T12.2/T8.4), перечитывание недописанного ответа (T3.5), битая фикстура эмулятора.
CLAUDE.md: TIMEOUT по `min(reply_deadline, старт + SCAN_TIMEOUT_SECONDS=300)`; заглушки шаблона перечислены.
design.md, строка 32: формулировка про `data_ocr` реальных фикстур.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-04 05:05:42 +04:00
Andrey Epifancev
58bcae2a57 Срез 0 [6.3]: прогон DoD, предложения для docs и правки .env.example
- open-questions-proposal.md: compose-фрагмент scan-emulator/scan-gateway, таблица предложений по контракту и OQ,
  чеклист для человека (файлы в ../docs не менялись)
- .env.example: SCAN_EMULATOR_POLL_SECONDS; уточнён комментарий PUBLISH_RETRIES (повторы после первой попытки)
- отмечена задача 16 плана и пункт 6.3 tasks.md

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-04 04:44:33 +04:00
Andrey Epifancev
27fe24cb5e Срез 0 [6.2]: make check-full = check + test-integration + docker-build
Добавлена цель docker-build (IMAGE ?= scan-gateway:dev, контекст — корень репозитория).
check-full вызывает шаги последовательно через $(MAKE), поэтому порядок и остановка на
первой ошибке гарантированы и при make -j. README/CLAUDE.md и help приведены в соответствие,
отмечены задача 15 плана и пункт 6.2 tasks.md.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-04 04:38:16 +04:00
Andrey Epifancev
e2286354c9 docs: D-9 design.md приведён к R-7/R-10 (интеграционный тест в процессе, синтетический успех)
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-04 04:33:00 +04:00
Andrey Epifancev
22f62a4eda Срез 0 [1.3]: README.md и актуализированный CLAUDE.md, отметка задачи
README.md описывает сервис как он есть: границы (без БД и фронта), поток обработки,
протокол горячих папок, переменные окружения шлюза и эмулятора, коды ошибок,
контракт NATS, запуск (dev, полный круг против compose и эмулятора, проверки),
/healthcheck, Docker-образ и ограничения Среза 0. CLAUDE.md: «Соглашения шаблона»
переписаны по фактическому дереву api/, устаревший SCAN_EMULATOR=1 заменён на
`make emulator` / `python -m src.scan_emulator`.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-04 04:31:54 +04:00
Andrey Epifancev
700aba4dc3 docs: решения исполнителя задачи 6.1 в design.md slice-0-skeleton
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-04 04:28:36 +04:00
Andrey Epifancev
6552ebe345 Срез 0 [6.1]: сквозной интеграционный тест test_roundtrip.py, отметка задачи
Lifespan приложения и эмулятор ИС в процессе теста (R-7) против compose NATS/MinIO, горячая папка в tmp-каталоге.
Три сценария (R-10): aep_5.pdf (реальная фикстура) — INVALID_DOCUMENT от ИС, повтор во время ожидания и после
результата даёт ещё один ack без второго файла; ok_doc.pdf (синтетический успех) — NOT_IMPLEMENTED; unknown.pdf —
INVALID_DOCUMENT эмулятора. Проверяются схема конверта, service.name, Nats-Msg-Id, raw/<job_id>.json байт в байт,
входящий файл против объекта S3, /healthcheck, остановка без незавершённых задач и ошибок в логе.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-04 04:23:10 +04:00
Andrey Epifancev
04fff8bb89 docs: решения исполнителей задач 5.3, 5.4 в design.md slice-0-skeleton
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-04 04:13:14 +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
09f0bb32e2 Срез 0 [5.3]: /healthcheck.nats и .hotfolder, воркер и NATS в lifespan, отметка задачи
src/core/health.py: HealthProvider — nats ok/down/disabled по is_connected; hotfolder —
healthy() в потоке под wait_for (2 с) с кэшем 5 с, зависшая проба не запускается
повторно (T8.4). Сбой регистрации SMB-сессии виден естественно: SmbHotFolder.healthy()
обращается к шаре с теми же учётными данными (T2.3).

app.py: в lifespan S3Storage, NatsGateway, Worker(NullNormalizer); подключение к NATS
и подписка — фоновой задачей (connect ждёт сервер), её сбой — logger.exception и
nats=down без падения HTTP; остановка отменяет подключение, останавливает воркер,
закрывает NATS и S3. Объекты lifespan — в app.state.

test_app.py: тесты lifespan переведены на NATS_ENABLED=false и tmp-корень (иначе фоновое
подключение шло бы в compose NATS), проверка полей healthcheck расширена nats/hotfolder.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-04 03:50:22 +04:00
Andrey Epifancev
9adec14b2e docs: решения R-13..R-20 и исполнителя задачи 5.2 в design.md slice-0-skeleton
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-04 03:37:50 +04:00
Andrey Epifancev
5d82607715 Срез 0 [5.2]: слой NATS без JetStream (src/core/nats.py), интеграционные тесты, отметка задачи
NatsGateway: подключение с nkeys/JWT или без учётных данных, NATS_ENABLED=false — без подключения,
автопереподключение nats-py, subscribe_requests в queue group scan-gateway, publish с Nats-Msg-Id и
повторами (PUBLISH_RETRIES попыток всего) -> PublishFailed, publish_result для конвертов ack/result.
src.core.clients и src.core.nats — в strict-списке mypy. Интеграционные тесты против compose-NATS/MinIO:
queue group, заголовок Nats-Msg-Id, roundtrip S3, отсутствующий ключ.

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