OQ-179 (срок хранения raw/{job_id}.json), роль raw и dkb_metrics в 03-architecture.md,
openspec proposal/design/specs, план реализации (AURORA-1759).
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
24 KiB
Метрики качества первички — модель данных (DBML v5.25) Implementation Plan
For agentic workers: REQUIRED SUB-SKILL: Use superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (
- [ ]) syntax for tracking.
Goal: Добавить в модель данных DBML v5.25 три таблицы фактов качества распознавания первички, связанные
перечисления и столбцы, контракт payload и правило подсчёта/атрибуции в 05-domain-rules.md §14 — так, чтобы
arm-core могло написать по ним миграцию и ORM без дальнейших решений об именах или типах.
Architecture: Чисто документный change в arm-ka-docs: новая версия DBML (копия v5.24 + диффы), её
человекочитаемое описание (entities-v5.25.md), алгоритм (05-domain-rules.md §14), контракт payload
(JSON Schema) и обновление диаграмм/гида. Данных и кода здесь нет — читатель этого change — исполнитель
arm-core/openspec/changes/quality-metrics.
Tech Stack: DBML (dbdiagram.io синтаксис), Markdown, JSON Schema Draft 2020-12, Python (scripts/gen_model_diagrams.py,
scripts/validate_contracts.py), make (diagrams, check), Node/npx (dbml-renderer, resvg) — только для диаграмм.
Spec: openspec/changes/quality-metrics/{proposal,design}.md (этот репозиторий); контекст решений и WHY —
../arm-core/openspec/changes/quality-metrics/design.md (не копируется, только читается).
Global Constraints
- DBML — единственный источник имён и структур; расхождение с кодом решается в пользу DBML (
../CLAUDE.md). - Версия DBML меняется только вперёд, с записью в changelog в шапке файла (
../CLAUDE.md, «Чего не делать»). - Факты — append-only, без FK на рабочие таблицы (design §1.4–1.6).
- Язык документов и идентификаторов — русский текст / английские имена, как в остальной DBML.
openspec validate --strictдолжен проходить без ошибок к концу последней задачи.docs/source/**не редактируется (не затрагивается этим change).
Review Focus
- OSV-документы получают
quality_intake_factбез построчного снимка (payloadбезlines/values, только счётчики иosv_warnings[]) — если это не сказано явно и одинаково в entities.md, домен-правилах и схеме контракта, читающий код вarm-coreзаполнитlines: []вместо того, чтобы не писать их — задача 2 и 4 должны явно повторить эту оговорку, не только задача 1. quality_outcome_fact.document_idне unique — у документа может быть несколько исходов (переподтверждение ОСВ,*_AFTER_CONFIRM); без явного индекса-подсказки и фразы «метрики берут последний поoutcome_at» в тексте таблицы читатель DBML предположит один факт на документ, как уquality_intake_fact.- Старая заметка
recognition_job«сырой ответ ИС Сканирование… в БД не регистрируется» прямо противоречит новомуraw_s3_object_id— задача 1 должна отредактировать этот текст в Note самой таблицы, а не только добавить столбец. make diagramsжёстко проверяет полнотуPARTS(sys.exitпри несовпадении множества таблиц) — не зафиксировано, что проверка пройдёт, если забыть одну из трёх новых таблиц или опечатать имя; задача 1 обязана прогнатьmake diagramsи показать, что он не падает, а не только отредактировать словарь на глаз.quality-facts.schema.jsonсознательно не подключается кvalidate_contracts.py(design §2) — без явной строки в самом файле схемы ("description"верхнего уровня) читатель контракта через полгода предположит, чтоmake checkего проверяет, и не заметит, что сломал JSON без предупреждения.
Task 1: DBML v5.25 — таблицы фактов, перечисления, изменённые столбцы
Files:
- Create:
model/data-model-v5.25.dbml(копияmodel/data-model-v5.24.dbml+ диффы ниже) - Modify:
Makefile:9(DBML ?= model/data-model-v5.25.dbml) - Modify:
scripts/gen_model_diagrams.py(словарьPARTS: новая часть10_quality_metrics) - Modify:
context/04-data-model-guide.md(строка 1–7 — имена файлов и диапазон частей; раздел «Девять частей модели» → «Десять частей модели» с новой строкой; новый абзац**v5.25:** …в начале списка изменений)
Interfaces:
-
Produces (имена, на которые ссылаются задачи 2–4 и
arm-core): enums3_bucket_role.raw,permission_object.QUALITY_METRICS,recognition_pipeline(переиспользуется, без изменений), новые enumquality_outcome,quality_cause,quality_failure_kind(значения — design §1.3); таблицыquality_intake_fact,quality_outcome_fact,quality_failure_fact(точный список столбцов — design §1.4–1.6); новые столбцыstored_file.is_scan,recognition_job.raw_s3_object_id. -
Step 1: Скопировать DBML и поднять версию
cp model/data-model-v5.24.dbml model/data-model-v5.25.dbml
Поменять заголовок (строка 1: v5.24 → v5.25) и вставить новый блок changelog в начало (после строки 1, перед
блоком v5.24) по образцу существующих блоков (см. v5.24/v5.23 в шапке файла):
// v5.25 (AURORA-1759, RSHB/arm-ka-docs#202; миграция в arm-core — отдельный change arm-core#190):
// 1. Три новые таблицы фактов качества распознавания первички: quality_intake_fact, quality_outcome_fact,
// quality_failure_fact (отдельная схема dkb_metrics, append-only, без FK на рабочие таблицы) — design §1.4-1.6.
// 2. s3_bucket_role: + raw (сырой ответ ИС Сканирование, не экспирится с файлом); recognition_job.raw_s3_object_id
// — ссылка на него (отменяет решение v5.13 «сырой ответ в БД не регистрируется»).
// 3. stored_file.is_scan — признак скан/цифровой PDF (NULL для не-PDF).
// 4. permission_object: + QUALITY_METRICS (право QUALITY_METRICS_VIEW — seed в arm-core).
- Step 2: Enum
s3_bucket_role— добавитьraw
В блоке Enum s3_bucket_role { uploads results exports archive } добавить строку
raw [note: 'сырой ответ ИС Сканирование, raw/{job_id}.json; не экспирится с файлом — вход для эталонного прогона (OQ-111)'].
- Step 3: Enum
permission_object— добавитьQUALITY_METRICS
В блоке Enum permission_object { ... } добавить QUALITY_METRICS [note: 'метрики качества распознавания первички'].
- Step 4: Три новых enum для фактов
Вставить перед Table quality_intake_fact (после существующего Enum recognition_pipeline, рядом по смыслу)
точные блоки quality_outcome, quality_cause, quality_failure_kind — текст design §1.3 (скопировать как есть,
это уже финальная формулировка).
- Step 5: Изменить
stored_file
Добавить столбец is_scan boolean [note: 'только PDF: признак текстового слоя при загрузке; true = цифровой (в т. ч. скрытый OCR-слой — допущение §14); NULL для не-PDF'] после superseded_by_file_id.
- Step 6: Изменить
recognition_job
Добавить столбец raw_s3_object_id uuid [ref: > s3_object.id, note: 'сырой ответ ИС Сканирование, роль raw; заполняется при приёме результата image pipeline'] после result_s3_object_id. В тексте столбца
result_s3_object_id и в Note таблицы убрать/переписать фразу «Сырой ответ ИС Сканирование... в БД не
регистрируется» — он теперь регистрируется.
- Step 7: Три новые таблицы
Добавить Table quality_intake_fact, Table quality_outcome_fact, Table quality_failure_fact в самостоятельном
разделе // ============ МЕТРИКИ КАЧЕСТВА ============ в самом конце файла, после Table required_document_rule
(последняя таблица в текущем v5.24, раздел «ПРОЧЕЕ» — после него файл кончается, отдельных Ref-блоков нет).
Точные столбцы, типы, индексы и пояснения — design §1.4 (intake), §1.5 (outcome),
§1.6 (failure); перенести 1:1, включая оговорку про OSV (payload без lines/values) в Note quality_intake_fact
и оговорку про неуникальность document_id в Note quality_outcome_fact.
- Step 8: Обновить
Makefile
Makefile:9: DBML ?= model/data-model-v5.24.dbml → DBML ?= model/data-model-v5.25.dbml.
- Step 9: Добавить часть 10 в
scripts/gen_model_diagrams.py
В словарь PARTS добавить запись после "09_audit_ex":
"10_quality_metrics": (
"Метрики качества первички",
["quality_intake_fact", "quality_outcome_fact", "quality_failure_fact"],
),
- Step 10: Прогнать рендер диаграмм и убедиться, что скрипт не падает на несовпадении
PARTS
Run: make diagrams DBML=model/data-model-v5.25.dbml
Expected: скрипт доходит до рендера SVG/PNG (сеть/npx может быть недоступна в песочнице — тогда ожидаемый результат
это ошибка npx/сети, а НЕ sys.exit(...Раскладка частей не совпадает...); если видно именно эту ошибку —
значит забыта таблица или опечатка в PARTS, вернуться к Step 9).
- Step 11: Обновить
context/04-data-model-guide.md
Строки 1–7: имена файлов v5.24 → v5.25, диапазон диаграмм part01…09 → part01…10. Заголовок «Девять частей
модели» → «Десять частей модели», новая строка таблицы:
| 10 Метрики качества первички | \quality_intake_fact`, `quality_outcome_fact`, `quality_failure_fact` | факты распознавания и исхода документа, технические отказы — append-only, без FK |. Перед существующим абзацем v5.24: …вставитьv5.25: три таблицы фактов качества распознавания
(`quality_intake_fact`/`_outcome_fact`/`_failure_fact`), `s3_bucket_role.raw`, `stored_file.is_scan`,
`recognition_job.raw_s3_object_id`, `permission_object.QUALITY_METRICS` (AURORA-1759).`
- Step 12: Коммит
git add model/data-model-v5.25.dbml Makefile scripts/gen_model_diagrams.py context/04-data-model-guide.md
git commit -m "docs(#202): DBML v5.25 — факты качества первички (AURORA-1759)"
Task 2: entities-v5.25.md — бизнес-описание
Files:
- Create:
model/entities-v5.25.md(копияmodel/entities-v5.24.md+ диффы)
Interfaces:
-
Consumes: имена таблиц/столбцов из Task 1 (Produces).
-
Step 1: Скопировать файл
cp model/entities-v5.24.md model/entities-v5.25.md
- Step 2: Добавить блок изменений
В начало файла, после заголовка, вставить ## Что изменилось в v5.25 (AURORA-1759, RSHB/arm-ka-docs#202) с
перечислением: три новые таблицы фактов (append-only, без FK — зачем, одной фразой со ссылкой на
../arm-core/openspec/changes/quality-metrics/design.md §1–3 за полным WHY), s3_bucket_role.raw,
stored_file.is_scan, recognition_job.raw_s3_object_id, permission_object.QUALITY_METRICS.
- Step 3: Дополнить существующие строки «Часть 04»
В строке stored_file добавить предложение **v5.25:** \is_scan` — скан/цифровой PDF по текстовому слою при
загрузке.В строкеrecognition_job—v5.25: сырой ответ ИС Сканирование теперь регистрируется в
`s3_object` (роль `raw`) через `raw_s3_object_id` — решение v5.13 «не регистрируется» отменено.`
- Step 4: Новая «Часть 10 — Метрики качества первички»
После «Часть 09» добавить раздел с таблицей (формат как в остальных частях: Сущность | Что это | Ключевые связи |
Откуда), строка на каждую из трёх таблиц. В описании quality_intake_fact явно сказать: «для ОСВ — без построчного
снимка строк/значений, только счётчики и предупреждения OSV_*» (Review Focus, п.1). В описании
quality_outcome_fact явно сказать: «не один факт на документ — повторное подтверждение ОСВ и исход после
подтверждения пишут новый факт; метрики берут последний по outcome_at» (Review Focus, п.2). Колонка «Откуда» —
AURORA-1759; arm-core#190 для всех трёх строк.
- Step 5: Коммит
git add model/entities-v5.25.md
git commit -m "docs(#202): entities-v5.25 — метрики качества первички"
Task 3: 05-domain-rules.md §14 — правило подсчёта и атрибуции
Files:
- Modify:
context/05-domain-rules.md(новый раздел## §14.в конце файла, после текущего## §12)
Interfaces:
-
Consumes: enum/таблицы Task 1; структуру
payloadиз Task 4 (писать после Task 4, либо держать формулировки согласованными — Task 4 должен быть написан первым или одновременно, см. порядок задач). -
Step 1: Написать §14.1 «Какие документы считаются»
BALANCE/INCOME/OSV — факт пишется; DISCLOSURE/OTHER — нет (как в document.document_type, design §1.4).
- Step 2: Написать §14.2 «Атрибуция правки (сервис / наш разбор)»
Перенести таблицу из ../arm-core/openspec/changes/quality-metrics/design.md §5 текстуально (источник правды —
design arm-core; здесь — рабочая копия для ссылок §14.2 из кода arm-core, явно подписать
«источник: design arm-core#190 §5»).
- Step 3: Написать §14.3 «Причина документа (приоритет
quality_cause)»
Перенести правило приоритета из design.md (этого репозитория) §6 / арм-core design §6: SERVICE_ERROR >
OUR_ERROR > CLIENT_DOCUMENT > WITHOUT_PARTICIPATION > AS_IS; DELETED*/SUPERSEDED* — отдельные столбцы
outcome, не входят в матрицу, primary_cause = NULL.
- Step 4: Написать §14.4 «Документ клиента»
Правило: ручное подтверждение с checks_accepted = true (акцепт жёстких нарушений §7) и нет правки, закрывающей
нарушенное соотношение; мягкие нарушения и межформенная 1370↔2400 не учитываются.
- Step 5: Написать §14.5 «Технические отказы»
Считаются по файлам (quality_failure_fact), не по документам; знаменатель — загруженные файлы того же pipeline;
FILE_REPROCESS — первая неудачная попытка остаётся отказом, успешная — получает свои факты intake/outcome.
- Step 6: Написать §14.6 «Признак скана»
PDF с текстовым слоем — цифровой; PDF со скрытым OCR-слоем — тоже цифровой (ASSUMPTION(OQ-111 не подходит — завести новый номер следующей свободной OQ, см. Task 5) явно помечено как допущение.
- Step 7: Коммит
git add context/05-domain-rules.md
git commit -m "docs(#202): §14 — счёт и атрибуция метрик качества первички"
Task 4: docs/contracts/quality-facts.schema.json — контракт payload
Files:
- Create:
contracts/quality-facts.schema.json
Interfaces:
-
Consumes: имена и смысл полей
payloadиз Task 1 (quality_intake_fact.payload,quality_outcome_fact.payload). -
Produces:
$id/$defsintake-payload,outcome-payload— имена, под которыми на схему будет ссылаться тест вarm-core(design §2). -
Step 1: Написать JSON Schema
Draft 2020-12, $defs.intake-payload и $defs.outcome-payload по составу из design §2 (header/lines/values/issues/
raw_line_codes для intake; + fixes[] для outcome; у OSV — osv_warnings/счётчики вместо lines/values, выразить
через oneOf по наличию document_type или через оба варианта структуры — на выбор исполнителя, с комментарием
в самой схеме). Верхнеуровневое "description" схемы должно явно сказать: «не валидируется make check
(scripts/validate_contracts.py) — проверяется тестом в arm-core, который формирует payload» (Review Focus, п.5).
- Step 2: Проверить, что файл — валидный JSON Schema
Run: python3 -c "import json, jsonschema; jsonschema.Draft202012Validator.check_schema(json.load(open('contracts/quality-facts.schema.json')))"
Expected: без вывода и без исключения (код возврата 0).
- Step 3: Коммит
git add contracts/quality-facts.schema.json
git commit -m "docs(#202): контракт payload фактов качества первички"
Task 5: Документы контекста и openspec validate
Files:
-
Modify:
context/07-open-questions.md(новый OQ — срок храненияraw/{job_id}.json, design §9 арм-core/design §1.1 этого файла) -
Modify:
context/03-architecture.md(если там есть раздел про S3/бакеты — отметить рольraw; раздел про внешних читателей БД — отметить read-only роль Superset к схемеdkb_metrics) -
Modify:
openspec/changes/quality-metrics/proposal.md/design.md— поставить реальный номер OQ вместо плейсхолдера OQ-111, если он занят (проверить в Step 1) -
Step 1: Проверить следующий свободный номер OQ
Run: grep -n "^### OQ-" context/07-open-questions.md | tail -5
Записать новый вопрос под следующим свободным номером (не обязательно OQ-111 — он мог быть занят после 27.10);
везде, где в design.md/proposal.md этого change и арм-core стоит плейсхолдер OQ-111, заменить на реальный номер
(если он совпал — ничего менять не нужно).
- Step 2: Дописать вопрос
Текст: «Срок хранения сырых ответов ИС Сканирование (raw/{job_id}.json, роль raw) и подтверждённых uploads/,
на которые ссылаются факты качества — решает платформа (эталонный прогон использует их неопределённо долго, пока
change не отменён)».
- Step 3: Отметить в
03-architecture.md
Если в файле есть таблица ролей бакета S3 — добавить строку raw; если есть раздел про внешние читатели БД —
добавить абзац про read-only роль Superset к схеме dkb_metrics (design арм-core §8). Если ни одного из разделов
нет — создать короткий абзац в конце файла, не переписывая остальное.
- Step 4: Прогнать валидацию OpenSpec
Run: openspec validate quality-metrics --strict
Expected: без ошибок.
- Step 5: Прогнать
make check
Run: make check
Expected: код возврата 0 (validate-contracts, validate-openspec, test-snapshot, test-sync-statements — этот
change их не касается, должны остаться зелёными как были).
- Step 6: Коммит
git add context/07-open-questions.md context/03-architecture.md openspec/changes/quality-metrics/
git commit -m "docs(#202): открытые вопросы и architecture — метрики качества первички"