feat(mera/лендинг): витрина показывает полосу расхождения −5…+20 %; плитку «уверенность низкая» сменил замер 12.09 #3468

Merged
bot-backend merged 2 commits from feat/landing-showcase-band into main 2026-09-12 10:51:50 +00:00
Collaborator

Что меняется на странице

Витрина сделок теперь показывает ОТОБРАННУЮ полосу расхождения −5 %…+20 %, а не всю сверку. Строки вне полосы существуют (на проде сегодня 12 из 20 показанных — от −27,9 % до +75,7 %), и их больше не видно. Чтобы страница от этого не начала врать, полоса названа на ней прямым текстом в четырёх местах:

  1. Правило прогона (REJECTION_RULE, едет в /showcase вместе со строками и рендерится под таблицей):

    «На витрине — ОТОБРАННАЯ полоса расхождения, а не вся сверка: показаны только сделки, у которых расхождение прогноза с ценой ДКП лежит от -5 % до +20 % включительно. Промахи крупнее полосы в данных есть, и здесь их не видно — судить по этим строкам о точности расчёта нельзя, для этого есть медиана расхождения по всей сверке. Внутри полосы порядок задают полнота данных и свежесть квартала: величина отклонения на него не влияет, лучший хвост самой полосы витрина тоже не показывает. Кроме полосы строку снимает только отсутствие данных: …»

    Прежняя формулировка — «Величина отклонения на отбор и отбраковку не влияет — иначе витрина показывала бы лучший хвост, а не работу расчёта» — после фильтра стала ложью ровно про то, чего опасалась. Снята, а не смягчена.

  2. Подпись под таблицей сверок (AccuracyV3):

    «Разброс показанных строк: медианное расхождение 6,1 % по 8 строкам, худшая 10,6 %. Это отобранная полоса расхождения от -5 % до +20 %, а не вся сверка: промахи крупнее полосы в данных есть, здесь их не видно. Медиана по всей сверке — 15,3 % (325 сделок).»

  3. Подпись бегущей строки (DealsTickerV3) — она висит над первым экраном, её числа читают раньше любых оговорок:

    «Показаны сделки с расхождением от -5 % до +20 % — отобранная полоса, не вся сверка. Медиана показанных строк — 6,1 %, худшая — 10,6 %»

  4. Счётчики прогона — подпись поправлена, потому что они разъехались со смыслом: eligible − written больше не значит «столько не поместилось», в разницу входят отсеянные полосой. Было «Показано 20 строк из 159 годных», стало «Показано 8 строк из 159 собранных прогоном».

Утверждение про полосу проверяет само себя (правка по ревью, коммит db47fa0e)

Ревьюер нашёл дыру в ВЫКАТЕ до мержа. Границы полосы стоят в коде фронта, а строки и rejection_rule приезжают из БД от последнего прогона задачи — задачи нет в расписании, её запускают руками. В окне «фронт выкачен, витрина не пересчитана» страница утверждала бы полосу над прежними двадцатью строками и тут же показывала под утверждением +75,7 %. Это хуже, чем было до правки.

Чинится конструкцией: allWithinBand(deals) в deal-view.ts спрашивает сами показанные строки теми же границами, что стоят в тексте.

  • все показанные строки в полосе → печатается формулировка про полосу (см. выше);
  • хоть одна вне → про полосу не утверждается ничего. Таблица: «Полосу расхождения от -5 % до +20 % эта подпись не обещает: среди показанных строк есть расхождения вне неё, то есть витрину собрал прогон с другим правилом — тем, что напечатано выше». Правило того прогона приезжает из ТОГО ЖЕ прогона, что и строки, поэтому подпись с ними согласована по построению. Лента печатает только посчитанное по строкам: «Медиана расхождения показанных строк — 11,5 %, худшая — 75,7 %».
  • Медиана по ВСЕЙ сверке печатается в ОБЕИХ ветках — она и удерживает страницу честной независимо от того, пересчитана витрина.

Отрендерено и прочитано глазами в обоих состояниях, на реальных двадцати err_pct прода:

ТАБЛИЦА — ДО ПЕРЕСЧЁТА
Разброс показанных строк: медианное расхождение 11,5 % по 20 строкам, худшая 75,7 %.
Полосу расхождения от -5 % до +20 % эта подпись не обещает: среди показанных строк
есть расхождения вне неё, то есть витрину собрал прогон с другим правилом — тем, что
напечатано выше. Медиана по всей сверке — 15,3 % (325 сделок).
ЛЕНТА — ДО ПЕРЕСЧЁТА
Медиана расхождения показанных строк — 11,5 %, худшая — 75,7 %

ТАБЛИЦА — ПОСЛЕ ПЕРЕСЧЁТА
Разброс показанных строк: медианное расхождение 6,1 % по 8 строкам, худшая 10,6 %.
Это отобранная полоса расхождения от -5 % до +20 %, а не вся сверка: промахи крупнее
полосы в данных есть, здесь их не видно. Медиана по всей сверке — 15,3 % (325 сделок).
ЛЕНТА — ПОСЛЕ ПЕРЕСЧЁТА
Показаны сделки с расхождением от -5 % до +20 % — отобранная полоса, не вся сверка.
Медиана показанных строк — 6,1 %, худшая — 10,6 %

Решения, которые стоит отревьюить

  • Фильтр в select_rows, а не в build_row. Строка вне полосы обязана остаться кандидатом и попасть в eligible: отбракуй её раньше — и вышло бы «показано 20 из 20 годных», счётчик, из которого отбор не виден вообще.
  • Границы полосы подставляются в текст правила из BAND_MIN_ERR_PCT/BAND_MAX_ERR_PCT. Вписанный руками «−5 %» в подписи и >= -5.0 в коде — две независимые величины; тест test_rejection_rule_names_the_band_that_is_actually_applied держит их вместе.
  • «В пределах 20 % — N из N» из подписи снято. При потолке полосы +20 у каждой показанной строки |отклонение| ≤ 20 по построению: счёт всегда выходил бы «8 из 8» и читался бы как замер попадания. Неработающая проверка читается как работающая — то же правило, по которому из продюсера когда-то убрали мёртвый MAX_FACT_PPM2.
  • Медиана по всей сверке (15,3 %, 325 сделок) осталась в подписи и сторожится тестом. Это то, что удерживает страницу честной: разброс отобранной двадцатки по построению лучше работы расчёта.
  • Меньше лимита в полосе — показываем сколько есть, добора нет (добор ближайшими по ошибке был бы тем же отбором по величине ошибки, с другой стороны).

Вторая часть: плитка блока «Точность»

«400 из 400 расчётов с пометкой „уверенность низкая“» заменена на свежий замер 12.09.2026 (--engine full --sample 325 --spread scattered, три пересборки с солями 11/22/33, только чтение):

«52,7 % · сделок — расхождение в пределах ±20 % · по 290 сделкам · замер 12.09.2026»

Оговорки на экране (все три обязательны):

  • замер НЕ point-in-time — прогноз по СЕГОДНЯШНИМ активным объявлениям против ПРОШЛЫХ сделок, дрейф рынка входит в расхождение целиком;
  • разброс по трём пересборкам 46,2-56,6 %, точного значения без диапазона не существует;
  • медианное расхождение того же прогона — 19,1 %, то есть ВЫШЕ, чем 15,3 % из замера 31.08: величины меряют разное и взяты в разные дни, но свежий прогон вышел хуже прежнего, и молчать об этом на странице с двумя датами нельзя.

confidenceLow не удалена — помечена снятой с витрины (прогон 29.08 на кластеризованной, непредставительной выборке, что признано в шапке самого файла) и ждёт решения владельца. priceError (15,3 %) и coverage (84,3 %) не тронуты.

Сторож свежести (backtest-freshness) теперь следит за ОБЕИМИ датами замеров: второе число на странице, которое не сторожит никто, — та же дыра, ради которой сторож и заводился.

Проверки

  • Бэкенд: pytest tests/ -q — 5950 passed, 35 skipped; ruff check app tests — чисто.
  • Фронт: tsc --noEmit — чисто; vitest run — 288 passed (32 файла).
  • Фальсификация №1, фильтр полосы (снят руками, без stash): краснеют 3 теста, ключевой — по значению на реальных строках прода:
    E  AssertionError: на витрину прошла строка вне полосы −5 %..+20 %: подпись обещает полосу, а показывает не её
    E  assert [44, 43, 41] == [44]
    
    (id 41 = +75,71 %, id 43 = −27,87 %, id 44 = +9,85 % — три реальные строки landing_showcase_deals прода.)
  • Фальсификация №2, самопроверка подписи (allWithinBand обезврежен руками, всегда true): краснеют оба новых теста, и красный текст показывает ровно тот дефект, ради которого правка делалась:
    AssertionError: подпись обещает полосу, а в таблице под ней строка вне полосы
    Received: "Разброс показанных строк: медианное расхождение 38,1 % по 2 строкам,
               худшая 75,7 %. Это отобранная полоса расхождения от -5 % до +20 % …"
    
    Обе проверки возвращены, прогоны зелёные.
  • Прод, только чтение: из 20 сегодняшних строк витрины в полосу попадают 8 (40 %); последний прогон — considered=200, eligible=159, written=20. Доля по всем 159 собранным строкам из БД не читается (в таблице лежат только показанные 20), ближайший замер — «доля в полосе −5…+20 % = 35,5 %» из бэктеста 12.09.

После мержа

  1. Перегнать витрину: docker exec tradein-backend python -m app.tasks.landing_showcase_deals. До пересчёта в таблице лежат старые 20 строк (12 вне полосы), и страница — благодаря самопроверке — честно не будет обещать полосу, но и показывать будет набор старого правила.
  2. Задачи нет в расписании (scrape_schedules — строки нет вовсе, запуск ручной). Это отдельная задача, её заводит ревьюер; здесь отмечено, чтобы не потерялось: пока расписания нет, каждая правка полосы на фронте требует ручного пересчёта, а витрина стареет молча.
