openspec init (config с контекстом docs-репозитория) и change slice-0-skeleton: proposal, design (11 решений без обсуждения, открытые вопросы к человеку), спеки recognition-contract, dev-environment, ci-template, tasks в порядке зависимостей между репозиториями. 06-test-data.md §6: справочники продукта — seed arm-core, не фикстуры. 09-delivery-plan.md: Срез 0 по факту (change'и, compose в docs/dev, контракт копией без общего пакета, seed). Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
6.3 KiB
Spec Delta: recognition-contract
Purpose
Контракт обмена между ядром arm-core и stateless-сервисами распознавания (tabular-parser, scan-gateway):
тела сообщений NATS recognition.{tabular|image}.request и recognition.result, файл результата в S3 и правила
версионирования и идемпотентности. Сервисы не знают БД; ядро — единственный писатель (DECISION-4).
ADDED Requirements
Requirement: Сообщение запроса распознавания
Тело сообщения на subject recognition.tabular.request или recognition.image.request SHALL соответствовать
docs/contracts/recognition-request.schema.json v1.0: обязательные поля schema_version ("1.0"), job_id (uuid =
recognition_job.id), file_id (uuid = stored_file.id), pipeline (tabular | image), file_type
(XLS | XLSX | XLSB | PDF | PNG | JPG), original_name, s3 {bucket, key} исходника в роли uploads,
reply_deadline (date-time, UTC), attempt (≥ 1). Subject SHALL соответствовать pipeline.
Scenario: Публикация запроса ядром
- WHEN ядро переводит
recognition_jobизqueuedвpublished - THEN в subject, соответствующий
recognition_job.pipeline, публикуется сообщение, проходящее схему запроса, с заголовкомNats-Msg-Id=<job_id>:<attempt>
Scenario: Сообщение не по схеме
- WHEN сервис получает запрос, не проходящий схему (нет
s3.key, неизвестныйfile_type) - THEN сервис публикует результат со
status = error,error.code = SCHEMA_MISMATCHи не падает
Requirement: Сообщение результата распознавания
Тело сообщения на subject recognition.result SHALL соответствовать docs/contracts/recognition-result-message.schema.json
v1.0: обязательные поля schema_version ("1.0"), job_id, file_id, status (done | needs_check | error),
service {name, version}; при status ≠ error обязательны result_s3 {bucket, key} и result_schema_version;
при status = error обязателен error {code, message}; опциональны raw_s3_key (только scan-gateway) и metrics.
Поле group_schema в конверт NOT включается — источник recognition_job.group_schema — файл результата.
Scenario: Успешный результат
- WHEN сервис завершил обработку файла
- THEN файл результата записан в S3 по ключу
results/{file_id}/{job_id}/result.json, а затем опубликован конверт соstatus = done | needs_check,result_s3указывает на этот файл, заголовокNats-Msg-Id=result:<job_id>:<attempt>
Scenario: Ошибка обработки
- WHEN сервис не смог обработать файл (нечитаем, таймаут внешней системы, тип не поддерживается)
- THEN публикуется конверт со
status = errorиerror.codeиз перечня схемы (UNSUPPORTED_FORMAT,UNREADABLE,TIMEOUT,SCHEMA_MISMATCH,NOT_IMPLEMENTED,FILE_READ_ERROR,INVALID_FORMAT,INVALID_DOCUMENT,RECOGNITION_FAILED,UNKNOWN_ERROR);result_s3может отсутствовать
Requirement: Файл результата
Файл результата SHALL соответствовать docs/contracts/recognition-result.schema.json v1.0: один файл (stored_file)
→ один job_id → массив documents из osvDocument и/или statementDocument; денежные значения — строки
^-?\d+(\.\d{1,2})?$; confidence — 0–100. Пустой массив documents допустим только при status = error.
Scenario: Результат валидируется примерами
- WHEN CI сервиса запускает тесты контракта
- THEN все файлы
docs/contracts/examples/result-*.jsonпроходят схему файла результата, а всеrequest-*.json/result-message-*.json— схемы сообщений
Requirement: Версионирование контракта
Поле schema_version SHALL быть строкой MAJOR.MINOR. Добавление необязательных полей или значений enum —
MINOR (1.1, обратно совместимо); удаление/переименование полей, смена типов или семантики — MAJOR (2.0).
Сервис SHALL отвергать запрос с неизвестным MAJOR (error.code = SCHEMA_MISMATCH); ядро SHALL принимать результат
с тем же MAJOR и любым известным или новым MINOR.
Scenario: Несовместимая версия запроса
- WHEN сервис, поддерживающий
1.x, получает запросschema_version = "2.0" - THEN публикуется результат
status = error,error.code = SCHEMA_MISMATCH, запрос подтверждается (ack), чтобы не зациклить доставку
Requirement: Копия контракта в сервисе идентична источнику
Каждый сервис, читающий или пишущий контракт, SHALL хранить копию файлов схем в api/contracts/ и проверять в CI их
байтовую идентичность файлам docs/contracts/ (checkout arm-ka-docs или путь ARM_KA_DOCS).
Scenario: Копия устарела
- WHEN в
docs/contracts/изменена схема, а копия в сервисе — нет - THEN тест идентичности в CI сервиса падает с указанием имени файла