Обмен с ядром на core NATS: подписка queue group, ack status=processing сразу по получении, process-local LRU job_id против повторных запросов, публикация результата с повторами; удалены durable consumer / max_deliver / ack_wait. Dockerfile python:3.11-slim; make check / make check-full вместо CI; raisa_* фильтруются при dev-установке. Обновлены proposal, design (решения без обсуждения), specs, tasks, CLAUDE.md, openspec/config.yaml. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
65 lines
6.1 KiB
Markdown
65 lines
6.1 KiB
Markdown
# Proposal: Срез 0 — скелет tabular-parser
|
||
|
||
**Срез:** 0 «Скелет» (`../docs/context/09-delivery-plan.md`). **Репозиторий:** tabular-parser. **Issue:** RSHB/arm-tabular-parser#1.
|
||
**Родительский change:** `../docs/openspec/changes/slice-0-skeleton` (контракт v1.0, compose, проверки качества).
|
||
**Соседние:** `../arm-core/openspec/changes/slice-0-skeleton`, `../scan-gateway/openspec/changes/slice-0-skeleton`.
|
||
|
||
## Why
|
||
|
||
Репозиторий сейчас — полная копия каркаса `arm-core` с фронтом, Alembic и моделями, то есть противоречит DECISION-4
|
||
(сервис без БД, видит только NATS и S3). Прежде чем в Срезе 2 писать парсер ОСВ, нужен сервис, который уже умеет
|
||
принять запрос из NATS, подтвердить его, прочитать файл из S3, положить результат и ответить по контракту v1.0 — чтобы
|
||
парсер стал чистой функцией «байты → документы», а транспорт был проверен end-to-end вместе с ядром на той платформе,
|
||
что есть: NATS без JetStream, Python 3.11, без Nexus.
|
||
|
||
## What Changes
|
||
|
||
- **Вырезать из шаблона** (список — `CLAUDE.md`, «Соглашения шаблона»): `web/`, `setup/.npmrc` и npm-шаги
|
||
`setup/setup.sh`; из `app.py` — mount SPA, CORS, SMB-сессия, импорт `raisa_fastapi_protected_api`; `db/`, `models/`,
|
||
`repositories/`, `alembic/`, `alembic.ini`; настройки `OPENBAO.DATABASE`, `OPENBAO.SMB`; зависимости `asyncpg`,
|
||
`SQLAlchemy`, `alembic`, `smbprotocol`, `argon2-cffi`, `raisa_fastapi_protected_api`; шаблонный `README.md`.
|
||
- **Инструменты**: `api/pyproject.toml` (ruff, mypy), `requirements-dev.txt` = `-r requirements.txt` + инструменты,
|
||
`Dockerfile` (`python:3.11-slim`; строка убрана из `.gitignore`), `Makefile` с общими целями `up / test /
|
||
test-integration / lint / check / check-full` + `venv`, `.env.example`, `.env.test`; `Settings` читает `ENV_FILE`;
|
||
`SERVICE_NAME = "tabular-parser"`.
|
||
- **Контракт**: вендоренные схемы `api/contracts/` + pydantic-модели `src/contract/` (запрос, конверт со статусами
|
||
`processing | done | needs_check | error`, файл результата); тест идентичности с `../docs/contracts`.
|
||
- **Воркер** `src/core/worker.py` (NATS без JetStream): подписка на `recognition.tabular.request` в queue group
|
||
`tabular-parser`; по получении — сразу ack: конверт `status = processing` в `recognition.result`
|
||
(`Nats-Msg-Id = ack:<job_id>:<attempt>`); затем чтение исходника из S3 `uploads/…`, вызов парсера, запись
|
||
`results/{file_id}/{job_id}/result.json`, публикация конверта результата (`Nats-Msg-Id = result:<job_id>:<attempt>`).
|
||
Process-local множество `job_id` в работе: повторный запрос (ядро публикует повторно, не получив ack) получает ack и не
|
||
обрабатывается второй раз.
|
||
- **Парсер как интерфейс**: `src/parser/` — протокол `Parser` и `NullParser`, возвращающий `status = error`,
|
||
`error.code = NOT_IMPLEMENTED` для любого файла (Срез 2 заменяет реализацией §1/§12); `api/rules/README.md` —
|
||
место словарей синонимов.
|
||
- **Ошибки транспорта** всегда превращаются в результат: запрос не по схеме → `SCHEMA_MISMATCH`; файл не читается из
|
||
S3 → `FILE_READ_ERROR`; неожиданное исключение → `UNKNOWN_ERROR`. Ядро не ждёт таймаута, если сервис жив.
|
||
- **Healthcheck** `/healthcheck` шаблона дополняется полем `nats` (`ok`/`down`).
|
||
- **Проверки качества** вместо CI: `make check` (ruff, mypy, pytest без Docker, идентичность контракта) и
|
||
`make check-full` (+ интеграционный тест против compose, `docker build`) — по `../docs/dev/checks.md`.
|
||
|
||
## Capabilities
|
||
|
||
### New Capabilities
|
||
- `tabular-recognition-service`: stateless-сервис, который принимает задания из NATS без JetStream, подтверждает их,
|
||
обменивается файлами через S3 и отвечает по контракту v1.0; в Срезе 0 — с парсером-заглушкой.
|
||
|
||
### Modified Capabilities
|
||
<!-- openspec/specs пуст -->
|
||
|
||
## Impact
|
||
|
||
- **Таблицы DBML:** сервис не пишет в БД. Косвенно: `recognition_job` ядра получает `status = processing`
|
||
(`started_at`), затем `error`, `error_code = NOT_IMPLEMENTED`, `service_name = tabular-parser` из конвертов.
|
||
- **Правила:** §1.0/§12 — только как контракт будущего парсера (интерфейс `Parser`), §9.4 — статусы задания.
|
||
- **Зависимости:** удаляются БД/SMB/фронт; добавляются `ruff`, `mypy`, `pytest*`, `jsonschema` (валидация примеров).
|
||
- **Внешние системы:** NATS без JetStream (subjects `recognition.*`), MinIO/S3 (бакет `arm-ka`).
|
||
|
||
## Non-goals
|
||
|
||
- Разбор ОСВ и форм ББ/ОФР (§1, §12) — Срез 2; property-тесты на `../fixtures/osv/**` — Срез 2.
|
||
- Словари `rules/*.yaml` — Срез 2 (здесь только каталог и README).
|
||
- Периодический heartbeat `processing` — не реализуется (один ack при получении).
|
||
- Любая работа с БД, SMB, фронтом; конфигурации CI.
|