## Что меняется на странице **Витрина сделок теперь показывает ОТОБРАННУЮ полосу расхождения −5 %…+20 %, а не всю сверку.** Строки вне полосы существуют (на проде сегодня 12 из 20 показанных — от −27,9 % до +75,7 %), и их больше не видно. Чтобы страница от этого не начала врать, полоса названа на ней прямым текстом в четырёх местах: 1. **Правило прогона** (`REJECTION_RULE`, едет в `/showcase` вместе со строками и рендерится под таблицей): > «На витрине — ОТОБРАННАЯ полоса расхождения, а не вся сверка: показаны только сделки, у которых расхождение прогноза с ценой ДКП лежит от -5 % до +20 % включительно. Промахи крупнее полосы в данных есть, и здесь их не видно — судить по этим строкам о точности расчёта нельзя, для этого есть медиана расхождения по всей сверке. Внутри полосы порядок задают полнота данных и свежесть квартала: величина отклонения на него не влияет, лучший хвост самой полосы витрина тоже не показывает. Кроме полосы строку снимает только отсутствие данных: …» Прежняя формулировка — «Величина отклонения на отбор и отбраковку не влияет — иначе витрина показывала бы лучший хвост, а не работу расчёта» — после фильтра стала ложью ровно про то, чего опасалась. Снята, а не смягчена. 2. **Подпись под таблицей сверок** (`AccuracyV3`): > «Разброс показанных строк: медианное расхождение 6,1 % по 8 строкам, худшая 10,6 %. **Это отобранная полоса расхождения от -5 % до +20 %, а не вся сверка: промахи крупнее полосы в данных есть, здесь их не видно.** Медиана по всей сверке — 15,3 % (325 сделок).» 3. **Подпись бегущей строки** (`DealsTickerV3`) — она висит над первым экраном, её числа читают раньше любых оговорок: > «Показаны сделки с расхождением от -5 % до +20 % — отобранная полоса, не вся сверка. Медиана показанных строк — 6,1 %, худшая — 10,6 %» 4. **Счётчики прогона** — подпись поправлена, потому что они разъехались со смыслом: `eligible − written` больше не значит «столько не поместилось», в разницу входят отсеянные полосой. Было «Показано 20 строк из 159 годных», стало **«Показано 8 строк из 159 собранных прогоном»**. ## Утверждение про полосу проверяет само себя (правка по ревью, коммит `db47fa0e`) Ревьюер нашёл дыру в ВЫКАТЕ до мержа. Границы полосы стоят в коде фронта, а строки и `rejection_rule` приезжают из БД от последнего прогона задачи — **задачи нет в расписании, её запускают руками**. В окне «фронт выкачен, витрина не пересчитана» страница утверждала бы полосу над прежними двадцатью строками и тут же показывала под утверждением +75,7 %. Это хуже, чем было до правки. Чинится конструкцией: `allWithinBand(deals)` в `deal-view.ts` спрашивает сами показанные строки теми же границами, что стоят в тексте. * все показанные строки в полосе → печатается формулировка про полосу (см. выше); * хоть одна вне → про полосу **не утверждается ничего**. Таблица: «Полосу расхождения от -5 % до +20 % эта подпись не обещает: среди показанных строк есть расхождения вне неё, то есть витрину собрал прогон с другим правилом — тем, что напечатано выше». Правило того прогона приезжает из ТОГО ЖЕ прогона, что и строки, поэтому подпись с ними согласована по построению. Лента печатает только посчитанное по строкам: «Медиана расхождения показанных строк — 11,5 %, худшая — 75,7 %». * Медиана по ВСЕЙ сверке печатается в ОБЕИХ ветках — она и удерживает страницу честной независимо от того, пересчитана витрина. Отрендерено и прочитано глазами в обоих состояниях, на реальных двадцати `err_pct` прода: ``` ТАБЛИЦА — ДО ПЕРЕСЧЁТА Разброс показанных строк: медианное расхождение 11,5 % по 20 строкам, худшая 75,7 %. Полосу расхождения от -5 % до +20 % эта подпись не обещает: среди показанных строк есть расхождения вне неё, то есть витрину собрал прогон с другим правилом — тем, что напечатано выше. Медиана по всей сверке — 15,3 % (325 сделок). ЛЕНТА — ДО ПЕРЕСЧЁТА Медиана расхождения показанных строк — 11,5 %, худшая — 75,7 % ТАБЛИЦА — ПОСЛЕ ПЕРЕСЧЁТА Разброс показанных строк: медианное расхождение 6,1 % по 8 строкам, худшая 10,6 %. Это отобранная полоса расхождения от -5 % до +20 %, а не вся сверка: промахи крупнее полосы в данных есть, здесь их не видно. Медиана по всей сверке — 15,3 % (325 сделок). ЛЕНТА — ПОСЛЕ ПЕРЕСЧЁТА Показаны сделки с расхождением от -5 % до +20 % — отобранная полоса, не вся сверка. Медиана показанных строк — 6,1 %, худшая — 10,6 % ``` ## Решения, которые стоит отревьюить * **Фильтр в `select_rows`, а не в `build_row`.** Строка вне полосы обязана остаться кандидатом и попасть в `eligible`: отбракуй её раньше — и вышло бы «показано 20 из 20 годных», счётчик, из которого отбор не виден вообще. * **Границы полосы подставляются в текст правила** из `BAND_MIN_ERR_PCT`/`BAND_MAX_ERR_PCT`. Вписанный руками «−5 %» в подписи и `>= -5.0` в коде — две независимые величины; тест `test_rejection_rule_names_the_band_that_is_actually_applied` держит их вместе. * **«В пределах 20 % — N из N» из подписи снято.** При потолке полосы +20 у каждой показанной строки |отклонение| ≤ 20 по построению: счёт всегда выходил бы «8 из 8» и читался бы как замер попадания. Неработающая проверка читается как работающая — то же правило, по которому из продюсера когда-то убрали мёртвый `MAX_FACT_PPM2`. * **Медиана по всей сверке (15,3 %, 325 сделок) осталась в подписи и сторожится тестом.** Это то, что удерживает страницу честной: разброс отобранной двадцатки по построению лучше работы расчёта. * Меньше лимита в полосе — показываем сколько есть, добора нет (добор ближайшими по ошибке был бы тем же отбором по величине ошибки, с другой стороны). ## Вторая часть: плитка блока «Точность» «400 из 400 расчётов с пометкой „уверенность низкая“» заменена на свежий замер 12.09.2026 (`--engine full --sample 325 --spread scattered`, три пересборки с солями 11/22/33, только чтение): **«52,7 % · сделок — расхождение в пределах ±20 % · по 290 сделкам · замер 12.09.2026»** Оговорки на экране (все три обязательны): * замер НЕ point-in-time — прогноз по СЕГОДНЯШНИМ активным объявлениям против ПРОШЛЫХ сделок, дрейф рынка входит в расхождение целиком; * разброс по трём пересборкам 46,2-56,6 %, точного значения без диапазона не существует; * **медианное расхождение того же прогона — 19,1 %, то есть ВЫШЕ, чем 15,3 % из замера 31.08**: величины меряют разное и взяты в разные дни, но свежий прогон вышел хуже прежнего, и молчать об этом на странице с двумя датами нельзя. `confidenceLow` **не удалена** — помечена снятой с витрины (прогон 29.08 на кластеризованной, непредставительной выборке, что признано в шапке самого файла) и ждёт решения владельца. `priceError` (15,3 %) и `coverage` (84,3 %) не тронуты. Сторож свежести (`backtest-freshness`) теперь следит за ОБЕИМИ датами замеров: второе число на странице, которое не сторожит никто, — та же дыра, ради которой сторож и заводился. ## Проверки * Бэкенд: `pytest tests/ -q` — 5950 passed, 35 skipped; `ruff check app tests` — чисто. * Фронт: `tsc --noEmit` — чисто; `vitest run` — 288 passed (32 файла). * **Фальсификация №1, фильтр полосы** (снят руками, без stash): краснеют 3 теста, ключевой — по значению на реальных строках прода: ``` E AssertionError: на витрину прошла строка вне полосы −5 %..+20 %: подпись обещает полосу, а показывает не её E assert [44, 43, 41] == [44] ``` (id 41 = +75,71 %, id 43 = −27,87 %, id 44 = +9,85 % — три реальные строки `landing_showcase_deals` прода.) * **Фальсификация №2, самопроверка подписи** (`allWithinBand` обезврежен руками, всегда true): краснеют оба новых теста, и красный текст показывает ровно тот дефект, ради которого правка делалась: ``` AssertionError: подпись обещает полосу, а в таблице под ней строка вне полосы Received: "Разброс показанных строк: медианное расхождение 38,1 % по 2 строкам, худшая 75,7 %. Это отобранная полоса расхождения от -5 % до +20 % …" ``` Обе проверки возвращены, прогоны зелёные. * Прод, только чтение: из 20 сегодняшних строк витрины в полосу попадают **8 (40 %)**; последний прогон — considered=200, eligible=159, written=20. Доля по всем 159 собранным строкам из БД не читается (в таблице лежат только показанные 20), ближайший замер — «доля в полосе −5…+20 % = 35,5 %» из бэктеста 12.09. ## После мержа 1. **Перегнать витрину:** `docker exec tradein-backend python -m app.tasks.landing_showcase_deals`. До пересчёта в таблице лежат старые 20 строк (12 вне полосы), и страница — благодаря самопроверке — честно не будет обещать полосу, но и показывать будет набор старого правила. 2. **Задачи нет в расписании** (`scrape_schedules` — строки нет вовсе, запуск ручной). Это отдельная задача, её заводит ревьюер; здесь отмечено, чтобы не потерялось: пока расписания нет, каждая правка полосы на фронте требует ручного пересчёта, а витрина стареет молча.
bot-backend added 1 commit 2026-09-12 10:30:23 +00:00
feat(mera/лендинг): витрина показывает полосу расхождения −5…+20 %, плитку уверенности сменил замер 12.09
All checks were successful
CI Trade-In / changes (pull_request) Successful in 10s
CI Trade-In / browser-tests (pull_request) Has been skipped
CI / changes (pull_request) Successful in 12s
CI / backend-tests (pull_request) Has been skipped
CI / frontend-tests (pull_request) Has been skipped
CI / openapi-codegen-check (pull_request) Has been skipped
CI Trade-In / frontend-checks (pull_request) Successful in 1m13s
CI Trade-In / backend-tests (pull_request) Successful in 5m29s
2467943200
Владелец просит на витрине только сделки, где прогноз разошёлся с ценой ДКП
в пределах от −5 % до +20 %. Фильтр живёт в продюсере (`select_rows`), поэтому
таблица сверок и бегущая строка берут ОДИН набор, а не два.

Чтобы страница от этого не начала врать:

* `REJECTION_RULE` переписан. Прежняя формулировка («величина отклонения на
  отбор и отбраковку не влияет — иначе витрина показывала бы лучший хвост»)
  после фильтра стала ложью ровно про то, чего опасалась, поэтому снята, а не
  смягчена. Новая называет полосу и говорит, что это отбор показательных
  строк, а не вся сверка. Границы в текст ПОДСТАВЛЯЮТСЯ из констант
  `BAND_MIN_ERR_PCT`/`BAND_MAX_ERR_PCT` — подпись не может разъехаться с
  фильтром, и это проверяется тестом.
* Фильтр стоит в `select_rows`, а не в `build_row`: строка вне полосы остаётся
  кандидатом и попадает в `eligible`. Отбраковав её раньше, мы получили бы
  «показано 20 из 20 годных» — счётчик, из которого отбор не виден вообще.
* Счётчики разъехались с подписью, и подпись поправлена: `eligible − written`
  больше не значит «столько не поместилось», в разницу входят отсеянные
  полосой. Под таблицей теперь «показано N строк из M собранных прогоном».
* «В пределах 20 % — N из N» из подписи снято: при потолке полосы +20 счёт
  всегда выходил бы N из N и читался бы как замер попадания. Неработающая
  проверка читается как работающая.
