Ошибка ИС пробрасывается с кодом из ответа, неизвестный код/вид ошибки -> UNKNOWN_ERROR с исходным представлением, успех -> NOT_IMPLEMENTED, не объект -> INVALID_FORMAT. Пакет добавлен в strict-список mypy. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
7.2 KiB
7.2 KiB
Tasks: Срез 0 — скелет scan-gateway
Репозиторий — scan-gateway; команды — из api/. Зависимости: 3.1 ждёт контракт v1.0 (docs 1.1–1.4); интеграционные
тесты 6.x — compose (docs 2.1, 5.3). Каждая задача ≤ половины дня. CI нет — проверки локальные.
1. Вырезать фронт и БД из шаблона (SMB остаётся)
- 1.1 Удалить
web/,setup/.npmrc, npm-шагиsetup/setup.sh,api/alembic/,api/alembic.ini,api/src/db/,api/src/models/,api/src/repositories/; убратьDockerfileиз.gitignore; проверка:git status— только удаления и.gitignore - 1.2
src/app.py: убрать mount SPA/os.makedirs("web"), CORS, импортraisa_fastapi_protected_api; оставить SMB-сессию (только приSCAN_HOTFOLDER_MODE=smb);src/core/config.py: убратьDBSettings; добавитьENV_FILE,SERVICE_NAME="scan-gateway",NATS_ENABLED=true,PUBLISH_RETRIES=3,DONE_CACHE_SIZE=1000,SCAN_HOTFOLDER_MODE="local",SCAN_HOTFOLDER_PATH,SCAN_INPUT_DIR="Input",SCAN_OUTPUT_DIR="Output",SCAN_POLL_SECONDS=5,SCAN_TIMEOUT_SECONDS=300,SCAN_MAX_INFLIGHT=4;requirements.txtбезasyncpg,SQLAlchemy,alembic,argon2-cffi,raisa_fastapi_protected_api; проверка: чистый venv (python3.11),python run_server.pyс.env.example,/healthcheck200 - 1.3
README.md— описание сервиса (назначение, протокол горячих папок, env, запуск против compose и эмулятора),CLAUDE.md— актуализировать «Соглашения шаблона» по факту; проверка: упомянутые файлы существуют
2. Инструменты
- 2.1
api/pyproject.toml(ruff, mypy),requirements-dev.txt=-r requirements.txt+ ruff, mypy, pytest, pytest-asyncio, pytest-env, httpx, jsonschema;Makefile:venv(python3.11, безraisa_*),lint,test,test-integration,check,check-full,up,emulator; проверка:make venv && make lintзелёные - 2.2
Dockerfile(python:3.11-slim;CMD python run_server.py, эмулятор — черезcommandв compose),.env.example,.env.test; проверка:docker buildуспешен без Nexus
3. Контракт
- 3.1
api/contracts/— копии схем иexamples/из../docs/contracts;src/contract/— pydantic-модели (конверт со статусамиprocessing | done | needs_check | error);tests/unit/test_contract.py— идентичность (skip без docs), примеры, round-trip; проверка: тесты зелёные
4. Горячие папки и эмулятор
- 4.1
src/gateway/hotfolder.py: протоколHotFolder,LocalHotFolder(put/poll/healthy);tests/unit/test_local_hotfolder.pyнаtmp_path; проверка: put пишет<uuid>_<name>, poll возвращаетNoneдо появления ответа и байты после - 4.2
src/gateway/smb.py:SmbHotFolderповерхsmbclient(UNC\\host\path\Input), те же методы; unit-тест с подменённымsmbclient(вызовыopen_file,listdir); проверка: тест зелёный, в режимеlocalмодуль не импортируется - 4.3
src/scan_emulator/__init__.py+__main__.py: функцияprocess_once(root, fixtures, delay)и цикл; поиск фикстуры по имени/префиксу, подстановкаfile_uid, ошибкаINVALID_DOCUMENT, переименование в.done;tests/unit/test_emulator.py— сценарии spec «Точное имя», «Префикс», «Нет пары» наtmp_pathс копиями../fixtures/ocr/*.json(маркерfixtures, skip без фикстур); проверка: зелёный
5. Воркер и нормализатор-заглушка
- 5.1
src/normalizer/__init__.py: протоколNormalizer,NormalizeOutcome,NullNormalizer(ошибка ИС → код из ответа; успех →NOT_IMPLEMENTED; не JSON →INVALID_FORMAT); unit-тесты наaep_5.json,aep_8_form4.json, синтетическом ответе сerror; проверка: зелёный - 5.2
src/core/clients.py(get_bytes,put_json,put_bytes),src/core/nats.py(подключение с/без nkeys, автопереподключение,subscribe_requests(queue="scan-gateway", cb),publishсNats-Msg-Idи повторами); проверка: unit с фейками, интеграционный тест подключения к compose-NATS без JetStream - 5.3
src/core/worker.py:on_request(msg): валидация → LRUjob_id→ ackprocessing→ очередь; семафорSCAN_MAX_INFLIGHT;handle(job): S3 get →hotfolder.put→ опрос до дедлайна →raw/{job_id}.json→Normalizer→ результат/конверт → publish; таблица ошибок D-7;/healthcheck.nats,.hotfolder; проверка: unit-тестыhandleс фейками иLocalHotFolder+process_onceэмулятора — сценарии spec (ack раньше файла, повторный запрос → один файл, успех → NOT_IMPLEMENTED сraw_s3_key, INVALID_DOCUMENT, TIMEOUT с укороченными таймаутами, RECOGNITION_FAILED при отсутствии каталога, SCHEMA_MISMATCH без ack, FILE_READ_ERROR) - 5.4 Тест параллелизма: пять заданий при
SCAN_MAX_INFLIGHT = 4— пять ack сразу, четыре файла во входящем каталоге, пятый после освобождения слота (фейковые S3/NATS,LocalHotFolder); проверка: зелёный
6. Интеграция, проверки, завершение
- 6.1
tests/integration/test_roundtrip.py(маркерintegration): compose сscan-emulator— положитьaep_5.pdfв MinIOuploads/…, опубликоватьrequest-image.json, собратьrecognition.result:processing, затемNOT_IMPLEMENTEDсraw_s3_key; проверить объектraw/<job_id>.jsonв MinIO; второй запрос сunknown.pdf→INVALID_DOCUMENT; проверка: зелёный - 6.2
make check-full:make check+pytest -m integration+docker build; проверка: зелёный против compose docs на веткеfeat/1-slice-0-skeleton - 6.3 Прогон DoD:
make up→make check-full→ ручная проверка изdocs/dev/README.md;openspec validate slice-0-skeleton --strict; выводmake check-full— в описание PR