# 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, CI-шаблон). **Соседние:** `../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 вместе с ядром. ## 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` (строка убрана из `.gitignore`), `Makefile` (`up / test / lint`), `.env.example`, `.env.test`; `Settings` читает `ENV_FILE`; `SERVICE_NAME = "tabular-parser"`. - **Контракт**: вендоренные схемы `api/contracts/` + pydantic-модели `src/contract/` (запрос, конверт результата, файл результата); тест идентичности с `../docs/contracts`. - **Воркер** `src/core/worker.py`: durable pull-consumer `tabular-parser` на `recognition.tabular.request` (`max_deliver` 3 — OQ-15), чтение исходника из S3 `uploads/…`, вызов парсера, запись `results/{file_id}/{job_id}/result.json`, публикация конверта `recognition.result` с `Nats-Msg-Id = result::`, 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**: `.gitea/workflows/ci.yml` из шаблона docs (ruff, mypy, pytest c NATS/MinIO, идентичность контракта, сборка образа). ## Capabilities ### New Capabilities - `tabular-recognition-service`: stateless-сервис, который принимает задания из NATS, обменивается файлами через S3 и отвечает по контракту v1.0; в Срезе 0 — с парсером-заглушкой. ### Modified Capabilities ## Impact - **Таблицы DBML:** сервис не пишет в БД. Косвенно: `recognition_job` ядра получает `status = error`, `error_code = NOT_IMPLEMENTED`, `service_name = tabular-parser` из конверта. - **Правила:** §1.0/§12 — только как контракт будущего парсера (интерфейс `Parser`), §9.4 — статусы задания. - **Зависимости:** удаляются БД/SMB/фронт; добавляются `ruff`, `mypy`, `pytest*`, `jsonschema` (валидация примеров). - **Внешние системы:** NATS JetStream (stream `RECOGNITION`), MinIO/S3 (бакет `arm-ka`). ## Non-goals - Разбор ОСВ и форм ББ/ОФР (§1, §12) — Срез 2; property-тесты на `../fixtures/osv/**` — Срез 2. - Словари `rules/*.yaml` — Срез 2 (здесь только каталог и README). - Heartbeat `processing` (DBML: «опц. heartbeat») — не реализуется. - Любая работа с БД, SMB, фронтом.