* Медиана по ВСЕЙ сверке (15,3 %, 325 сделок) в подписи осталась и теперь
  сторожится тестом: без неё разброс отобранной двадцатки читается как
  точность расчёта.
* Полоса названа и в подписи ленты — она висит над первым экраном, её числа
  читают раньше любых оговорок блока «Точность».
* Меньше лимита в полосе — показываем сколько есть, добора нет.

Плитка «400 из 400 расчётов с пометкой „уверенность низкая“» заменена на
свежий замер 12.09.2026 (engine=full, 290 сделок, медиана трёх пересборок с
солями 11/22/33): «52,7 % сделок — расхождение в пределах ±20 %». Запись
`confidenceLow` не удалена, а помечена снятой (прогон 29.08 на
кластеризованной выборке) — до решения владельца.

Оговорки новой величины называют три вещи, без которых она льстит: замер не
point-in-time, разброс пересборок 46,2–56,6 %, и что медианное расхождение
того же прогона (19,1 %) ВЫШЕ прежних 15,3 % от 31.08 — на странице два числа
разных дат, и молчать о том, что свежий прогон вышел хуже, нельзя.

`priceError` и `coverage` не тронуты. Сторож свежести теперь следит за ОБЕИМИ
датами замеров, а не только за 31.08.

Проверено: на проде из 20 сегодняшних строк витрины в полосу попадают 8
(40 %), что сходится с 35,5 % «доли в полосе» из бэктеста 12.09.
Фальсификация: снятие фильтра руками красит 3 теста, ключевой — по значению
([44, 43, 41] вместо [44] на реальных строках прода +75,7 / −27,9 / +9,9 %).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Light1YT added 1 commit 2026-09-12 10:44:36 +00:00
fix(mera/лендинг): утверждение про полосу проверяет само себя по показанным строкам
All checks were successful
CI Trade-In / changes (pull_request) Successful in 12s
CI / changes (pull_request) Successful in 15s
CI Trade-In / browser-tests (pull_request) Has been skipped
CI / backend-tests (pull_request) Has been skipped
CI / frontend-tests (pull_request) Has been skipped
CI / openapi-codegen-check (pull_request) Has been skipped
CI Trade-In / frontend-checks (pull_request) Successful in 1m48s
CI Trade-In / backend-tests (pull_request) Successful in 6m0s
db47fa0ecd
Дыра в выкате, найденная ревьюером до мержа. Подпись про полосу собиралась из
констант `BAND_MIN_PCT`/`BAND_MAX_PCT` в коде фронта, а строки витрины и
`rejection_rule` приезжают из БД, от ПОСЛЕДНЕГО прогона задачи
`landing_showcase_deals`. Задачи нет в расписании — её запускают руками.

Значит в окне «фронт выкачен, витрина не пересчитана» страница утверждала бы
«показаны сделки с расхождением от −5 % до +20 %», а под утверждением лежали
бы прежние двадцать строк: по замеру на проде 12 из 20 вне полосы, худшая
+75,7 %. Утверждение и его опровержение в одном экране — хуже, чем было до
правки.

Чинится конструкцией, а не запуском задачи: `allWithinBand(deals)` в
`deal-view.ts` спрашивает САМИ показанные строки теми же границами, что стоят
в тексте.

* Все показанные строки в полосе — печатаем прежнюю формулировку.
* Хоть одна вне — про полосу НЕ утверждаем. В таблице: «Полосу расхождения от
  -5 % до +20 % эта подпись не обещает: среди показанных строк есть
  расхождения вне неё, то есть витрину собрал прогон с другим правилом — тем,
  что напечатано выше». Правило того прогона и так приезжает в
  `rejection_rule` из ТОГО ЖЕ прогона, что и строки, поэтому подпись с ними
  согласована по построению. В ленте остаётся только то, что посчитано по
  строкам: медиана и худшая.
* Медиана по ВСЕЙ сверке (15,3 %, 325 сделок) печатается в обеих ветках — она
  и удерживает страницу честной независимо от того, пересчитана витрина.

Тесты по значению в обе стороны: набор с одной строкой вне полосы (+75,71 % —
реальная строка прода) → утверждения про полосу нет; все в полосе → есть.
Фальсификация: `allWithinBand` обезврежен руками (всегда true) — краснеют оба
новых теста, и красный текст показывает ровно тот дефект:
«Это отобранная полоса расхождения от -5 % до +20 % … худшая 75,7 %».
Проверка возвращена.

Проверка заодно поймала мои же фикстуры ленты: −11,5 % ниже нижней границы
полосы (−5 %), то есть «маленькое отклонение» ещё не значит «в полосе».
Значения заменены на внутриполосные.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
bot-backend merged commit 42daf8404f into main 2026-09-12 10:51:50 +00:00
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
2 participants
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference: lekss361/gendesign#3468
No description provided.