feat(#190): метрики качества первички (AURORA-1759) #229
@ -234,3 +234,6 @@ PDF, точный вид выгрузки, разбиение на задачи.
|
||||
| 06.11.2026 | Task 8 (`DELETED`/`DELETED_AFTER_CONFIRM`): (1) документ в статусе, отличном от `CONFIRMED`/`RECOGNIZED`/`NEEDS_CHECK` (практически только `ERROR`), при удалении файла НЕ получает факт исхода — у него никогда не было содержательного состояния «как распознано» для фиксации (нет формы/строк, не проходил ни через `AUTO_CONFIRMED`, ни через intake-факт); (2) `issue_count_at_outcome` вычисляется как `counts.error + counts.info` из уже посчитанного агрегата `issue_counts_by_document` вместо отдельного запроса — тот же смысл «все нарушения документа без фильтра», что `len(issues)` в Task 6/7, дешевле на один запрос; (3) `payload` для DELETED*-фактов — единый минимальный вызов `build_outcome_payload(document, fixes=())` без дополнительных запросов к строкам/значениям формы или ОСВ (эти строки всё равно будут физически удалены этим же вызовом `delete`, повторный их снимок здесь экономически не оправдан — а в матрицу §6 эти факты и не попадают, доступны только как «удалён/заменён», drill-down уже видит прежний исход через более ранний intake/outcome факт того же `document_id`) | бриф задачи 8 явно делегировал все три пункта исполнителю («если неоднозначно — зафиксировать выбор, не угадывать»); исполнитель выбрал и задокументировал в докстрингах кода, перенесено сюда контроллером по правилу маркировки находок (решение агента без обсуждения с человеком — в design.md) | (1): при появлении у `ERROR`-документов содержательного состояния до удаления (гипотетически) — нужно будет расширить список статусов; (2)/(3): минимальный риск — агрегаты эквивалентны, а payload не используется для атрибуции (там `primary_cause=None`, вне матрицы) |
|
||||
| 06.11.2026 | Task 10 (`quality_failure_fact`): `error_code` для отказов маппинга (`_fail`, `_register_failure`) — константа `MAPPING_FAILURE_ERROR_CODE = "MAPPING_FAILED"` (`result_mapping.py`), не свободный текст из `message`/описания исключения | `QualityFailureFact.error_code` не имеет свободнотекстового столбца-соседа для деталей отказа маппинга (в отличие от `recognition_job.error_message`); деталь остаётся в `metrics.mapping_error`/логе, код — единая константа, отличимая от кодов обмена (`ERROR_NO_ACK`/`ERROR_INVALID_REQUEST`), что проверяет отдельный тест | если деталь отказа маппинга понадобится в матрице причин без обращения к логам — нужен отдельный столбец/payload-поле, не замена константы |
|
||||
| 06.11.2026 | Task 9 (`SUPERSEDED`/`SUPERSEDED_AFTER_CONFIRM`): документ в статусе `ERROR` НЕ исключён из факта-исхода при автозамене — `outcome = SUPERSEDED_AFTER_CONFIRM if status is CONFIRMED else SUPERSEDED`, без третьей ветки, в отличие от Task 8 (`delete`), где `ERROR`/прочие статусы факт не получают вовсе. Выбор противоположен Task 8-й строке выше, но осознанно: подтверждён построчной проверкой всех мест `Document.status = ...` в `src/` (`documents.py`, `osv_header.py`, `auto_confirm.py`, `domain/osv_mapping.py`) — `DocumentStatus.ERROR` НИГДЕ не присваивается документу в продакшн-коде сегодня, различие с Task 8 необнаружимо на практике | бриф задачи 9 дал буквальную формулу (`CONFIRMED` → `..._AFTER_CONFIRM`, иначе → без суффикса) без явного исключения `ERROR`; поскольку путь недостижим, более простой код (без третьей ветки) предпочтён усложнению ради симметрии с Task 8 | если в будущем появится код, присваивающий `Document.status = ERROR`, `delete()` и `supersede_previous()` разойдутся в поведении (один пропустит факт, другой запишет `SUPERSEDED`) без того, чтобы это было осознанным решением на тот момент — стоит перепроверить эту строку, если `ERROR`-статус когда-нибудь станет достижим |
|
||||
| 07.11.2026 | Task 14 (`compute_matrix`): по `document_id` берётся последний факт по `outcome_at`; при равенстве `outcome_at` — `*_AFTER_CONFIRM` > `CONFIRMED`/`AUTO_CONFIRMED` > `DELETED`/`SUPERSEDED`, затем поздний во входе | результат не должен зависеть от порядка строк SELECT; design §4.2 — метрики берут последний факт | при редком совпадении времени документ посчитается подтверждённым вместо удалённого или наоборот |
|
||||
| 07.11.2026 | Task 14: два столбца вне долей — `removed_before_confirm` (DELETED, SUPERSEDED) и `removed_after_confirm` (оба `*_AFTER_CONFIRM`), без разбивки на удалён/заменён; доли — float, при нулевом знаменателе 0.0 (не None); исход из знаменателя с `primary_cause=None` и неизвестный `outcome` — `ValueError`, без молчаливого пропуска | design §6 п.1 называет два столбца; битый факт или новый enum не должен тихо искажать матрицу | разбивку придётся добавлять позже; битый факт даёт 500 на экране вместо искажённой матрицы; фронт отличает 0% от «нет данных» только по `denominator` |
|
||||
| 07.11.2026 | Task 14 (R-8): ряд по месяцам идёт по месяцу даты приёма (`received_at` = `quality_intake_fact.intake_at`), а не по `outcome_at`; поле добавлено во входную строку `QualityOutcomeFactRow`, Task 15 подставляет его join'ом intake↔outcome по `document_id`; пропущенные месяцы заполняются нулями | design §7 и решение 27.10: период по дате приёма (когорта) | документ попадёт в месяц исхода, а не приёма, метрики недавних периодов исказятся |
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user