Andrey Epifancev 753eccbd97 docs(openspec): рулинги R-27, R-28, чек-лист Task 8, уточнения по ревью ветки (#206)
I-4, M-3, M-9, M-10, M-11.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-28 22:16:14 +04:00

38 KiB
Raw Blame History

Дизайн: экран «Таблица корректировки» (AURORA-1541, arm-core #206)

Зачем

Кредитный аналитик на шаге консолидации видит, где внутригрупповые обороты двух компаний не сошлись, разбирается, из каких строк ОСВ сложилась каждая сторона, переносит строки между правилами и вносит корректировку — сколько и из каких статей ББ исключить. Без экрана корректировки ВГО делаются только вне системы, и тестирование корректировок (AURORA-1542, с 03.11) начать нельзя.

Что считается готовым (слова владельца, 28.10.2026)

  • К сроку 02.11 — рабочий экран на настоящем API, не демо на моках. Если бэкенд (AURORA-1540) или аналитика не успевают — мы сами помогаем ребятам доделать.
  • Моки нужны, чтобы фронт не стоял, пока нет API, а не как результат.

Объём плана — только web/. Бэкенд (DBML, vgo_assignment, разнесение, эндпоинты, аудит) — AURORA-1540 Цыганкова; помогаем ему на ревью его PR, а не задачами этого плана. Последняя задача плана — подключение к настоящему API, когда 1540 слит: флаг REACT_APP_CORRECTIONS_MOCK выключается, если эндпоинты есть в main, вкладка открывается на стенде на реальной версии и проходит сценарии спеки; расхождения ответа с контрактом правятся в той ветке, где ошибка (фейк или бэкенд). Сверяем фейк с реальным ответом мы (владелец / этот агент) при подключении.

Источники и их вес

  1. Аналитика Лысенко — DOC-272613, ответы 1–7 (AURORA-1395, 27.10), DOC-274230. Приоритетна над нашими правилами и черновиками (решение владельца 28.10).
  2. Дизайн от 23.10.2026 — ДКБ_таблица_корректировок_23_10_26_1.html (вложение к DOC-272613; в корне workspace). Как лежат строки в дизайне — визуализация; логика — по аналитике.
  3. ТЗ 6.8 / Прил. 9 — ниже аналитики, иногда игнорируется.
  4. Контракт API — ../docs/dev/api-contract-corrections.md и .openapi.yaml (docs #183, вложение в AURORA-1540).

Открытые вопросы аналитику (комментарий [design-23-10-check] в AURORA-1395, п. 1–12 + 3 по ТЗ; в AURORA-1396 — ОФР) не блокируют работу: зависящие места сделаны так, чтобы ответ менял поведение точечно.

Цели

  • Вкладка «Таблица корректировки» страницы отчёта версии, по виду — как дизайн 23.10.
  • Таблица агрегатов с раскрытием до строк ОСВ, нераспределённые строки, итоги, фильтры, пресеты по правилам, единицы, настройка колонок, экспорт, полный экран.
  • Окно «Корректировка операции» агрегата: строки сторон, распределение по статьям, контроль, комментарий, сохранение.
  • Решения по строкам: флажок «Учитывать в КФО», отнести / перенести / убрать / вернуть к автоматике.
  • Отмена корректировки агрегата.
  • Только чтение, когда сервер так говорит (editable = false).

Не цели

  • Бэкенд и DBML (AURORA-1540), правила §8 в 05-domain-rules.md.
  • ОФР (нет в дизайне; AURORA-1396), импорт xlsx (ТЗ 6.8, ждёт ответа).
  • Корректировка строки ОСВ и нераспределённой строки (аналитика: только агрегат; ждёт п. 2).
  • Переход из шахматки с фокусом на паре (AURORA-1653), учёт корректировок в шахматке (AURORA-1643).

Анти-цели (провал, даже если «работает»)

  • Фронт сам считает разнесение строк, отклонения, порог 5 % или статусы агрегата — это делает сервер; фронт только показывает, форматирует и суммирует видимые строки для «Итого».
  • Деньги через number/float с потерей копеек. Суммы — строки контракта, сложение — точное десятичное.
  • Экран, в котором можно что-то нажать и молча потерять изменения окна корректировки.
  • Кнопки правки у версии, которую сервер считает нередактируемой.

Ограничения

  • web/ arm-core: React 18 + TS strict, antd 6, react-router 7, biome (140, одинарные кавычки), vitest.
  • Деньги в API — рубли строками с двумя знаками; показ в руб. / тыс. руб. и 0–2 знака — как в шахматке.
  • Состояние экрана — локальные хуки (стор Redux пуст по соглашению шаблона).
  • Пользователь слаб во фронте — решения в PR объясняются простыми словами.
  • Каждый экран сверяется с дизайном в Playwright и проходится руками до сдачи.

Как устроено

Данные

  • GET …/corrections?statement_type=balance — одна загрузка всей таблицы; фильтры, сортировка, «Итого» — на клиенте.
  • Правки: PUT …/aggregates/{rule}/{c1}/{c2} (сохранить), POST …/revoke, POST …/allocations (решение по строке, ответ — вся таблица), GET …/export.
  • Клиент — web/src/services/api/corrections.ts поверх api/client.ts. При REACT_APP_CORRECTIONS_MOCK=true те же функции отвечают из фейка контракта в памяти (данные — из дизайна 23.10, с проверками контракта: обязательный комментарий, expected_version_no, применимость правила). Флаг по умолчанию выключен; фейк включается только переменной окружения, но код фейка остаётся в бандле (R-21, R-26).

Таблица

Колонки как в дизайне: «Учитывать в КФО»; Дебет — ЮЛ, Строка баланса, Счёт, Сумма; Кредит — то же; Контроль — Отклонение %, Отклонение сумма; Корректировка — Строка баланса, Сумма (Дт), Строка баланса, Сумма (Кт), Комментарий; колонка действий.

  • Строка агрегата. Суммы сторон, счета (accounts), отклонение. Процент и сумма отклонения красные при exceeds_threshold. Корректировка — статьи и суммы correction.debit / credit (несколько статей стороны — по строке на статью в ячейке), комментарий. Действия: «Корректировать» (окно), меню «…» — «Отменить корректировку» (если есть). composition_changed — подсветка строки и значок с подсказкой «Состав изменился после корректировки». correction.status = DRAFT — пометка «черновик» у корректировки.
  • Раскрытие. Под агрегатом — его строки ОСВ (side_1.entries, затем side_2.entries): строка стороны 1 заполняет блок «Дебет», стороны 2 — «Кредит», остальные ячейки пустые (DOC-272613 п. 3.4; пары строк из дизайна не строим). У строки — флажок «Учитывать в КФО» и меню: «Перенести в правило…» (правила — candidate_rule_ids строки; фронт сам не сверяет счета с правилами), «Убрать из правила», «Вернуть к автоматике» (если decision = ASSIGN).
  • Флажок агрегата «Учитывать в КФО» — только показ: «Да» — все строки учитываются, «Частично» — часть исключена, «Нет» — все исключены. Сам признак ставится на строке (DOC-272613; ждёт п. 4).
  • Нераспределённые строки — после агрегатов, фон приглушён. Владелец — на своей стороне (дебетовая строка — в «Дебет», кредитовая — в «Кредит»), на другой стороне — только ЮЛ контрагента. Строка баланса не показывается (DOC-272613 п. 4.3). Флажок «Учитывать в КФО», меню «Отнести к правилу…» (список — candidate_rule_ids), «Вернуть к автоматике» для reason = UNASSIGNED. Кнопки «Корректировать» нет (ждёт п. 2).
  • «Итого» — суммы сторон, отклонения и корректировок по видимым агрегатам, точным сложением строк; процент «Итого» не показываем (смысл не задан).
  • Подписи «Отнести/Перенести в правило…» показывают правила как пресеты: «Правило N: <статья 1> — <статья 2>».

Панель

  • «Отображение»: «Общий» / «По пресету»; при «По пресету» — выбор правила (подпись с номером — снимает одинаковые подписи правил 5 и 8 из дизайна, п. 12); в таблице только агрегаты этого правила и те нераспределённые строки, у которых это правило есть в candidate_rule_ids (их можно отнести к нему).
  • «Тип записи»: «Все» / «Пары счетов» (агрегаты) / «Нераспределенные записи».
  • Фильтры «ЮЛ» и «Счёт» действуют и на нераспределённые строки; «Строка баланса» и «Отклонение» — только на агрегаты, при заданном одном из них нераспределённые строки скрываются (у них нет статьи и отклонения).
  • Составная статья правила ("1450/1550", "1310/1350", правила 1 и 2) показывается как «1450 / 1550»; в фильтре «Строка баланса» это два кода; в окне корректировки подставляется первый код, аналитик может выбрать второй.
  • Единицы и знаки — тот же компонент, что в шахматке.
  • Фильтры в заголовках: ЮЛ (подстрока, обе стороны), Строка баланса (список), Счёт (начало кода), Отклонение % («Все» / «≥ 5 %» / «< 5 %», по exceeds_threshold); «Сбросить фильтры» — когда что-то задано.
  • «Настройка таблицы» — GenericTable/ColumnSettings (видимость групп и колонок); «Экспорт» — файл сервера; «На весь экран» — как в шахматке.

Окно «Корректировка операции»

По дизайну: шапка сторон (компания, статья правила), блоки «Исходные данные ОСВ» и «Распределение корректировки» для каждой стороны, итоги, комментарий, «Отменить» / «Сохранить корректировки».

  • Исходные данные ОСВ — строки стороны агрегата. «×» у строки — «Убрать из правила» (UNASSIGN), «Добавить строку ОСВ» — выбор из нераспределённых строк, которые подходят под эту сторону: та же пара компаний (владелец и контрагент), сторона строки = сторона правила, правило агрегата есть в candidate_rule_ids (ответ 3(а)). Обе операции идут на сервер сразу (POST …/allocations), окно перечитывает агрегат.
  • Распределение — статьи стороны: строка баланса (код статьи) и сумма; «Добавить строку» — дочерняя статья. Без корректировки окно предлагает по стороне одну статью правила с суммой стороны (как в дизайне).
  • Контроль — суммы исходных строк сторон и суммы распределения сторон, разница и процент к меньшему (как в таблице; 79,77 % из дизайна — ошибка дизайна, п. 7). Расхождение не запрещает сохранение (ждёт п. 8).
  • Сохранить — PUT с status = APPLIED, expected_version_no из ответа; ошибки сервера показываются в окне по коду (COMMENT_REQUIRED — у поля комментария, INVALID_LINE_CODE — у статьи, CORRECTION_VERSION_CONFLICT — «Корректировку уже изменили, данные обновлены», окно перечитывает данные).
  • Черновик окна в localStorage (решение владельца 28.10.2026 вместо блокировки переходов): статьи распределения и комментарий сохраняются при каждой правке; ключ — пользователь + версия + агрегат (rule_id, компании), в записи — время и version_no корректировки, от которой начаты правки. Переход «Назад», закрытие вкладки, переход по ссылке правки не теряют. При открытии окна этого агрегата черновик подставляется с плашкой «Восстановлены несохранённые правки от ЧЧ:ММ» и кнопкой «Сбросить»; если version_no на сервере уже другой — плашка «Корректировку изменили после ваших правок» (аналитик решает: оставить или сбросить). Черновик удаляется после успешного сохранения и после «Отменить» с подтверждением «Есть несохранённые изменения. Закрыть без сохранения?». Действия со строками в черновик не входят (они уже на сервере). Доступ к хранилищу — в try/catch: недоступно (приватный режим) — работаем без черновика.

Только чтение

editable = false — «Корректировать», флажки и меню решений неактивны; подсказка по read_only_reason: VERSION_NOT_EDITABLE — «Версия закрыта для изменений», LOCK_REQUIRED — «Возьмите консолидацию в работу», LOCKED_BY_OTHER — «Консолидацию редактирует другой пользователь». Окно корректировки открывается на просмотр.

Состояния

Загрузка — индикатор на месте таблицы; ошибка — уведомление с текстом сервера и «Повторить»; пусто — «Внутригрупповых остатков между компаниями периметра нет»; фильтры ничего не нашли — «Нет записей для выбранных фильтров» (текст дизайна).

Что оставлено исполнителю

Разбиение на компоненты и хуки, имена файлов внутри widgets/CorrectionTable/, способ раскрытия (antd expandable или собственные строки), вид меню действий, точная раскладка окна в пределах дизайна, состав данных фейка.

Decisions made without discussion

Дата Решение Почему Цена ошибки
28.10.2026 Контракт API пишем сами (docs #183), markdown + OpenAPI; корректировка в контракте — только на агрегат API ещё нет; аналитика приоритетна при ответе «можно на строку» (п. 2) — новый эндпоинт и кнопки на строках
28.10.2026 Раскрытие агрегата — строки ОСВ под своей стороной, не пары из дизайна DOC-272613 п. 3.4; пары нигде не хранятся ответ по п. 3 «пары нужны» — доработка раскрытия и контракта
28.10.2026 «Учитывать в КФО» ставится на строке; у агрегата — производное «Да / Частично / Нет» DOC-272613 (EXCLUDE на osv_entry) ответ по п. 4 «на агрегат» — поменять флажок агрегата на действие
28.10.2026 Действия со строками в окне корректировки идут на сервер сразу, статьи и комментарий — по «Сохранить» разнесение и корректировка — разные записи (vgo_assignment / correction); аналитик видит новые суммы до ввода корректировки отмена окна не откатывает перенос строк — аналитику нужно вернуть строку вручную
28.10.2026 Сохранение сразу применяет (APPLIED), черновик не показываем в дизайне одна кнопка ответ по п. 9 «нужен черновик» — вторая кнопка
28.10.2026 «Отменить корректировку» — в меню агрегата, с комментарием REVOKED в аналитике есть, в дизайне нет места ответ по п. 9 — перенести кнопку
28.10.2026 Процент в окне — к меньшему, как в таблице аналитика; в дизайне две формулы —
28.10.2026 Без корректировки окно предлагает суммы сторон целиком так в дизайне; в аналитике подсказка не описана ответ по п. 8 — поменять подсказку на min
28.10.2026 Фильтр «Отклонение» — по exceeds_threshold (≥ 5 % / < 5 %), а не диапазон чисел порог — главный вопрос аналитика; диапазон в дизайне не описан доработка фильтра
28.10.2026 «Итого» без процента смысл процента по итогам не задан добавить колонку
28.10.2026 Фейк контракта под флагом REACT_APP_CORRECTIONS_MOCK, данные из дизайна фронт не ждёт бэкенд; тот же код ходит в настоящий API фейк расходится с бэкендом — ловится при подключении API и ревью AURORA-1540
28.10.2026 Только statement_type = balance, переключателя ББ/ОФР нет в дизайне его нет; ОФР ждёт AURORA-1396 добавить переключатель
28.10.2026 Ключ черновика — пользователь + версия + агрегат; черновик без срока жизни, удаляется сохранением или «Отменить» на общем компьютере у разных пользователей разные черновики старые черновики копятся в localStorage — объём мал
28.10.2026 План — только web/, бэкенду помогаем на ревью 1540; последняя задача — подключение к API и снятие флага слова владельца «поможем ребятам на ревью» если 1540 не успеет к 02.11, экран сдаётся на фейке
28.10.2026 В контракт добавлен candidate_rule_ids у строки агрегата иначе фронту пришлось бы сверять счета с правилами — это разнесение, анти-цель правка контракта до начала 1540 — дёшево
28.10.2026 expected_version_no = null, когда действующей корректировки нет (и после отзыва) иначе после отзыва фронту неоткуда взять номер —
28.10.2026 Составная статья правил 1 и 2 — в окне первый код, можно выбрать второй line_code — один код; особый расчёт правил 1 и 2 (DOC-274230) — на сервере при ответе «нужно распределение по обеим» — аналитик добавляет вторую статью руками
28.10.2026 «По пресету» показывает и подходящие нераспределённые строки; «Строка баланса» и «Отклонение» скрывают нераспределённые пресет — рабочее место по правилу, строки для отнесения нужны рядом поменять функцию фильтров
28.10.2026 R-1: список правил в плане — ориентир; при расхождении с api/seed/core/elimination_rules_v1.yaml (в плане статья 1230/1510 встречается дважды) номера и статьи берутся из yaml, тесты плана про правила 1, 3, 6, 7 остаются верными seed — источник истины поправка mockData и тестов
28.10.2026 R-2: в фейк добавлен widgets/CorrectionTable/mockCalc.ts (пересчёт агрегата и итогов через BigInt-копейки) — общий для mockData и correctionsFake, иначе циклический импорт план не называл файл; без него циклический импорт перенос функций, без поведения
28.10.2026 R-3: в mockData сверх дизайна добавлены агрегат правила 6 «ООО "БСК"» — «ПМП ООО» (310000.00 / 300000.00) и агрегат правила 4 «Агро-Холдинг» без второй стороны (ONE_SIDED); status в фейке — ONE_SIDED / DISCREPANCY / AUTO, MANUAL не выдаётся тест фильтра ооо "бск" из плана требует агрегат с таким ЮЛ; ONE_SIDED нужен для проверки отображения поправка данных фейка, на прод не влияет
28.10.2026 R-4: в окне корректировки сумма с пробелами («1 000 000,5») отклоняется с ошибкой «Сумма без пробелов», хотя parseAmountInput пробелы принимает Review Focus плана прямо требует ошибку для этого ввода если заказчик хочет пробелы — снять одну проверку в validateLines
28.10.2026 R-5: percentOfSmaller, toCents, fromCents и порог 5 % (THRESHOLD_PERCENT_HUNDREDTHS) вынесены в utils/money.ts; editorModel и mockCalc импортируют оттуда, зависимости editorModel → mockCalc нет фейк mockCalc вырезается при подключении API, экран не должен от него зависеть (ревью Task 3, T3.1) поведение то же; тесты перенесены в utils/money.test.ts
28.10.2026 R-6: тексты ошибок валидации окна и ключ ошибки lines для «Добавьте статью» выбраны исполнителем бриф их не задаёт; тексты в spec не указаны правка строк
28.10.2026 R-7: флажки «Учитывать в КФО» и меню строк неактивны всегда (actionsEnabled=false) до Task 5–6, подсказка «только чтение» подключена бриф Task 4: решения по строкам — в Task 5 забыть включить флаг в Task 5
28.10.2026 R-8: ошибка загрузки показывается уведомлением с «Повторить» (по спеке) и кнопкой на месте таблицы после закрытия уведомления аналитик не остаётся без выхода две кнопки повтора
28.10.2026 R-9: «Итого» показывается только при наличии видимых агрегатов (при «Нераспределенные записи» его нет) сценарий спеки показать «Итого» с пустыми значениями
28.10.2026 R-10: ROW_ACTIONS_READY/actionsEnabled удалены; контролы строк неактивны при !editable (с подсказкой readOnlyHint) и на время запроса (busy, без подсказки) включение R-7 в Task 5; блокировка на время запроса не даёт отправить два решения подряд аналитик не видит, почему контрол замер, пока идёт запрос (виден спиннер таблицы)
28.10.2026 R-11: любая ошибка 409 при решении/отмене — уведомление с текстом сервера и reload() (needsReload) 409 = версия закрылась, блокировку забрали, корректировку уже изменили/отозвали: локальная таблица устарела лишний запрос при 409 без смысла для таблицы; комментарий окна отмены теряется при 409 и перезагрузке — допустимо, корректировка уже изменена; перечитывание и при 404 (needsReload)
28.10.2026 R-12: после allocate таблица заменяется ответом целиком (replace), после revoke подменяется один агрегат (replaceAggregate); окно отмены при не-409 ошибке остаётся открытым, при 409 закрывается allocate меняет и нераспределённые, revoke отдаёт агрегат; при сетевой ошибке комментарий не должен пропасть после revoke нераспределённые не обновляются (по контракту revoke их не трогает)
28.10.2026 R-13: меню строки вынесено в чистую allocationMenu (ключ MOVE — «выбрать правило», уходит как ASSIGN); правило-кандидат, которого нет в rules, пункт «в правило» не включает тестируемость без React; фронт не выдумывает правил при рассинхроне справочника правил пункт неактивен

| 28.10.2026 | R-14: окно получило пропс onReload сверх сигнатуры плана и рендерится только пока открыто (key = ключ агрегата) | при CORRECTION_VERSION_CONFLICT/409/404 окну нужно перечитать таблицу; черновик читается один раз при открытии | окно без onReload не обновит таблицу при конфликте | | 28.10.2026 | R-15: черновик пишется только при editable и если состояние отличается от исходного (суммы — копейками); вернули к исходному — черновик удаляется; при конфликте редакций правки остаются в окне, черновик сохраняется с прежним baseVersionNo, плашка «Корректировку изменили после ваших правок» | в режиме чтения черновик бессмыслен; совпавший с исходным — мусор в localStorage | при ручном возврате к исходному плашка восстановления пропадает | | 28.10.2026 | R-16: ключ строки статьи в окне — устойчивый числовой id из счётчика компонента (в EditorState ids нет); наружу (черновик, PUT) уходит EditorState без id | ключ-индекс при удалении строки переносил бы введённый текст на соседнюю | id не попадают в черновик, после перезагрузки выдаются заново | | 28.10.2026 | R-17: после UNASSIGN/ASSIGN в окне суммы статей без своих правок (не dirty) пересобираются из нового агрегата (initialEditorState), при правках — остаются как есть | у агрегата без корректировки статья предлагается с суммой стороны, она изменилась; затирать ввод аналитика нельзя | при правках статьи не подстраиваются под новые суммы сторон — их видно по строке контроля | | 28.10.2026 | R-18: суммы в окне показываются в рублях (1 000 000,00) независимо от единиц панели, а в полях ввода — как есть (1000000.00, пробелы запрещены R-4); у строки контроля без процента (percent = null, одна сторона 0) процент не пишется, у равенства — «= 0,00» | единицы панели — про таблицу; дизайн показывает «(100%)» там, где процент к меньшей стороне не определён, фронт его не выдумывает | расхождение с дизайном в тексте контроля | | 28.10.2026 | R-19: агрегат исчез из ответа — окно открыто, стороны «—», «Сохранить» неактивна, пояснение в плашке; ключ PUT берётся из ответа, поэтому без агрегата сохранить нельзя | Review Focus плана | — | | 28.10.2026 | R-20: в окне нет названий статей рядом с кодом («дт 1230 Дебиторская задолженность» в дизайне) | в ответе API названий статей нет, а фронт их не выдумывает | добавить поле article_name в контракт и показать | | 28.10.2026 | R-21: код фейка (correctionsFake, mockData, mockCalc, ~20 КБ исходников) остаётся в прод-бандле при сборке без флага; сам не вырезал | Config.CORRECTIONS_MOCK — обычное чтение process.env.REACT_APP_CORRECTIONS_MOCK, импорты статические: npm run build без флага даёт строку «Требуется сверка» в index_script; вырезание требует динамического импорта фейка или define-константы в rsbuild — не мелкая правка; Task 8 фейк всё равно удаляет | лишние ~8 КБ gzip в бандле до Task 8; вопрос владельцу: делать ли вырезание сейчас | | 28.10.2026 | R-22: Prettier и ESLint применены к файлам задачи (npm run lint падал на форматировании 17 файлов, на вложенных тернарниках окна и BOM-литерале в фейке); BOM — \uFEFF, поведение то же | npm run lint — шаг проверки Task 7 | — | | 28.10.2026 | R-23: «Вернуть к автоматике» на нераспределённой строке в фейке только снимает «исключена» и не возвращает строку в правило | фейк не знает, какое правило было автоматическим; настоящее поведение — на бэкенде (1540) | аналитик на демо на фейке не увидит возврата; проверить при подключении API | | 28.10.2026 | R-24: у агрегата флажок «Учитывать в КФО» — серый неактивный индикатор «Да / Частично / Нет», а в дизайне зелёный | решение 28.10 (флажок ставится на строках, у агрегата производное) | ответ по п. 4 «на агрегат» | | 28.10.2026 | R-25: отдельное ревью Task 7 (стиль, два мелких фикса, документация) не делалось, оно покрыто финальным ревью ветки | дифф механический, финальное ревью читает всю ветку | мелкая ошибка в Task 7 всплывёт на финальном ревью | | 28.10.2026 | R-26: фейк (R-21) остаётся в бандле до Task 8, который его удаляет | вырезание требует динамического импорта или define в rsbuild, и всё равно временное | ~20 КБ в бандле до подключения API | | 28.10.2026 | R-27: mockData и mockCalc остаются как тестовые фикстуры (их импортируют тесты tableModel, editorModel, readOnly, draftStorage); Task 8 удаляет только correctionsFake.ts (+ его тест) и ветку флага в corrections.ts. Уточняет R-5, R-21, R-26: «вырезается» относится только к фейку контракта correctionsFake | иначе при подключении API пришлось бы переписывать тесты моделей | если фикстуры устареют относительно контракта — тесты моделей перестанут ловить расхождения; сверять при Task 8 | | 28.10.2026 | R-28: окно выбора нераспределённой строки (picker) не показывает исключённые (excluded) — исключённую сначала возвращают в учёт флажком в таблице | исключённая строка сознательно убрана из КФО; разнесение её в правило молча вернуло бы её в расчёт | аналитику нужен лишний шаг; если захотят выбирать исключённые — снять условие !u.excluded в pickerCandidates |