Skip to content

feat(report): примеры решений в отчёте по просьбе чекпоинта 2, команда bound и сверка с критериями - #6

Merged
retrobich921 merged 3 commits into
mainfrom
docs/criteria-audit
Sep 5, 2026
Merged

retrobich921 merged 3 commits into
mainfrom
docs/criteria-audit

Conversation

@retrobich921

@retrobich921 retrobich921 commented Sep 5, 2026 •

Copy link
Copy Markdown
Contributor

0. Главное: сделано то, что попросили на чекпоинте 2

Эксперты 05.09: «добавьте несколько примеров в отчёт — если в итоговом отчёте видна логика
отмены заявок и поиска новых решений, проверяющий быстрее найдёт соответствующий код и оценит его»
.

В routing_report.json появился блок examples — четыре характерных случая, по одному на механизм:

ключ что показывает
choice_among_several среди нескольких допустимых выбран лучший по сумме взвешенных целей
single_eligible hard-правила оставили одного кандидата — скоринг уже ничего не решает
retry_after_failure провайдер отказал, заявка переотправлена следующему по рангу
fallback_to_self_provider внешние кончились — заявка ушла на self-provider

У каждого примера: кто выбран и почему (reason, score, чем именно обошёл соперника),
почему отсеяны остальные (код правила + детали), исход — и source с файлом и методом,
где это решение принимается. Ровно то, о чём просили: по отчёту находится код.

"fallback_to_self_provider": {
  "what_it_shows": "внешние кандидаты кончились — заявка ушла на self-provider",
  "operation": { "operation_id": "op_107", "amount": 800, "bank": "sberbank" },
  "selected": { "provider": "spacepayments", "reason": "fallback_self_provider",
                "why": "all 1 eligible providers failed: vipay: amount_below_minimum; ..." },
  "skipped": [ { "provider": "payflow", "reason": "provider_timeout",
                 "why": "dispatched, simulated result: expired after 631s (score 0.5683; ...)",
                 "dispatched": true, "simulated_result": "expired" } ],
  "outcome": { "simulated_result": "approved", "retries": 1, "fallback_used": true },
  "source": "lib/payout_router/routing/router.rb → Router#fallback (пул внешних исчерпан ...)"
}

Демонстрационный прогон каскада теперь подбирает seed так, чтобы в отчёте были видны обе
ветки сразу — и переотправка после отказа, и fallback. То же самое отдельной секцией в HTML-дашборде.

routing_decisions.json при этом не изменился: логика роутинга не тронута, менялся только отчёт.
Кастомные поля эксперты подтвердили дважды — на чекпоинте 1 и на чекпоинте 2
(«собственные названия и константы на баллы не влияют»).


Ниже — то, что было в этом PR до чекпоинта: строгая сверка репозитория с критериями трека,
ревизия всех документов и одна найденная при этом ошибка в модели.

1. Сверка с критериями — новый docs/criteria.md

Каждый подкритерий трека (эксперты 100 + жюри 140 + отраслевые 20) против конкретного артефакта
и команды, которой это проверяется за минуту. Плюс раздел «что знаем и не прячем» — слабые места
названы прямо, а не спрятаны.

Дублирующая таблица «за счёт чего побеждаем» из docs/plan.md заменена указателем на него.

Дыр по критериям не нашлось, но нашлась одна невыведенная наружу возможность — см. пункт 2.

2. Команда bound + исправленная модель эталона

AssignmentBound из #5 существовал, но запустить его можно было только скриптом — из CLI он
недоступен, то есть для жюри его как бы нет. Теперь это команда bound, она же в CI.

При выводе наружу вскрылась ошибка модели: оптимум с квотами по долям получался выше
оптимума без квот — невозможный результат. Причина: self-provider был доступен эталону без
ограничений, а по модели одобрения он выглядит лучше всех внешних (нет истории, заявленные 0.95
против откалиброванных 0.62–0.80, нет лимитов, лучшая маржа). Квоты выталкивали заявки на него
и «улучшали» результат.

Исправление: эталону разрешено ровно столько заявок на self-provider, сколько использовал наш
роутер. Тогда наше распределение заведомо допустимо в его задаче, и оптимум — настоящая верхняя
граница. Инвариант закреплён спеком (оптимум ≥ наш роутинг ≥ худшее допустимое).

Правильные цифры: на очередях в 200–1000 заявок наш онлайновый роутер берёт 92–96%
от всезнающего пакетного оптимума. В #5 было заявлено 96–97% — это исправлено в docs/search.md.

очередь наш роутинг оптимум разрыв
публичная (10) 6.54 7.80 −16.2%
синтетическая 200, seed 11 145.92 158.40 −7.9%
синтетическая 200, seed 12 144.57 153.60 −5.9%
синтетическая 1000, seed 7 892.17 925.09 −3.6%

В CI добавлены rake stress и bound — инварианты и эталон теперь проверяются и на Linux.

3. Ревизия всех .md

Сверены с фактическим прогоном все числа во всех документах. Было расхождение почти везде:

Что Было Стало
Спеки 181 / 211 / 213 в разных файлах 241
Покрытие строк 97.8% / 97.0% 96.1% (ветви 80.1%)
Правил рекомендаций 11 / 12 / 13 13
Hard-правил / целей 13 / 12 14 / 13
Пресетов 8 / 9 10 (+ дефолтный = 11 политик в compare)
Бэктест «+6.9%» 72.2 → 75.6 (+4.7%)
Ruby / Python 88 / 12 91 / 9
pr compare «семь политик» одиннадцать
explain op_110 загрузка «~99%» 98.3%

Каждая цифра проверена командой, а не переписана по памяти.

4. Убрано лишнее

  • docs/checkpoint2.md удалён. Он повторял docs/checkpoint.md (демо, вопросы, чек-лист)
    и уже разошёлся с ним в цифрах — ровно тот случай, из-за которого документы и врут.
    Уникальное перенесено туда, где ему место:
    • «задача простыми словами» → README.md (её читает жюри, а не только команда);
    • таблица «если что-то не так» → README.md;
    • три новых вопроса к экспертам → docs/checkpoint.md §5 (теперь их шесть).
  • Остатки прошлой задачи в out/demo/ вычищены из рабочей копии (в git их и не было).

5. docs/plan.md приведён к реальности

Раздел «где мы сейчас» — на 5 сентября; по чекпоинту 2 отмечено, что сделано (search, bound,
пресет bank_affinity_first), а что осознанно отложено за стопкод (calibrate, вкладки в HTML).

Риск для сдачи: нулевой

Дефолтная политика, режим optimistic и формат attempts не тронуты.
bundle exec rake public перегенерирует routing_decisions.json и routing_report.json
байт в байт такими же — проверено после каждого шага.

Как проверить

$env:PATH = "C:\Ruby40-x64\bin;" + $env:PATH

bundle exec rake            # 241 спек, 0 падений; RuboCop 166 файлов, 0 замечаний
bundle exec rake validate   # скрипт организаторов 29/0/0, наш валидатор 30/0/0
bundle exec rake stress     # 17 сценариев, 15 990 заявок, 0 нарушений инвариантов
bundle exec rake public     # git status после него пустой

ruby -Ilib bin/payout_router bound
ruby -Ilib bin/payout_router bound --synthetic 200 --seed 11

Посмотреть примеры в отчёте: routing_report.json → examples, или открыть routing_report.html
и раскрыть секцию «Разобранные примеры».

Читать: docs/criteria.md — сверка с критериями, docs/manual_check.md §7 — новые команды.

🤖 Generated with Claude Code

https://claude.ai/code/session_01N7LBzBD5qBUzAAPsGTB9Nk

retrobich921 and others added 3 commits September 5, 2026 13:34
…еделения

AssignmentBound был написан, но не выведен наружу — запустить его можно было только скриптом.
Теперь это команда `bound`, она же в CI вместе со стресс-прогоном.

Исправлена ошибка модели: оптимум с квотами получался выше оптимума без них. Причина —
self-provider был доступен эталону без ограничений, а по модели одобрения он выглядит лучше
всех внешних (нет истории, заявленные 0.95 против откалиброванных 0.62–0.80, нет лимитов).
Квоты выталкивали заявки на него и «улучшали» результат. Теперь эталону разрешено ровно
столько заявок на self-provider, сколько использовал наш роутер: наше распределение заведомо
допустимо в его задаче, и оптимум становится настоящей верхней границей.

Правильные цифры: на очередях в 200–1000 заявок наш онлайновый роутер берёт 92–96%
от всезнающего пакетного оптимума (было заявлено 96–97%).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01N7LBzBD5qBUzAAPsGTB9Nk
Добавлен docs/criteria.md — каждый подкритерий трека (100 + 140 + 20) против конкретного
артефакта и команды, которой это проверяется за минуту, плюс раздел «что знаем и не прячем».
Дублирующая таблица в docs/plan.md заменена указателем на него.

Удалён docs/checkpoint2.md: он повторял docs/checkpoint.md и уже разошёлся с ним в цифрах.
Уникальное перенесено туда, где ему место: «задача простыми словами» и таблица «если что-то
не так» — в README (их читает жюри), три новых вопроса к экспертам — в docs/checkpoint.md §5.

Сверены с прогоном все числа во всех документах: 236 спеков, покрытие строк 96.0%,
14 hard-правил, 13 целей, 13 правил рекомендаций, 10 пресетов, 11 политик в compare,
бэктест 72.2 → 75.6, соотношение Ruby/Python 91/9. Раньше в разных файлах стояли
211/213/181 спек, 11/12/13 правил рекомендаций и бэктест «+6.9%», которого давно нет.

docs/plan.md приведён к фактическому состоянию на 5 сентября: что из плана чекпоинта 2
сделано, а что осознанно отложено за стопкод.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01N7LBzBD5qBUzAAPsGTB9Nk
@retrobich921
retrobich921 merged commit 62e6495 into main Sep 5, 2026
1 check passed
@retrobich921 retrobich921 changed the title docs: сверка с критериями трека, ревизия документов и команда bound feat(report): примеры решений в отчёте по просьбе чекпоинта 2, команда bound и сверка с критериями Sep 5, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant