arm-scan-gateway/CLAUDE.md
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

65 lines
7.3 KiB
Markdown
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.

# CLAUDE.md — scan-gateway
Общий контекст системы — `../CLAUDE.md` и `../docs/`. Этот файл — только про этот сервис.
## Что это
Адаптер внешней ИС Сканирование (Content AI) для PDF/PNG/JPG: переименовать файл `UUID_имя`, положить в «Входящие»
(через `SCAN_TMP_DIR`, по умолчанию `Tmp`: `.part` пишется туда, на той же ФС/шаре, и переименовывается), забрать **все**
`Исходящие/UUID/*.json` (ИС кладёт по одному json на файл ответа), склеить и сохранить сырой ответ в S3
`raw/{job_id}.json` (в БД не регистрируется),
нормализовать в `../docs/contracts/recognition-result.schema.json` (`statementDocument`), опубликовать
`recognition.result`. Таймаут → ошибка `TIMEOUT` по `min(reply_deadline, старт + SCAN_TIMEOUT_SECONDS=300)`, старт —
запись файла во «Входящие». **Нет доступа к БД.**
## Правила
- Нормализация по фактическим ответам `../fixtures/ocr/aep_*.json`, а не по ТЗ (OQ-13, OQ-14): confidence → 0–100,
поля организации/даты — по тому, что реально приходит.
- Набор ответа готов по settle: есть `*.json`, а имена и размеры не менялись `SCAN_SETTLE_SECONDS` (по умолчанию 2;
отсчёт от первого опроса, увидевшего окончательный набор). Не ждать «один файл `<UUID>.json`».
- Склеенный `raw/{job_id}.json`: `{"job_id", "files": [{"name", "response", "parse_error"}, ...]}`, все `*.json`
каталога по возрастанию имени; нормализатор получает ровно эту структуру.
- Успех файла ответа — `error.code == ""` (`error` при этом не `null`!), ошибка — непустой `error.code` или
`parse_error`. Проверка `error is None` для реального ответа неверна. Ошибочные файлы — в `metrics.warnings`
(`<имя>: <код>: <сообщение>`); все файлы ошибочны → код первого, есть успешный → `NOT_IMPLEMENTED` (Срез 0).
- В одном json может быть несколько таблиц разных форм (баланс, ОФР); тип документа задаёт `label` таблицы. Таблицы не
интерпретируются в Срезе 0 — разбор в Срезе 3.
- Dev-режим: эмулятор ИС Сканирование: по входящему `<uuid>_<name>.<ext>` кладёт в `Output/<uuid>/` набор фикстур
`<name>.json` + `<name>_*.json` как `<uuid>.json` / `<uuid>_<суффикс>.json` (атомарно, через `Tmp`): `make emulator`
(то же, что `python -m src.scan_emulator` из `api/`); в контейнере — тот же образ с `command: python -m src.scan_emulator`.
- Описание сервиса, протокол горячих папок, env, запуск и коды ошибок — `README.md`; требования и решения Среза 0 —
`openspec/changes/slice-0-skeleton/` (`design.md`).
## Соглашения шаблона
Тот же шаблон команды, что у `arm-core` («Шаблон FastAPI», `RSHB/DKB_ARMKA@ba172f8`); общие соглашения —
`../docs/context/03-architecture.md`, «Соглашения шаблона команды». Репозиторий приведён к сервису **без фронта и без
БД**, но с SMB. Команды `make` — из корня репозитория (рецепты сами заходят в `api/`), `pytest` — из `api/`.
**Оставлено от шаблона:** `api/run_server.py` (точка входа платформы, `SERVER__HOST/PORT`), `api/src/app.py` (lifespan:
SMB-сессия, S3, NATS, воркер; `GET /healthcheck`; gzip/proxy middleware), `core/config.py` (pydantic-settings,
`OPENBAO__MINIO__*`, `OPENBAO__NATS__*`, `OPENBAO__SMB__*`, `DEBUG`), `core/exception_handlers.py` (подключается в
`create_app`), `api/pytest.ini`, `api/requirements*.txt` (включая `smbprotocol`), `raisa_config.yml`,
`setup/setup.sh` + `setup/pip.conf` (без npm-шага). Заглушки шаблона без кода сервиса: `src/api/` (пустой `router`,
пустые `dependencies/` и `endpoints/`), `src/schemas/` и `src/services/` (пустые пакеты), `common/exceptions.py`
(`NotFoundError`, `CouldntCreateError` нигде не используются), `core/logger.py` (`setup_logger` нигде не вызывается).
**Вырезано (Срез 0):** `web/`, `setup/.npmrc`; из `app.py` — mount SPA, CORS, `raisa_fastapi_protected_api`; `db/`,
`models/`, `repositories/`, `alembic/`; `OPENBAO.DATABASE`; из `requirements.txt` — `asyncpg`, `SQLAlchemy`, `alembic`,
`raisa_fastapi_protected_api`; шаблонные `core/nats_callback.py` и `README.md` заменены своими.
**Добавлено:**
- `api/src/gateway/` — горячие папки: протокол `HotFolder` (`hotfolder.py`: `LocalHotFolder`, `SettleTracker`, `inbox_name`),
`smb.py` (`SmbHotFolder`, импортируется лениво), фабрика `create_hotfolder`; `merge.py` — склейка файлов ответа в `raw/`; референс поллинга — `../reference-old-arm/api/src/core/PDFWorker`.
- `api/src/core/` — `worker.py` (задание: проверка → ack → S3 → горячая папка → опрос → `raw/` → нормализатор →
результат; ошибки по таблице D-7), `nats.py` (core NATS без JetStream, queue group `scan-gateway`, публикация с
повторами), `clients.py` (`S3Storage`), `health.py` (`nats`/`hotfolder` в `/healthcheck`).
- `api/src/normalizer/` — `Normalizer`, `NullNormalizer` (Срез 0: разбор по файлам склейки — все ошибочны → код
первого, есть успешный → `NOT_IMPLEMENTED`, ошибочные файлы → `metrics.warnings`); настоящая нормализация — Срез 3.
- `api/src/contract/` + `api/contracts/` — pydantic-модели и байт-в-байт копии схем `../docs/contracts`; идентичность
проверяет `api/tests/unit/test_contract.py` (входит в `make check`).
- `api/src/scan_emulator/` — эмулятор ИС Сканирование (`SCAN_FIXTURES_DIR`, `SCAN_EMULATOR_DELAY`,
`SCAN_EMULATOR_POLL_SECONDS`); в compose контейнера пока нет — `make emulator`.
- `Makefile` (`venv`, `lint`, `test`, `test-integration`, `check`, `docker-build`, `check-full`, `up`,
`emulator`), `api/pyproject.toml` (ruff, mypy), `Dockerfile` + `.dockerignore` (один образ: шлюз и эмулятор),
`api/.env.example`, `api/.env.test`.
- Тесты: `api/tests/unit/`, `api/tests/integration/` (маркеры `integration`, `fixtures`); перед PR — `make check-full`.