14 Commits

Author SHA1 Message Date
Andrey Epifancev
621c0b2dc4 feat: реальный парсер в воркере, CLI разбора файла, интеграционный сценарий
CLI `python -m src.parser.cli <файл> [--file-type]` печатает JSON результата (коды 0/1/2 по статусу, 3 — файл/использование);
сборка RecognitionResult выделена из воркера в чистую `build_result` без изменения логики; тесты воркера на реальном
OsvParser, интеграционный сценарий «Реальная ОСВ через воркер», README «Запуск на файле».

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012vJkmBGKKqMoEMzvsXG3y2
2026-10-05 14:51:01 +04:00
Andrey Epifancev
e705d75520 feat(parser): контрольные суммы §1.4, статусы, OsvParser как парсер по умолчанию, лимиты
checks.py: тождество сальдо по каждой строке, суммы родителя = Σ детей того же data_type
(CURRENCY/QUANTITY исключены; обороты — по колонкам, сальдо — по колонкам или по нетто при
свёрнутом сальдо родителя), «Итого» = корневой счёт (R-13: нет корня — «Итого» пусто/0;
R-20: нет «Итого» — false и предупреждение).
osv.py: OsvParser — лимит размера, чтение по сигнатуре, листы по содержимому (формы ББ/ОФР и
прочие — пропуск с предупреждением), карта исходов D-6, кооперативный дедлайн, metrics
(rows без TOTAL, warnings с «sheet=<имя> hierarchy=<стратегия>» первой записью по листу).
get_parser(settings, rules_dir=…) → OsvParser (словари грузятся при создании: битый словарь —
падение старта); PARSE_MAX_BYTES / PARSE_TIMEOUT_SECONDS в Settings и .env.*; app.py передаёт
настройки. test_null_parser.py → test_parser_factory.py.
Тесты: юнит-карта статусов, «Испорченная сумма», «Пустая ОСВ», два листа ОСВ, новый синоним
без релиза кода (R-8); property-тест на 66 реальных файлах (все done, < 5 с, схема v1.1).
test_app и интеграционный round-trip ждут ошибку реального парсера вместо NOT_IMPLEMENTED.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012vJkmBGKKqMoEMzvsXG3y2
2026-10-05 14:37:21 +04:00
Andrey Epifancev
8685441fcd fix: настройки — SERVICE_NAME только tabular-parser, PUBLISH_RETRIES ≥ 0 (M-1, M-3, M-4, M-5)
- SERVICE_NAME: Literal["tabular-parser"] (R-35); в config.py, .env.example,
  README и CLAUDE.md исправлено «имя queue group» — queue group задаёт
  константа REQUEST_QUEUE_GROUP в core/nats.py.
- PUBLISH_RETRIES: NonNegativeInt — 0 означает одну попытку без повторов,
  как и принимает NatsConnection.
- Удалён неиспользуемый модульный settings = get_settings() из config.py.
- pyproject.toml: убран override mypy для raisa_fastapi_protected_api
  (зависимость удалена D-1).
- tests/conftest.py: фабрика minimal_settings (Settings из временного .env с
  минимальным окружением, окружение процесса скрыто); test_config.py —
  умолчания при минимальном окружении (M-8), PUBLISH_RETRIES=0/-1,
  SERVICE_NAME≠tabular-parser.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-04 03:48:34 +04:00
Andrey Epifancev
bf2f60b3b5 fix: NATS — отказ в правах логируется отдельно; drain ограничен 10 с (I-3, M-7)
nats-py 2.14 при Permissions Violation не закрывает соединение и не роняет
subscribe/flush/publish, а только вызывает error_cb. Раньше это логировалось
как «Нет связи с NATS, повторяем подключение» с лимитом раз в минуту. Теперь
_on_error распознаёт «permissions violation» и пишет error
error_category=nats_permission с subject, каждый раз и без серии ошибок
подключения. Исправлены ложные утверждения docstring («ошибки прав
проявляются сразу»).

