Копии api/contracts/ побайтно равны docs/contracts/ (тест идентичности плана 0): схемы v2.0 основные, .v1 рядом, examples/ — v2.0, examples/v1/ — v1.0. Модели result_v2.py и RecognitionResultMessageV2, versions.py выбирает модель по MAJOR. Приём конвертов принимает оба MAJOR; metrics.warnings в recognition_job пишется структурами (строки 1.x оборачиваются в LEGACY_WARNING). JobBrief.warnings отдаёт структуры, мусор пропускается, БД не переписывается. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BJKMLHdxMwSUeYcdkwqX4W
86 lines
5.8 KiB
JSON
86 lines
5.8 KiB
JSON
{
|
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
"$id": "arm-ka/recognition-result-message/v2",
|
|
"title": "Сообщение результата распознавания (tabular-parser / scan-gateway → arm-core), контракт v2.0",
|
|
"description": "Тело сообщения на subject ответа (настройка окружения NATS_RESULT_SUBJECT, по умолчанию files.tabular_parsed). Заголовок Nats-Msg-Id (не поле тела) на этом subject имеет две формы: ack:<job_id>:<attempt> — для status = processing; result:<job_id>:<attempt> — для done, needs_check и error. Форма запроса <job_id>:<attempt> описана в схеме recognition-request. status = processing — ack «взял в работу», публикуется до чтения файла из S3. group_schema в конверт не входит: источник — файл результата (recognition-result).",
|
|
"$comment": "Версионирование: schema_version = MAJOR.MINOR. MINOR (2.1) — необязательные поля и новые значения enum; MAJOR (3.0) — удаление/переименование полей, смена типов или семантики. Потребитель принимает известный MAJOR и любой MINOR. Новый MINOR раскатывается сначала на потребителей (ядро и сервисы обновляют копии схем раньше, чем производитель начнёт слать новый MINOR), потому что закрытые enum отвергают незнакомые значения; новый MAJOR — «сначала ядро»: ядро на время перехода принимает конверты (включая ack processing) и прежнего, и нового MAJOR. Changelog: 1.0 — исходный контракт; 2.0 (RSHB/arm-ka-docs#116, change unified-statement-normalization) — metrics.warnings[] стали структурами {code, severity, message, line_refs?, column_index?, field?, locator?} (как metrics.warnings файла результата), производитель пишет в конверт тот же MAJOR, что и в файл результата. Схема 1.0 на окне перехода лежит рядом — recognition-result-message.v1.schema.json (примеры — examples/v1/).",
|
|
"type": "object",
|
|
"required": ["schema_version", "job_id", "file_id", "status", "service"],
|
|
"properties": {
|
|
"schema_version": { "type": "string", "pattern": "^2\\.\\d+$", "description": "MAJOR.MINOR; производитель контракта v2.0 пишет \"2.0\"" },
|
|
"job_id": { "type": "string", "format": "uuid", "description": "recognition_job.id" },
|
|
"file_id": { "type": "string", "format": "uuid", "description": "stored_file.id" },
|
|
"status": { "enum": ["processing", "done", "needs_check", "error"] },
|
|
"service": {
|
|
"type": "object",
|
|
"required": ["name", "version"],
|
|
"properties": {
|
|
"name": { "enum": ["tabular-parser", "scan-gateway"] },
|
|
"version": { "type": "string" }
|
|
}
|
|
},
|
|
"result_s3": {
|
|
"type": "object",
|
|
"description": "файл результата (recognition-result): results/{file_id}/{job_id}/result.json",
|
|
"required": ["bucket", "key"],
|
|
"properties": {
|
|
"bucket": { "type": "string", "minLength": 1 },
|
|
"key": { "type": "string", "minLength": 1 }
|
|
}
|
|
},
|
|
"result_schema_version": { "type": "string", "pattern": "^\\d+\\.\\d+$", "description": "schema_version файла результата, MAJOR.MINOR" },
|
|
"error": {
|
|
"type": "object",
|
|
"required": ["code", "message"],
|
|
"properties": {
|
|
"code": { "enum": ["UNSUPPORTED_FORMAT", "UNREADABLE", "TIMEOUT", "SCHEMA_MISMATCH", "NOT_IMPLEMENTED", "FILE_READ_ERROR", "INVALID_FORMAT", "INVALID_DOCUMENT", "RECOGNITION_FAILED", "UNKNOWN_ERROR"] },
|
|
"message": { "type": "string" }
|
|
}
|
|
},
|
|
"raw_s3_key": { "type": ["string", "null"], "description": "scan-gateway: raw/{job_id}.json — сырой ответ ИС Сканирование; в БД не регистрируется" },
|
|
"metrics": {
|
|
"type": "object",
|
|
"properties": {
|
|
"duration_ms": { "type": "integer" },
|
|
"pages": { "type": "integer" },
|
|
"rows": { "type": "integer" },
|
|
"fields_total": { "type": "integer" },
|
|
"fields_low_confidence": { "type": "integer" },
|
|
"fields_unrecognized": { "type": "integer" },
|
|
"warnings": { "type": "array", "items": { "$ref": "#/$defs/fileWarning" }, "description": "предупреждения уровня файла — те же, что metrics.warnings файла результата" }
|
|
}
|
|
}
|
|
},
|
|
"$defs": {
|
|
"fileWarning": {
|
|
"type": "object",
|
|
"required": ["code", "severity", "message"],
|
|
"properties": {
|
|
"code": { "type": "string", "pattern": "^[A-Z][A-Z0-9_]*$" },
|
|
"severity": { "enum": ["error", "info"] },
|
|
"message": { "type": "string" },
|
|
"line_refs": { "type": "array", "items": { "type": "string" } },
|
|
"column_index": { "type": "integer" },
|
|
"field": { "enum": ["organization_name", "inn", "report_date", "units", "okud", "okpo", "okopf", "okfs", "okei", "address"] },
|
|
"locator": { "type": "string" }
|
|
}
|
|
}
|
|
},
|
|
"allOf": [
|
|
{
|
|
"if": {
|
|
"properties": { "status": { "enum": ["done", "needs_check"] } },
|
|
"required": ["status"]
|
|
},
|
|
"then": { "required": ["result_s3", "result_schema_version"] }
|
|
},
|
|
{
|
|
"if": {
|
|
"properties": { "status": { "const": "error" } },
|
|
"required": ["status"]
|
|
},
|
|
"then": { "required": ["error"] }
|
|
}
|
|
]
|
|
}
|