arm-ka-docs/contracts/metrics/quality-facts.schema.json
2026-11-07 03:56:47 +04:00

110 lines
6.2 KiB
JSON
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

{
"$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": {
"money": {
"type": ["string", "null"],
"pattern": "^-?\\d+(\\.\\d{1,2})?$",
"description": "Decimal как строка (как contracts/recognition-result.schema.json#/$defs/money) — деньги не float"
},
"intake-payload": {
"type": "object",
"description": "Снимок документа на момент приёма результата (до подтверждения). Для OSV — без lines/values, только osv_warnings (взаимоисключение — см. dependentSchemas ниже).",
"dependentSchemas": {
"osv_warnings": {
"not": { "anyOf": [{ "required": ["lines"] }, { "required": ["values"] }] }
}
},
"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": { "$ref": "#/$defs/money" },
"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"], "description": "header покрывает и правку даты колонки — §14.2 считает их вместе" },
"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 отверг бы его как совпавший с обоими)."
}