Ревью фикс-раунда 1: у old_file в обоих тестах был только один документ
(account="62"), ключ которого не совпадал ни с одним документом нового
файла (account="60") — _replaceable не находила совпадений, file_ids
оставался пустым, и supersede_previous возвращала [] на раннем
`if not file_ids: return []`, до locked/хука. Тесты не проверяли
SUPERSEDED/SUPERSEDED_AFTER_CONFIRM, а падали бы с NoResultFound при
реальном прогоне. Добавлен документ account="60" в old_file каждого
теста — триггер замены файла; account="62" остаётся выпавшим документом,
на котором проверяется факт исхода.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
§14.3 (design quality-metrics §4.2, AURORA-1759): supersede_previous пишет
один факт исхода на каждый документ BALANCE/INCOME/OSV заменённого файла —
и выпавший (без ключа среди документов нового файла, OQ-154), и совпавший
по ключу («rest»): замена идёт файлом целиком (design №33), поэтому факт
не ограничивается только выпавшими документами. CONFIRMED на момент замены
(в т. ч. вручную — здесь, в отличие от удаления файла, нет 409-проверки) →
SUPERSEDED_AFTER_CONFIRM, иначе SUPERSEDED; primary_cause всегда NULL (вне
матрицы причин). Счётчик нарушений — одним запросом на все документы всех
заменяемых файлов.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Удаление файла (PrimaryFilesService.delete) пишет факт качества quality_outcome_fact
по каждому документу типа BALANCE/INCOME/OSV до физического удаления строк: DELETED —
документ не подтверждался (RECOGNIZED/NEEDS_CHECK), DELETED_AFTER_CONFIRM —
автоподтверждённый CONFIRMED (вручную подтверждённые сюда не доходят, дают 409 раньше
в том же методе). primary_cause=None явно (§14.3 правило 1, вне матрицы причин),
payload — минимальный снимок без построчных данных (build_outcome_payload(document, fixes=())).
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Ревью задачи 7, раунд 1: (1) добавлена строка design.md 06.11.2026 — решение
«нет сырого текста → наш разбор» для value/code/header фиксов задокументировано
отдельно (не то же, что 1250\n1260); тем же рядом исправлено направление для
PDF-добавленной строки — "наш разбор", не "сервис" (пустой raw_line_codes не
должен давать service через attribute_added_row, это противоречило уже принятому
27.10.2026 решению). (2) _added_row_fix для PDF больше не вызывает
attribute_added_row с заведомо пустым raw_line_codes — атрибуция "ours" прямо.
(3) _header_fix теперь возвращает "before" (meta.<field>_original_value), как
у _value_fix/_code_fix.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
DocumentService._write_confirm_outcome_fact — третий хук quality_outcome_fact
(outcome=CONFIRMED). В отличие от AUTO_CONFIRMED правки возможны: суммы и коды
строк сравниваются с живыми *_modified/original_*/source_text (не с JSON факта
приёма), добавленные строки и правки шапки — через attribute_* (Task 3), период/
счёт ОСВ — всегда "наш разбор". primary_cause — по приоритету сервис > наш разбор
> документ клиента > как есть. Гейт типа документа (BALANCE/INCOME/OSV) —
OUTCOME_FACT_DOCUMENT_TYPES, DISCLOSURE/OTHER без факта.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Ревью нашло: хук писал quality_outcome_fact для ЛЮБОГО автоподтверждённого
документа, в том числе DISCLOSURE/OTHER — у них нет факта приёма
(INTAKE_FACT_DOCUMENT_TYPES, Task 5), и факт исхода без пары превратился бы
в сироту при соединении по document_id. Добавлен гейт
OUTCOME_FACT_DOCUMENT_TYPES = {BALANCE, INCOME, OSV} (не импортируется из
result_mapping.py — там уже отложенный импорт auto_confirm во избежание
цикла); auto_confirm для DISCLOSURE/OTHER не меняется — только пропускает
запись факта. Поправлен вводивший в заблуждение комментарий в
_outcome_fact_fields. Тест на DISCLOSURE: автоподтверждение проходит,
quality_outcome_fact не появляется.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Хук в auto_confirm: на каждый документ, подтверждённый системой,
пишется quality_outcome_fact (outcome=AUTO_CONFIRMED,
primary_cause=WITHOUT_PARTICIPATION всегда — правок при автоподтверждении
не бывает, D-3 блокирует формы с нарушениями). payload строится
build_outcome_payload по тому же шаблону, что факт приёма (Task 5):
ОСВ — osv_warnings/row_count, формы — lines/values/header_source,
issue_count_at_outcome — все нарушения документа без фильтра.
Запись в транзакции маппинга, без flush/commit (Task 4 insert_outcome_fact).
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Хук в _map_candidate (result_mapping.py): после map_file, до auto_confirm — для
каждого документа BALANCE/INCOME/OSV строит снимок build_intake_payload и пишет
quality_intake_fact через insert_intake_fact. Чисто добавочный шаг: не меняет
документы, статусы и прочий результат маппинга; DISCLOSURE/OTHER факта не получают.
Счётчики строк/значений — из financial_statement_* (BALANCE/INCOME) и document_issue;
warning_count/osv_warnings — предупреждения источника service (document_issue.source =
service): для BALANCE/ОФР 1.x таких записей нет, для ОСВ это коды OSV_*. Для ОСВ
построчные счётчики не считаются (их в ядре нет), только row_count в payload.
Тесты в test_result_mapping.py (маркер integration, не запускались — нет PostgreSQL
в песочнице, подтверждена только коллекция) + один DB-free тест на множество типов
документов хука.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Тонкие функции insert_intake_fact / insert_outcome_fact / insert_failure_fact: session.add
без flush и commit, факт попадает в транзакцию вызывающего (design §4).
Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
Снимки приёма и исхода получают необязательные kwargs: header_source (сырой текст шапки
из financial_statement_meta.header_source) кладётся в header для ББ/ОФР, osv_row_count —
в payload ОСВ как row_count. Без kwargs ключи не эмитятся.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Тест не обновили вместе с .env.test (ревью #208, I-5): докстринг и
сам .env.test уже говорят про стандартный docker-compose порт 5432,
а assert всё ещё сверял 5431.
test_all_golden_snapshots_mapped сравнивал документы 1:1 с листами
снимка. Синтетика s48_other_system_titles, s49_balance_and_turnover_by_side,
s50_sap_in_out_glued_side, s53_balance_by_side (tp#81, AURORA-1717/1732)
намеренно кладёт несколько листов под один счёт/период в одном файле,
проверяя распознавание разных названий ведомости — по D-7
(services/result_mapping._split_duplicates) core оставляет только
первый лист документом, остальные — предупреждением. Ожидаемый набор
локаторов теперь считается той же _split_duplicates, что и продакшен-код.
attach_corrections молча пропускала (continue) корректировку, чей
агрегат (rule_id, пара ЮЛ) больше не существует после пересчёта
разнесения ВГО — вместо этого, как и в остальных ветках функции,
поднимаем ConflictError("CORRECTION_REVIEW_REQUIRED").
Был 5431 вместо 5432 из docs/dev/docker-compose.yml, как и утверждает
комментарий в шапке файла — интеграционные тесты не подключались к
стенду, поднятому make up.
Синтетика s47_indent_hierarchy_code_sums (fixtures f1f7f83, #33; tabular-parser#78, AURORA-1858) — субсчета
68.01.1 и 91.02.1, которых нет в плане счетов seed; test_all_golden_snapshots_mapped на main падал с «новые коды вне
плана счетов». Найдено полной регрессией перед выкладкой (docs #179).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Подпись пары без служебных слов, тест пары на фикстурах РБ, модалка при уходе с «ОСВ» на любую вкладку,
без «Экспорт» в режиме пар, README и ARCHITECTURE, таблица решений design.md.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Синтетика s46 (fixtures 530ede1, tabular-parser#71, AURORA-1714) — субсчета 60.111/60.112, которых нет в плане
счетов seed; test_all_golden_snapshots_mapped на main падал с «новые коды вне плана счетов».
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Кандидаты «Требуется проверка» / «Распознан» и состояние файлов («Обработка» / «Ошибка загрузки») чек-лист берёт
только со стола консолидации (§9.5 п. 11) — тем же фильтром, что панель «Первичные документы» (`files.on_desk`).
Документы организации из других консолидаций и из карточки ЮЛ ячейку больше не меняют: без документов — «Отсутствует».
В `on_desk` документ подзапроса — псевдоним: в запросе по `Document` он иначе коррелирует с внешним.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
GET /me дополнен role_details [{code, name}] (аддитивно), фронт показывает
названия ролей, при их отсутствии — коды. Требования внесены в спеки
authn-authz и consolidations-ui, change 184-user-role удалён.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Пара «новый документ — прежний» с counterparty_check = MISMATCH у любого из двух
в автозамене не участвует: сканы разных организаций в одной карточке больше не
вытесняют друг друга. UNKNOWN заменяется как прежде. Если файл оставлен только
из-за MISMATCH, в mapping_warnings нового файла — «автозамена не выполнена»
с именем и версией оставленного файла. Спека primary-files дополнена.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- суммы сторон со знаком, как в шахматке; строки с суммой < 0 в упаковку не идут, причина NEGATIVE_AMOUNT;
при min(ΣA, ΣB) ≤ 0 процент null и элиминация 0, статус списка AUTO — только при элиминации > 0
- группы одного размера выбираются по проценту расхождения к меньшей сумме (точной дробью), ничья — по равному проценту
- elimination_amount группы и тройки переименован в deviation_amount; version_no тройки обязателен
- суммы и проценты пар в JSON — с двумя знаками
- elimination-pairs по правилу с measure ≠ closing — 422 INVALID_RULE
- дельта спеки, design.md (R-7, R-8), tasks, README
make check-full: exit 0 (1896 passed; integration 990 passed).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- consolidation_version.elimination_rules_version NOT NULL: миграция 0010
проставляет существующим версиям номер правил, действовавших на дату
создания (по Москве), иначе последних открытых; без правил — отказ;
создание версии без действующих правил — 409 ELIMINATION_RULES_MISSING;
ветки «правила не зафиксированы» убраны (rules, preset, is_version_fixed
всегда true);
- GET …/elimination-totals: все тройки «правило ББ × упорядоченная пара
периметра» с ΣA, ΣB, расхождением, суммой элиминации, статусом
AUTO/DISCREPANCY/ONE_SIDED/MANUAL и osv_entry_ids; сводная ОСВ строится
один раз; сбор строк сторон вынесен в _collect_rule_sides — общий
с упаковкой тройки.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
v5.22 структуру БД не меняет (comment.object_type: убраны chess_cell и
kfo_result_line из описания), миграция не нужна.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>