Спеки применены: 5 новых capability (arm-core, arm-web, scan-gateway, statement-normalization, tabular-recognition-service) с Purpose, изменения quality-checks и recognition-contract. Ссылки в 05-domain-rules, DBML v5.19, entities, dev/checks.md и dev/qa-statements-v2.md ведут в архив. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
5.9 KiB
scan-gateway Specification
Purpose
Требования к scan-gateway в единой нормализации ББ/ОФР: адаптер json-ответов ИС Сканирование (шаг 1) в общую сетку ячеек и выдача результата распознавания контракта 2.0, нормализованного общим кодом arm_statements.
Requirements
Requirement: Адаптер json ИС шага 1
scan-gateway SHALL оставить у себя обмен с ИС Сканирование (горячие папки, опрос, срок, склейку набора json в
raw/{job_id}.json до нормализации, очистку папки) и адаптер «таблица table_structure[i] json → FormCandidate»;
шаги 2–8 SHALL выполняться копией пакета arm_statements. Адаптер SHALL: создавать кандидата на каждую таблицу каждого
успешного json; копировать шапку json (organization, inn, units, date) в шапку каждой своей таблицы как Cell
(text = form_name, confidence ИС); передавать label.form_name таблицы как заголовок в evidence (тип — общим
правилом шага 1 по словарю заголовков, statement_labels.yaml уходит в словарь пакета); строить плотную сетку по
row_index и column_index ИС (пустые позиции — null), Cell.ref = row:<row_index>; locator = file:<имя json>;table:<i>. value у OCR-ячеек всегда null.
Scenario: Один json — ББ и ОФР
- WHEN json
aep_3.jsonсодержит две таблицы — «Бухгалтерский баланс» и «Отчет о финансовых результатах» — под общей шапкой - THEN два кандидата с
locatorfile:aep_3.json;table:0и…;table:1, у каждого копия шапки json
Requirement: Ошибки набора json
Ошибочный json набора (parse_error, непустой error.code, корень не объект) при хотя бы одном успешном соседе SHALL
давать предупреждение файла JSON_FAILED (error, locator = file:<имя json>, в message — код и сообщение ИС);
все json ошибочны — конверт error с кодом первого. Исключение при разборе таблицы — предупреждение файла
TABLE_PARSE_ERROR (error, locator = file:<имя json>;table:<i>; документа у таблицы нет), остальные таблицы
разбираются; ни одной таблицы не разобрано — error RECOGNITION_FAILED.
Scenario: Таблица упала при разборе
- WHEN разбор
table:1jsonaep_3.jsonбросил исключение,table:0разобрана - THEN документ
BALANCEизtable:0; вmetrics.warnings—TABLE_PARSE_ERRORуровняerrorсlocator = "file:aep_3.json;table:1"; конвертneeds_check; ядро не автоподтверждает документы файла
Scenario: Потерянный ОФР (решение № 28 среза 3a)
- WHEN
<job_id>.jsonуспешен (ББ), а<job_id>_ofr.jsonвернулINVALID_DOCUMENT - THEN документ ББ получает свой статус; в
metrics.warnings—JSON_FAILEDуровняerror; конвертneeds_check; ядро не автоподтверждает документы файла
Requirement: Что уходит из шлюза
scan-gateway SHALL удалить api/rules/statement_lines.yaml и подстановку наименований по справочнику, срезание
уверенности кода до 99 по справочнику, выбор редакции для имён (_choose_edition), пропуск строк с нечисловым и пустым
кодом со счётчиками, правило «оставлена первая строка» при повторе кода, синтез шапки, правило «ячейки под колонкой
нет → confidence = 0, не распознано», привязку is_recognized к confidence и правило «любое предупреждение →
needs_check». Модули normalizer/ocr/text|dates|amounts переезжают в общие разборы пакета, layout|rows|header| document — в шаги 2–6 пакета; ocr_lookalikes.yaml — в словарь пакета.
Scenario: Строки без кода в aep_3
- WHEN в
aep_3.jsonстроки «БАЛАНС» и «Выручка» имеют пустой код, а в колонке значения мусор211(1 | - THEN строки попадают в результат со статусами (
detailпод строкой с кодом,missingв начале таблицы) и сырым текстом; значение211(1 |—amount = null,string_value = "211(1 |",is_recognized = false(скобка внутри цифр, правило шага 4), а не 2111; счётчиков «строк без кода с суммами пропущено» нет
Scenario: Таблица ИС только с текстом
- WHEN в json есть таблица без столбца кодов и без распознанного типа, в ячейках только текст подписей
- THEN документа нет, в
metrics.warnings—TABLE_SKIPPEDуровняinfoсlocatorтаблицы; конверт из-за неё неneeds_check