12 KiB
Spec Delta
MODIFIED Requirements
Requirement: Результат по контракту
После подтверждения сервис SHALL прочитать объект s3.key из бакета s3.bucket, вызвать парсер, записать файл результата
(по recognition-result.schema.json v2.0, schema_version = "2.0") в results/{file_id}/{job_id}/result.json и
опубликовать конверт результата (по recognition-result-message.schema.json v2.0, result_schema_version = "2.0") с
заголовком Nats-Msg-Id = result:<job_id>:<attempt>. Ack processing SHALL нести schema_version = "2.0"; запрос
recognition-request остаётся v1.0. service.statements_version файла результата SHALL быть версией библиотеки
arm_statements (VERSION или метаданные установленного дистрибутива; без версии сервис не стартует) и записываться при наличии statementDocument.
metrics.warnings конверта SHALL содержать предупреждения уровня файла структурами {code, severity, message, locator?},
не строками. Статус конверта — по общему правилу: done ⇔ все документы done ∧ нет предупреждений файла уровня
error. При неудаче публикации сервис SHALL повторить её до трёх раз с паузой, затем залогировать ошибку.
Scenario: Запрос с заглушкой парсера (Срез 0)
- WHEN воркеру явно передана заглушка
NullParser(только тесты воркера; реализация по умолчанию — реальный парсер), запрос подтверждён и объект существует вuploads/ - THEN в
files.tabular_parsedпоявляется конвертstatus = error,error.code = NOT_IMPLEMENTED,job_id/file_idиз запроса,metrics.duration_ms ≥ 0; файл результата может отсутствовать
Scenario: Запрос с реальным парсером
- WHEN запрос подтверждён и объект в
uploads/существует, но не является книгой Excel (сигнатура не XLS/XLSX/XLSB) - THEN в
files.tabular_parsedпоявляется конвертstatus = error,error.code = UNSUPPORTED_FORMAT(повреждённая книга —UNREADABLE),job_id/file_idиз запроса,metrics.duration_ms ≥ 0; файл результата может отсутствовать; корректная ОСВ в том же потоке даётdone(см. «Парсер — заменяемый интерфейс»)
Scenario: Результат и ack версии 2.0
- WHEN обработан запрос
schema_version = "1.0"с книгой, содержащей баланс - THEN ack
processingи конверт результата несутschema_version = "2.0",result_schema_version = "2.0", файл результата проходит схему v2.0,service.statements_versionравен версии библиотекиarm_statements
Scenario: Предупреждение файла структурой
- WHEN в книге лист «Примечания» без признаков ОСВ и формы
- THEN
metrics.warningsконверта содержит{code: "SHEET_OTHER", severity: "info", message, locator: "sheet:Примечания"}
Scenario: Повтор публикации
- WHEN первая публикация конверта результата завершается ошибкой соединения, вторая — успешно
- THEN конверт опубликован один раз с тем же
Nats-Msg-Id, обработка не повторяется
Requirement: Парсер — заменяемый интерфейс
Разбор файла SHALL выполняться через единый интерфейс «байты + тип файла → документы/метрики/ошибка», не знающий о
NATS и S3; воркер MUST NOT зависеть от конкретной реализации. Реализация по умолчанию (get_parser()) SHALL быть
оркестратором книги BookParser: он читает книгу один раз, классифицирует листы по содержимому и отдаёт листы ОСВ
конвейеру спеки osv-parsing, листы форм и их продолжения — конвейеру спеки statement-parsing (адаптер Excel и установленная библиотека
arm_statements); прочие листы дают предупреждение файла SHEET_OTHER. Файл результата SHALL писаться с
schema_version = "2.0"; документы книги — ОСВ в порядке листов, затем формы в порядке листов. Заглушка NullParser
(error NOT_IMPLEMENTED) SHALL использоваться только в тестах воркера и MUST NOT быть реализацией по умолчанию.
Реализация по умолчанию SHALL создаваться один раз при старте приложения (словари ОСВ читаются и проверяются там же,
словари форм — default_rules() пакета). Каталог api/rules/ SHALL содержать словари ОСВ (osv_headers, osv_groups,
periods, data_types, osv_checks) и README; словарей форм ББ/ОФР в сервисе нет — они часть библиотеки arm_statements.
Scenario: Подмена реализации в тесте
- WHEN в тесте воркеру передан парсер, возвращающий один
osvDocument - THEN файл результата с этим документом записан в S3, конверт имеет
status = doneиresult_s3на этот файл
Scenario: Реальная ОСВ через воркер
- WHEN в интеграционном тесте в S3 лежит
rb/2024-FY/ОСВ_66 за 2024.xlsи опубликован запросfile_type = XLS - THEN после ack публикуется конверт
doneсresult_schema_version = "2.0", файл результата проходит схему v2.0 и содержит одинosvDocumentсоstatus = doneиaccount_code_raw = "66"
Scenario: Реальные формы через воркер
- WHEN в интеграционном тесте в S3 лежит книга
statements-xlsx/npz/2025-Q3/…xlsxи опубликован запросfile_type = XLSX - THEN после ack публикуется конверт
doneсresult_schema_version = "2.0", файл результата проходит схему v2.0 и содержит дваstatementDocument(BALANCE,INCOME) со строкамиline_status,ref,checksи пустымиchecks.relations_failed; расхождения итогов в пределах округления (1600 = 1700на 1.94 / 9.02 / 2.48,2100/2200/2300) — вsoft_relations_failed(OQ-138);service.statements_versionравен версии библиотеки
Scenario: Книга без ОСВ и форм
- WHEN в S3 лежит книга Excel, ни один лист которой не имеет признаков ОСВ или формы
- THEN публикуется конверт
error,error.code = INVALID_DOCUMENT, сообщение называет число просмотренных листов
Scenario: Сервис без версии общего кода не стартует
- WHEN у библиотеки
arm_statementsнет ни VERSION, ни версии установленного дистрибутива - THEN
require_statements_version()бросаетRuntimeErrorс текстом «библиотека arm_statements без VERSION и версии пакета: выполните make install», сервис не стартует
Scenario: Установленный дистрибутив без VERSION
- WHEN библиотека установлена как
pylib_ai_arm_statements==0.1.1, файл VERSION отсутствует, а метаданные дистрибутива доступны - THEN сервис стартует и указывает
service.statements_version = "0.1.1"при обработке реальной книгиstatements-xlsx/npz/2025-Q3/…xlsx
ADDED Requirements
Requirement: Локальная поставка библиотеки форм
Окружение сервиса SHALL использовать установленную библиотеку pylib_ai_arm_statements==0.1.1 с импортом arm_statements. make venv SHALL пропускать строки pylib_ai* и raisa_* при установке из requirements через индекс и устанавливать библиотеку из STATEMENTS_DIR (по умолчанию ../pylib_ai_arm_statements). make install SHALL создавать окружение при необходимости и переустанавливать библиотеку из этого пути.
Scenario: Подготовка окружения
- WHEN разработчик выполняет
make venvпри доступной локальной библиотеке - THEN runtime- и dev-зависимости установлены в
api/.venv, библиотека импортируется из установленного пакета; запрос на скачиваниеpylib_ai*из PyPI не выполняется
Scenario: Переустановка после изменения библиотеки
- WHEN разработчик выполняет
make install STATEMENTS_DIR=<путь-к-библиотеке>после изменения её исходников без смены версии - THEN библиотека переустановлена из указанного пути в
api/.venvи изменения доступны сервису
Requirement: Библиотека форм в контейнерном образе
make docker-build SHALL передавать STATEMENTS_DIR именованным контекстом BuildKit arm_statements. Сборка SHALL устанавливать библиотеку из этого контекста вместе с публичными зависимостями, без загрузки pylib_ai* из PyPI. Образ SHALL содержать установленный пакет и его словари, доступные при запуске без исходной папки хоста.
Scenario: Сборка и запуск с локальной библиотекой
- WHEN образ собран через
make docker-buildпри доступном BuildKit и локальной библиотеке - THEN внутри образа импортируется
arm_statements, доступны словари и версия0.1.1; исходная папка хоста при запуске не требуется
Scenario: Прямая сборка
- WHEN сборка запускается напрямую командой
docker build - THEN вызывающая сторона SHALL передать
--build-context arm_statements=<путь-к-библиотеке>; отсутствие контекста не заменяется загрузкой библиотеки из PyPI