6.4 KiB
Решение
Итог тройки (rule_id, A, B) считается чистой функцией по строкам обеих сторон до упаковки: суммы сторон со знаком,
deviation_amount = |ΣA − ΣB|, процент к меньшей стороне, eliminated_amount = min(ΣA, ΣB) при расхождении ≤ 5 %,
иначе и для manual — 0. Упаковка итог не меняет. Каждое правило считается отдельно (каскад по остатку отменён
владельцем 21.10.2026): строка общего счёта входит в несколько правил, двойной учёт снимает AURORA-1751.
Сбор встречных строк тройки — одна функция _collect_rule_sides для итога, упаковки и списка версии: список версии
(build_totals) строит сводную ОСВ один раз и проходит правила ББ × упорядоченные пары периметра без упаковки.
Версия правил фиксируется при создании версии консолидации (latest_effective_version_no на московскую дату) и дальше
не меняется; ветки «правила не зафиксированы» в чтении правил, пресете шахматки и парах убраны.
Эталонный Excel используется только для сверки точных встречных строк: он списывает полную сумму каждой стороны, поэтому его общий итог не равен системному правилу минимума (OQ-155).
Решения владельца 23.10.2026 (ревью PR #175)
- Суммы сторон — со знаком, как в шахматке; строки с отрицательной суммой в упаковку не идут (
NEGATIVE_AMOUNT). - Группы одного размера сортируются по проценту расхождения, а не по сумме.
- Кроме тройки — список пар всей версии одним запросом (делаем сами в ветке PR).
elimination_rules_version— NOT NULL с миграцией существующих версий (DBML v5.23).
Decisions made without discussion
| Маркер | Дата | Решение | Обоснование | Цена ошибки |
|---|---|---|---|---|
| R-1 (design #1) | 23.10.2026 | При min(ΣA, ΣB) ≤ 0 процент null, элиминация 0, тройка подсвечивается при любом расхождении |
Минимум со знаком дал бы элиминацию отрицательной суммы или отрицательный процент, который не пробивает порог; аналитик должен разобрать такой случай | Поменять одну функцию calculate_rule_totals и §5 |
| R-2 (design #2) | 23.10.2026 | Список версии — GET …/elimination-totals, статусы AUTO / DISCREPANCY / ONE_SIDED / MANUAL; тройки без строк не возвращаются; только правила ББ с measure = closing |
Повторяет три категории задачи («сопоставленные, с расхождением, без пары») плюс ручные правила; ОФР в §4 не формализован | Переименование маршрута и статусов — правка фронта до его разработки |
| R-3 (design #3) | 23.10.2026 | Создание версии без правил, действующих на дату, — 409 ELIMINATION_RULES_MISSING |
Поле NOT NULL; подставлять «последние открытые» значило бы взять правила, ещё не вступившие в силу | При пустом справочнике правил консолидацию не создать до seed — на практике seed всегда заводит v1 |
| R-4 (design #4) | 23.10.2026 | Миграция: дата создания по Москве; пустой created_at — текущая дата; нет действующих на дату — последняя открытая; нет правил вовсе — отказ миграции |
Совпадает с правилом создания; запасной вариант нужен только для данных, созданных до появления правил | Неверный номер у старых версий — исправляется UPDATE до верификации |
| R-5 (design #5) | 23.10.2026 | is_version_fixed в ответе elimination-rules оставлен и всегда true |
Фронт шахматки уже читает поле (PR #141, #158) | Удалить поле позже вместе с фронтом |
| R-6 (design #6) | 23.10.2026 | Группа упаковки — deviation_amount вместо elimination_amount; отдельной суммы элиминации у группы нет |
В КФО идёт итог тройки; упаковка его не меняет (§5), а сумма у группы читалась бы как вклад в элиминацию | Добавить поле у группы, если корректировкам понадобится |
| R-7 (design #7) | 23.10.2026 | Статус тройки AUTO только при eliminated_amount > 0; обе стороны отрицательные и равные — DISCREPANCY |
Иначе тройка без элиминации выглядела бы сопоставленной автоматически; совпадает с гайдом фронта §5.7.2 | Одна строка в _total_status |
| R-8 (design #8) | 23.10.2026 | Процент расхождения при упаковке сравнивается точной дробью (Fraction), не округлённым Decimal |
Ничья по проценту (100 и 110,25 против 105 — по 5 %) не должна зависеть от точности деления | Нет: на выход процент идёт Decimal с двумя знаками |