Andrey Epifancev 8940f32ae3 fix: пары ВГО — суммы со знаком, процент в упаковке, deviation_amount (ревью #175, AURORA-1536)
- суммы сторон со знаком, как в шахматке; строки с суммой < 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>
2026-10-23 21:47:47 +04:00

6.4 KiB
Raw Blame History

Решение

Итог тройки (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)

  1. Суммы сторон — со знаком, как в шахматке; строки с отрицательной суммой в упаковку не идут (NEGATIVE_AMOUNT).
  2. Группы одного размера сортируются по проценту расхождения, а не по сумме.
  3. Кроме тройки — список пар всей версии одним запросом (делаем сами в ветке PR).
  4. 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 с двумя знаками