connect получает drain_timeout=DRAIN_TIMEOUT (10 с вместо 30 с nats-py):
STOP_TIMEOUT воркера + drain укладываются в 30 с платформы.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-04 03:46:33 +04:00
Andrey Epifancev
18276e607e fix: воркер — задание не теряется молча при остановке во время ack, невалидный дубль job_id не публикует SCHEMA_MISMATCH
I9.1: после ack повторная проверка приёма — warning error_category=shutdown, job_id снимается из «в работе».
T9.7: невалидное тело с job_id в работе/обработанным — warning и сброс (msg-id настоящего результата не занимается).
T9.5: error.message исхода парсера — одной строкой, ≤ 1000 символов. T9.6: docstring stop() про to_thread.
T9.1: тест конкуренции без опроса со sleep.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-04 03:17:11 +04:00
Andrey Epifancev
a7862c1843 feat: запуск воркера в lifespan при NATS_ENABLED и поле nats = ok | down | off в /healthcheck
Подписка — через on_connected NatsConnection; остановка: воркер (дорабатывает очередь) → NATS → S3. Клиент S3
остаётся и при неудачной проверке бакета, отсутствие бакета — warning (T2.1). Тест lifespan и healthcheck с фейками
(T8.7); формулировки nats в README, .env.example и spec приведены к R-17.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-04 03:09:06 +04:00
Andrey Epifancev
e1231dcdb4 feat: воркер распознавания src/core/worker.py — ack до чтения S3, дедуп job_id, таблица ошибок D-5
on_request: валидация (pydantic + MAJOR = 1) → повторный job_id получает только ack → ack processing → очередь;
рабочие корутины: S3 get → Parser через asyncio.to_thread → файл результата → конверт с metrics.duration_ms →
публикация с Nats-Msg-Id result:<job_id>:<attempt>. SCHEMA_MISMATCH без ack, FILE_READ_ERROR, UNKNOWN_ERROR,
NatsPublishError — error-лог. Docstring протокола Parser: ожидаемые сбои — исход error (T7.1).

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-04 03:05:47 +04:00
Andrey Epifancev
6c8d7b6e9b fix: NATS — PUBLISH_RETRIES как повторы после первой попытки (R-16), flush после подписки, снятие подписок при сбое on_connected, проброс отмены в stop(), error-лог самопроизвольного закрытия
Находки ревью Task 8: T8.2–T8.6.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-04 02:57:23 +04:00
Andrey Epifancev
ff08905580 feat: слой NATS src/core/nats.py — фоновое подключение (nkeys/без), подписка на запросы в queue group, публикация с повторами
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-04 02:47:17 +04:00
Andrey Epifancev
4c32cd36ac feat: S3Storage.get_bytes/put_json и протокол Storage вместо шаблонных put_object/get_object
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-04 02:45:25 +04:00
Andrey Epifancev
a24fee09c6 style: форматирование ruff остальных файлов шаблона и тип уровня в InterceptHandler
Нужно для зелёного make lint (R-8).

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-04 02:32:49 +04:00
Andrey Epifancev
9cdc62b26d chore: упрощены app.py, config.py и requirements.txt после выреза шаблона
Убраны SPA, CORS, SMB, РАИСА, SQLAlchemy-обработчики и зависимости БД/SMB;
настройки: ENV_FILE, SERVICE_NAME, NATS_ENABLED, WORKER_CONCURRENCY,
PUBLISH_RETRIES, DONE_CACHE_SIZE, MINIO_SECURE.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-04 02:25:35 +04:00
Andrey Epifancev
1bd97a3672 chore: вычищены остатки доменного кода, каркас проходит tsc/biome/rsbuild 2026-10-02 23:34:58 +04:00
Andrey Epifancev
29e5cc5bf4 chore: каркас из шаблона команды (DKB_ARMKA@ba172f8, доменный код удалён) 2026-10-02 23:15:38 +04:00