From 2af056df2237f598ea78bff3b742714bf4bf2f7e Mon Sep 17 00:00:00 2001 From: Andrey Epifancev Date: Thu, 5 Nov 2026 14:07:06 +0400 Subject: [PATCH] =?UTF-8?q?docs(#202):=20=D0=BA=D0=BE=D0=BD=D1=82=D1=80?= =?UTF-8?q?=D0=B0=D0=BA=D1=82=20payload=20=D1=84=D0=B0=D0=BA=D1=82=D0=BE?= =?UTF-8?q?=D0=B2=20=D0=BA=D0=B0=D1=87=D0=B5=D1=81=D1=82=D0=B2=D0=B0=20?= =?UTF-8?q?=D0=BF=D0=B5=D1=80=D0=B2=D0=B8=D1=87=D0=BA=D0=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Sonnet 5 --- contracts/quality-facts.schema.json | 99 +++++++++++++++++++++++++++++ 1 file changed, 99 insertions(+) create mode 100644 contracts/quality-facts.schema.json diff --git a/contracts/quality-facts.schema.json b/contracts/quality-facts.schema.json new file mode 100644 index 0000000..6669344 --- /dev/null +++ b/contracts/quality-facts.schema.json @@ -0,0 +1,99 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "arm-ka/quality-facts/v1", + "title": "Payload фактов качества распознавания первички (AURORA-1759)", + "description": "Структура jsonb-столбца payload таблиц quality_intake_fact и quality_outcome_fact (model/data-model-v5.25.dbml, context/05-domain-rules.md §14). quality_failure_fact не описан здесь — у него нет payload, все поля плоские. НЕ валидируется make check / scripts/validate_contracts.py: этот скрипт жёстко завязан на три сообщения NATS-контракта распознавания (request-/result-message-/result- примеры с дедупом и версией сообщения); payload фактов не ходит по NATS и не требует той же идемпотентности. Схему проверяет тест в arm-core, где payload формируется (см. openspec/changes/quality-metrics/design.md §2 этого репозитория).", + "$defs": { + "intake-payload": { + "type": "object", + "description": "Снимок документа на момент приёма результата (до подтверждения). Для OSV — без lines/values, только osv_warnings.", + "properties": { + "header": { + "type": "object", + "description": "header_source и распознанные поля шапки (period, inn, units, organization_name, …)", + "additionalProperties": true + }, + "lines": { + "type": "array", + "description": "Отсутствует для document_type = OSV", + "items": { + "type": "object", + "required": ["ref", "line_status"], + "properties": { + "ref": { "type": "string" }, + "row_index": { "type": ["integer", "null"] }, + "line_code": { "type": ["string", "null"] }, + "line_code_text": { "type": ["string", "null"] }, + "line_status": { "enum": ["ok", "unreadable", "missing", "detail"] }, + "needs_review": { "type": "boolean" } + } + } + }, + "values": { + "type": "array", + "description": "Отсутствует для document_type = OSV", + "items": { + "type": "object", + "required": ["line_ref", "column"], + "properties": { + "line_ref": { "type": "string" }, + "column": { "type": "string" }, + "amount": { "type": ["number", "null"] }, + "string_value": { "type": ["string", "null"] }, + "source_text": { "type": ["string", "null"] }, + "confidence": { "type": ["number", "null"] }, + "is_recognized": { "type": "boolean" }, + "needs_review": { "type": "boolean" } + } + } + }, + "issues": { + "type": "array", + "items": { + "type": "object", + "required": ["code"], + "properties": { + "code": { "type": "string" }, + "level": { "enum": ["relation", "soft", "warning", "info"] } + } + } + }, + "raw_line_codes": { + "type": "array", + "description": "Только PDF: четырёхзначные токены сырого ответа ИС, стоящие отдельной строкой — вход для §14.2 (добавленная строка)", + "items": { "type": "string", "pattern": "^\\d{4}$" } + }, + "osv_warnings": { + "type": "array", + "description": "Только для document_type = OSV, вместо lines/values", + "items": { "type": "string" } + } + } + }, + "outcome-payload": { + "type": "object", + "description": "Подтверждённое состояние (то же строение header/lines/values, что и intake-payload) плюс список правок", + "properties": { + "header": { "$ref": "#/$defs/intake-payload/properties/header" }, + "lines": { "$ref": "#/$defs/intake-payload/properties/lines" }, + "values": { "$ref": "#/$defs/intake-payload/properties/values" }, + "fixes": { + "type": "array", + "items": { + "type": "object", + "required": ["field", "after", "source", "rule"], + "properties": { + "field": { "enum": ["value", "code", "added_row", "header", "osv_period_account"] }, + "before_raw": { "type": ["string", "null"], "description": "сырой текст сервиса на этом поле, если был" }, + "before_recognized": { "description": "как было распознано до правки" }, + "after": { "description": "подтверждённое значение" }, + "source": { "enum": ["service", "ours"], "description": "§14.2 — только два источника правки" }, + "rule": { "type": "string", "description": "строка таблицы §14.2, которая сработала" } + } + } + } + } + } + }, + "$comment": "Корневая схема не инстанцируется напрямую: тест в arm-core валидирует quality_intake_fact.payload против #/$defs/intake-payload и quality_outcome_fact.payload против #/$defs/outcome-payload (не oneOf — оба $defs допускают пустой объект, и oneOf отверг бы его как совпавший с обоими)." +}