Commit graph

3279 commits

Author SHA1 Message Date
bot-backend
5c10aee4c2 fix(tradein/avito): browser-путь добора не смотрел на HTTP-статус — отказ площадки уходил в ошибку парсинга (#3297)
All checks were successful
CI Trade-In / changes (pull_request) Successful in 9s
CI Trade-In / frontend-checks (pull_request) Has been skipped
CI / openapi-codegen-check (pull_request) Has been skipped
CI Trade-In / backend-tests (pull_request) Successful in 5m4s
CI Trade-In / browser-tests (pull_request) Has been skipped
CI / changes (pull_request) Successful in 11s
CI / backend-tests (pull_request) Has been skipped
CI / frontend-tests (pull_request) Has been skipped
Замер прода 31.08.2026 (24 попытки через 3 узла) поймал три отказа, которые
доезжали до parse_detail_html и падали ValueError("Cannot extract item_id"):
страница 8172 байта, статус 439, title «Доска объявлений от частных лиц и
компаний на Авито». Отказ ПЛОЩАДКИ записывался generic-ошибкой разбора, узел
не ротировался и не банился, брейкер по доле его не видел.

Две независимые дыры, обе в browser-ветке fetch_detail:

1. last_response_status не читался вовсе. Curl-ветка того же файла статус
   проверяет (`if sc in (403, 439) or is_firewall`), browser-ветка смотрела
   только на HTML. Прод ходит именно browser-путём.

2. Маркер витрины-заглушки протух: искали «объявления на сайте авито», а
   фактический title — «доска объявлений от частных лиц и компаний на авито»,
   подстрока в нём не встречается.

Правка:

- новые константы _AVITO_DETAIL_BROWSER_BLOCK_STATUSES = {403, 439} и
  _AVITO_DETAIL_BROWSER_RATELIMIT_STATUS = 429, источник каждого статуса
  назван комментарием;
- проверка стоит ПОСЛЕ _is_detail_not_found (404 остаётся
  AvitoListingGoneError) и ДО parse_detail_html;
- статус None (сайдкар старой версии, goto без статуса) отказом НЕ считается —
  поведение прежнее, фолбэк на html-эвристики;
- 429 разведён с блокирующими статусами и поднимает AvitoRateLimitedError.
  Разница не косметическая: на AvitoBlockedError оркестратор один раз за прогон
  зовёт request_context_reset (#3251) и выбрасывает пройденный QRATOR-PoW. При
  rate-limit контекст цел, сбрасывать его — значит проходить проверку заново с
  того же IP. Зеркалит curl-ветку, где 429 тоже не блок;
- старый title-маркер не удалён, а дополнен снятым вживую: площадка может
  отдавать обе формы.

Тесты (9): каждый статус по отдельности, None-статус не ломает разбор и не
подавляет html-эвристики, 404 побеждает блокирующий статус (порядок проверок),
оба title-маркера опознаются, 429 не является AvitoBlockedError.

Фальсификация: без правки detail.py 5 из 9 новых тестов падают.
Прогон: 397 passed, 1 skipped (-k "avito or cadence or scheduler"), ruff чист.

Замер намеренно жёстче прода (без прогрева сессии и органического перехода из
выдачи), поэтому доля таких отказов в проде из него НЕ следует — её покажет
счётчик после правки.
2026-08-31 14:16:47 +03:00
c4fcedda9a Merge pull request 'лендинг: типографский ритм и мобильные отступы — подача без новых обещаний' (#3292) from feat/mera-landing-attractiveness into main
All checks were successful
Deploy Trade-In / changes (push) Successful in 13s
Deploy Trade-In / test (push) Has been skipped
Deploy Trade-In / build-browser (push) Has been skipped
Deploy Trade-In / build-backend (push) Has been skipped
Deploy Trade-In / build-frontend (push) Successful in 2m4s
Deploy Trade-In / deploy (push) Successful in 59s
Deploy Trade-In / deploy-status (push) Successful in 1s
Deploy Trade-In / perimeter-smoke (push) Successful in 11s
2026-08-31 09:32:59 +00:00
2274c82b7d Merge branch 'main' into feat/mera-landing-attractiveness
All checks were successful
CI Trade-In / changes (pull_request) Successful in 10s
CI Trade-In / backend-tests (pull_request) Has been skipped
CI Trade-In / browser-tests (pull_request) Has been skipped
CI / changes (pull_request) Successful in 14s
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 1m9s
2026-08-31 09:30:58 +00:00
41d0d84075 Merge pull request 'первый экран: оговорки вынесены из блока преимуществ' (#3293) from feat/mera-hero-separate-caveats into main
Some checks failed
Deploy Trade-In / deploy (push) Blocked by required conditions
Deploy Trade-In / changes (push) Successful in 18s
Deploy Trade-In / test (push) Has been skipped
Deploy Trade-In / perimeter-smoke (push) Blocked by required conditions
Deploy Trade-In / deploy-status (push) Blocked by required conditions
Deploy Trade-In / build-browser (push) Has been skipped
Deploy Trade-In / build-backend (push) Has been skipped
Deploy Trade-In / build-frontend (push) Has been cancelled
2026-08-31 09:30:51 +00:00
d3b0d0bea5 Merge branch 'main' into feat/mera-hero-separate-caveats
All checks were successful
CI Trade-In / changes (pull_request) Successful in 10s
CI Trade-In / backend-tests (pull_request) Has been skipped
CI Trade-In / browser-tests (pull_request) Has been skipped
CI Trade-In / frontend-checks (pull_request) Successful in 1m29s
2026-08-31 09:28:32 +00:00
eded14c3d6 Merge branch 'main' into feat/mera-landing-attractiveness
All checks were successful
CI Trade-In / changes (pull_request) Successful in 11s
CI / changes (pull_request) Successful in 14s
CI Trade-In / backend-tests (pull_request) Has been skipped
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 1m30s
2026-08-31 09:28:24 +00:00
1b7d10179f Merge pull request 'липкая панель прячется, пока герой в кадре' (#3296) from fix/mera-sticky-after-hero into main
Some checks failed
Deploy Trade-In / deploy-status (push) Blocked by required conditions
Deploy Trade-In / deploy (push) Blocked by required conditions
Deploy Trade-In / perimeter-smoke (push) Blocked by required conditions
Deploy Trade-In / changes (push) Successful in 17s
Deploy Trade-In / test (push) Has been skipped
Deploy Trade-In / build-browser (push) Has been skipped
Deploy Trade-In / build-backend (push) Has been skipped
Deploy Trade-In / build-frontend (push) Has been cancelled
2026-08-31 09:28:15 +00:00
e94a9792ce Merge branch 'main' into fix/mera-sticky-after-hero
All checks were successful
CI Trade-In / changes (pull_request) Successful in 8s
CI Trade-In / browser-tests (pull_request) Has been skipped
CI / frontend-tests (pull_request) Has been skipped
CI / openapi-codegen-check (pull_request) Has been skipped
CI / changes (pull_request) Successful in 10s
CI Trade-In / backend-tests (pull_request) Has been skipped
CI / backend-tests (pull_request) Has been skipped
CI Trade-In / frontend-checks (pull_request) Successful in 1m7s
2026-08-31 09:26:41 +00:00
86e6956257 Merge pull request 'лендинг: пятая плитка падала на вторую строку, столбец «Расхождение» читался пустым' (#3290) from fix/mera-kpi-grid-and-table into main
Some checks failed
Deploy Trade-In / perimeter-smoke (push) Blocked by required conditions
Deploy Trade-In / deploy-status (push) Blocked by required conditions
Deploy Trade-In / changes (push) Successful in 14s
Deploy Trade-In / test (push) Has been skipped
Deploy Trade-In / build-browser (push) Has been skipped
Deploy Trade-In / deploy (push) Blocked by required conditions
Deploy Trade-In / build-backend (push) Has been skipped
Deploy Trade-In / build-frontend (push) Has been cancelled
2026-08-31 09:26:34 +00:00
98a1944a86 Merge pull request 'числа лендинга: покрытие 88 % было выше всего диапазона представительных пересборок' (#3295) from fix/mera-honest-coverage-number into main
Some checks failed
Deploy Trade-In / test (push) Blocked by required conditions
Deploy Trade-In / build-backend (push) Blocked by required conditions
Deploy Trade-In / build-frontend (push) Blocked by required conditions
Deploy Trade-In / build-browser (push) Blocked by required conditions
Deploy Trade-In / deploy (push) Blocked by required conditions
Deploy Trade-In / perimeter-smoke (push) Blocked by required conditions
Deploy Trade-In / deploy-status (push) Blocked by required conditions
Deploy Trade-In / changes (push) Has been cancelled
2026-08-31 09:26:28 +00:00
b277b1f678 Merge branch 'main' into fix/mera-sticky-after-hero
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 11s
CI / backend-tests (pull_request) Has been skipped
CI Trade-In / 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 1m7s
2026-08-31 09:24:43 +00:00
3f57171f63 Merge branch 'main' into fix/mera-kpi-grid-and-table
All checks were successful
CI Trade-In / browser-tests (pull_request) Has been skipped
CI / backend-tests (pull_request) Has been skipped
CI / openapi-codegen-check (pull_request) Has been skipped
CI Trade-In / frontend-checks (pull_request) Successful in 1m8s
CI Trade-In / changes (pull_request) Successful in 9s
CI Trade-In / backend-tests (pull_request) Has been skipped
CI / changes (pull_request) Successful in 11s
CI / frontend-tests (pull_request) Has been skipped
2026-08-31 09:24:37 +00:00
44e7d4b63a Merge branch 'main' into fix/mera-honest-coverage-number
All checks were successful
CI Trade-In / changes (pull_request) Successful in 17s
CI / changes (pull_request) Successful in 16s
CI Trade-In / backend-tests (pull_request) Has been skipped
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 1m26s
2026-08-31 09:15:06 +00:00
f7d428c0c5 Merge pull request 'витрина: строка без улицы больше не открывает страницу и игру' (#3291) from fix/mera-showcase-order-street into main
All checks were successful
Deploy Trade-In / changes (push) Successful in 22s
Deploy Trade-In / build-browser (push) Successful in 41s
Deploy Trade-In / build-frontend (push) Successful in 2m41s
Deploy Trade-In / test (push) Successful in 4m22s
Deploy Trade-In / build-backend (push) Successful in 1m7s
Deploy Trade-In / deploy (push) Successful in 1m53s
Deploy Trade-In / deploy-status (push) Successful in 1s
Deploy Trade-In / perimeter-smoke (push) Successful in 12s
2026-08-31 09:14:48 +00:00
d20b844561 Merge pull request 'бэктест: выборка вразброс — ORDER BY id DESC садится на несколько улиц' (#3289) from feat/backtest-scattered-sampling into main
Some checks failed
Deploy Trade-In / test (push) Blocked by required conditions
Deploy Trade-In / build-backend (push) Blocked by required conditions
Deploy Trade-In / build-frontend (push) Blocked by required conditions
Deploy Trade-In / build-browser (push) Blocked by required conditions
Deploy Trade-In / deploy (push) Blocked by required conditions
Deploy Trade-In / perimeter-smoke (push) Blocked by required conditions
Deploy Trade-In / deploy-status (push) Blocked by required conditions
Deploy Trade-In / changes (push) Has been cancelled
2026-08-31 09:14:40 +00:00
078f102841 Merge pull request '«Для бизнеса» вела на форму входа — заведена страница /business' (#3294) from feat/mera-business-page into main
Some checks failed
Deploy Trade-In / test (push) Blocked by required conditions
Deploy Trade-In / build-backend (push) Blocked by required conditions
Deploy Trade-In / build-frontend (push) Blocked by required conditions
Deploy Trade-In / build-browser (push) Blocked by required conditions
Deploy Trade-In / deploy (push) Blocked by required conditions
Deploy Trade-In / perimeter-smoke (push) Blocked by required conditions
Deploy Trade-In / deploy-status (push) Blocked by required conditions
Deploy Trade-In / changes (push) Has been cancelled
Deploy Infra Host / sync-infra-host (push) Successful in 10s
Deploy / changes (push) Successful in 14s
perimeter-smoke-mera / smoke (push) Failing after 16s
Deploy / deploy-caddy (push) Has been skipped
Deploy / build-worker (push) Successful in 52s
Deploy / build-frontend (push) Successful in 53s
Deploy / build-backend (push) Successful in 54s
Deploy / deploy (push) Successful in 1m23s
Deploy / deploy-status (push) Successful in 2s
Deploy / perimeter-smoke (push) Failing after 13s
2026-08-31 09:14:34 +00:00
47df1a9020 липкая панель прячется, пока герой в кадре
All checks were successful
CI / backend-tests (pull_request) Has been skipped
CI Trade-In / changes (pull_request) Successful in 10s
CI Trade-In / backend-tests (pull_request) Has been skipped
CI / changes (pull_request) Successful in 12s
CI Trade-In / browser-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 1m37s
Владелец увидел на первом экране, что полоса «Проверить квартиру» лежит поверх
абзаца «Мы называем реальную цену вашей квартиры».

.barSpacer это НЕ лечит и не может: он добавляет высоту в КОНЕЦ документа, а
.barRoot — fixed, то есть накрывает нижние ~67px вьюпорта при ЛЮБОЙ прокрутке,
включая scrollTop=0. Разобравший это агент так и написал и не стал чинить молча.

Пока герой виден, панель не нужна: прямо в нём стоит та же форма проверки, и
полоса дублирует призыв, закрывая текст. Уходит герой — панель появляется.

ПО УМОЛЧАНИЮ ПАНЕЛЬ ВИДИМА. Скрытие включает только клиентский наблюдатель;
если скрипт не выполнился, поведение остаётся ровно сегодняшним. Обратный
порядок (скрыта, показывает скрипт) в тех же условиях убрал бы призыв со
страницы совсем — то есть чинил бы вид ценой работы. Нет секции героя —
наблюдать нечего, панель остаётся видимой, а не пропадает.

Убирается transform-ом, а не display:none: transform идёт на композиторе и не
вызывает перекладку. Страница и так дорога в отрисовке на мобильном (1824 мс в
Style & Layout), и лечение перекрытия не должно стоить пересчёта макета на
каждом пересечении границы героя.

Убранная панель уходит и из дерева доступности (aria-hidden + inert): иначе Tab
уводит в кнопку, которой на экране нет.

Тест проверяет ПОВЕДЕНИЕ, а не наличие класса в файле: наблюдателю скармливается
пересечение. Фальсификация обеих сторон — панель не прячется («expected false to
be true») и панель скрыта по умолчанию («до срабатывания панель видима»).
150 passed, eslint чисто.
2026-08-31 14:13:36 +05:00
da6a6b6e82 Merge pull request 'P1: лендинг отдавался без витрины — имя сервиса двоится между продуктами' (#3282) from fix/mera-ambiguous-service-names into main
Some checks failed
Deploy Trade-In / build-backend (push) Blocked by required conditions
Deploy Trade-In / deploy (push) Blocked by required conditions
Deploy Trade-In / perimeter-smoke (push) Blocked by required conditions
Deploy Trade-In / deploy-status (push) Blocked by required conditions
Deploy Trade-In / changes (push) Successful in 14s
Deploy Trade-In / build-browser (push) Successful in 43s
Deploy Trade-In / build-frontend (push) Successful in 2m29s
Deploy Trade-In / test (push) Has been cancelled
2026-08-31 09:10:09 +00:00
c4beee29ff для бизнеса: убраны обещания, которых нет в контуре; гейт чисел накрыл подстраницы
All checks were successful
CI Trade-In / changes (pull_request) Successful in 10s
CI / changes (pull_request) Successful in 10s
CI / frontend-tests (pull_request) Has been skipped
CI / openapi-codegen-check (pull_request) Has been skipped
CI Trade-In / backend-tests (pull_request) Has been skipped
CI Trade-In / browser-tests (pull_request) Has been skipped
CI / backend-tests (pull_request) Has been skipped
CI Trade-In / frontend-checks (pull_request) Successful in 1m3s
Снимает два замечания ревью.

1. КОПИЯ ОБЕЩАЛА НЕСУЩЕСТВУЮЩЕЕ. «Расчёты по потоку адресов», «не для одной
сделки, а потоком», «по вашему потоку адресов» — всё это подразумевает
массовую загрузку, которой в контуре нет: ни CSV, ни импорта, ни пакетной
ручки. Проверено grep-ом по src/app/v2.

Что там ЕСТЬ на самом деле и теперь названо: учётные записи команды
(app/api/v1/team.py), история своих расчётов (useEstimateHistory, оверлей
«Предыдущие оценки»), месячный лимит на аккаунт (account_quota_overrides,
monthly_limit/unlimited), выдача доступа вручную.

Это ровно тот дефект, который на этом лендинге выкорчёвывали весь день:
величина или возможность, которой никто не мерил и не делал, в продуктовом
голосе. Новая страница не имеет права начинать заново.

2. ГЕЙТ ЧИСЕЛ НЕ ВИДЕЛ НОВУЮ СТРАНИЦУ. Сканер знал два места: корневой
page.tsx и каталог _components/v3. Публичная /business под него не попадала —
правило держалось на памяти автора. Теперь подстраницы находятся ОБХОДОМ
каталога, а не списком: список — снимок, следующую страницу в него снова
забудут вписать.

Юридические страницы (оферта, политика, возврат, документы) исключены явно и
с обоснованием: они состоят из ссылок на законы («Закон РФ от 07.02.1992
№ 2300-1», «152-ФЗ», «ст. 18.1»), а по форме это те же числа, что и замеры.
Отличить регулярным выражением нельзя, и правило гейта к ним не относится —
там числа цитируются из нормативных актов, а не утверждаются о рынке.
Расширение проверено: включение этих страниц давало 4 ложных срабатывания.

Фальсификация: вписанные в /business «42 700 квартир» роняют гейт по значению
с указанием файла. 150 passed, tsc и eslint чисто.
2026-08-31 13:02:45 +05:00
79ae87019a бэктест: подписи окна приведены к замеру, уверенность — к тому же прогону
All checks were successful
CI Trade-In / changes (pull_request) Successful in 12s
CI Trade-In / backend-tests (pull_request) Has been skipped
CI / changes (pull_request) Successful in 14s
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 1m21s
Снимает три блокера ревью на этой же ветке.

1. ПОДПИСЬ ОКНА. Числа перевели на представительную выборку, а подпись
осталась от прежнего прогона: «сделки II квартала 2026 года». Автор честно
записал, что квартальный состав пересборки не смотрел, и оставил критерий
снятия — посчитать deal_date по выборке. Посчитал:

    III кв 2025 — 106 (26,5 %)      I кв 2026 — 88 (22,0 %)
    IV кв 2025  — 110 (27,5 %)     II кв 2026 — 96 (24,0 %)

Пересборка покрывает ЧЕТЫРЕ квартала, II квартал 2026 — четверть её. Прежняя
подпись для этих чисел была бы прямым враньём.

2. ЗНАМЕНАТЕЛЬ. Был 5 954 — сделки только II квартала. Для выборки по четырём
кварталам это завышало долю вчетверо: 5,5 % вместо 1,3 %. Замер тем же
фильтром, что у выборки: в окне 24 333, из них II квартал 2026 — 5 954. Оба
числа одним запросом.

3. УВЕРЕННОСТЬ. Плитка «325 из 327» была из прогона 29.08, а лид секции печатал
«замер 31.08» — старому числу приписывалась новая дата, и 325 в лиде совпадало
с 325 в плитке, читаясь как одна выборка. Заменено на «400 из 400» из ТОЙ ЖЕ
пересборки. Знаменатель 400 — запрошенные сделки, а не 325 сматчившихся:
уверенность считается на каждой оценке.

4. Оговорка уверенности не выводилась вовсе: AccuracyV3 собирал оговорки двух
величин из трёх. Плитка стояла без единого слова о том, почему уверенность
низкая. Добавлена третья.

Тесты проверены фальсификацией: возврат знаменатели одного квартала даёт
«expected 5954 to be 24333» и «expected 5.458 to be less than 2»; снятие
оговорки из вывода — «оговорка не выводится». 157 passed.
2026-08-31 12:59:27 +05:00
2864d80854 fix(mera-public): честные числа бэктеста — медиана трёх представительных пересборок
Покрытие 88 % и расхождение 14,5 % получались только на кластеризованной
выборке (ORDER BY id DESC: 20 строк на четыре улицы). Замер 31.08.2026 тремя
представительными пересборками (engine=full, ЕКБ, три соли) дал покрытие
82,77/84,31/86,02 % и MAPE 14,66/15,28/15,66 %: опубликованные 88 % лежат ВЫШЕ
всего диапазона, то есть недостижимы, а 14,5 % — чуть ниже, тот же
благоприятный край.

- BACKTEST.coverage 88 % -> 84,3 %, priceError 14,5 % -> 15,3 % (медианы),
  sampleN 327 -> 325 (медианная пересборка);
- в оговорки добавлен сам диапазон пересборок (82,8-86,0 % и 14,7-15,7 %):
  точечное значение без него обещает точность, которой у замера нет;
- BACKTEST_SOURCE переписан — представительная выборка, а не последние
  загруженные строки; дата замера 29.08 -> 31.08.2026;
- confidenceLow («325 из 327») на пересборках НЕ пересчитывался: у него
  отдельный источник с прежней датой и оговорка про свой знаменатель;
- квартальный состав представительной выборки не проверен — записан
  дословно, с критерием снятия, рядом с BACKTEST_PERIOD_LABEL.

Тест: backtest-freshness проверяет наличие диапазона в оговорках (+контроль на
инструмент) и что AccuracyV3/HeroV3 не содержат самих величин; render-тест
перестал сверяться с вписанным «14,5 %» и берёт значение из landing-facts.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-31 12:41:32 +05:00
4d51d19f7c feat(mera-public): публичная страница /business вместо ссылки на форму входа
Кнопка «Для бизнеса» в шапке и «МЕРА для бизнеса» в подвале вели на B2B_URL.
Реальная цепочка на проде: 308 → /trade-in → 307 → /trade-in/v2 → клиентский
редирект → /trade-in/login. Посетитель публичного сайта упирался в форму
«Логин / Пароль» от аккаунта, которого у него нет.

Заведена страница /business: кому полезен бизнес-контур, чем он отличается от
бесплатной проверки, и как связаться (почта и телеграм — те же константы, что
в подвале и в документах, не выдуманные для страницы). Ни цен, ни сроков, ни
объёмов: этих величин никто не мерил. Ссылка на вход оставлена внутри страницы
второстепенной — «уже работаете с нами».

Периметр согласован во всех четырёх местах: PUBLIC_ROUTES, три матчера Caddy
(@meraPages, @meraShortSlash, @meraLongPages), PUBLIC_SHORT_PATHS в RouteGuard,
плюс строка в smoke-mera-perimeter.sh. Гейт периметра проверен фальсификацией:
удаление /business из @meraShortSlash роняет public-perimeter.test.ts.

noindex — тем же способом, что у /docs (metadata.robots).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-31 12:40:59 +05:00
c9251d3ed5 первый экран: оговорки вынесены из блока преимуществ
All checks were successful
CI Trade-In / changes (pull_request) Successful in 10s
CI Trade-In / backend-tests (pull_request) Has been skipped
CI / changes (pull_request) Successful in 10s
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 1m0s
Владелец попросил сделать лендинг привлекательнее. Один скриншот мобильной
страницы показал причину, по которой первый экран читается стеной текста:
шесть однотипных пунктов подряд, из которых ДВА про обратное.

«Пример по рынку Екатеринбурга, а не расчёт по вашему адресу» и «По всем
расчётам МЕРЫ, а не только по Екатеринбургу» лежали ВНУТРИ .heroPerks — в том
же контейнере, тем же кеглем, с маркером в том же ряду, что «Бесплатно» и
«За 150 ₽». То есть дисклеймер выглядел как ещё один пункт оффера.

Вынесены в собственный блок за разделителем: тише, мельче, отдельно.

Слова НЕ ТРОНУТЫ. Порядок чтения не тронут: оговорки по-прежнему выше формы,
человек прочитает их до ввода адреса — ровно то требование, ради которого их
туда и ставили. Ширина колонки та же, контраст держит AA. Убирать или прятать
оговорку нельзя: замаскированная оговорка хуже показанной, и вся эта страница
построена на обратном принципе.

Тесты, проверяющие СОДЕРЖИМОЕ обеих строк (что экспозиция и аналоги подписаны
разными границами и не слиты в одну), держатся за parentElement строки, а не
за контейнер — переезд их не задел. 147 passed.
2026-08-31 11:35:02 +05:00
884a6b9cfe бэктест: режим выборки вразброс — ORDER BY id DESC садится на несколько улиц
All checks were successful
CI Trade-In / changes (pull_request) Successful in 8s
CI Trade-In / browser-tests (pull_request) Has been skipped
CI / changes (pull_request) Successful in 11s
CI Trade-In / frontend-checks (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 / backend-tests (pull_request) Successful in 5m12s
ORDER BY id DESC берёт последние ВСТАВЛЕННЫЕ строки, а Росреестр грузится
пачками по домам: соседние id это один дом и одна улица. Замер на проде
31.08.2026 по Екатеринбургу, выборка 200:

    последние 200 по id : 38 разных улиц, до 22 сделок с ОДНОЙ улицы
    случайные 200       : 129 разных улиц, максимум 6 с одной

На этой выборке стоит витрина лэндинга: 20 строк с ЧЕТЫРЁХ улиц, 16 из них с
двух. Владелец заметил это как «почти все сделки из одного района».

ЧТО ЗАМЕР ПОКАЗАЛ, а что нет. Пять прогонов по 200 сделок:

    recent            MAPE 15.18%  покрытие 88.75%
    scattered mera    MAPE 14.96%  покрытие 83.13%
    scattered alpha   MAPE 15.97%  покрытие 88.34%
    scattered bravo   MAPE 13.69%  покрытие 83.85%
    scattered charlie MAPE 14.36%  покрытие 86.23%

Заголовочная точность УСТОЯЛА — опубликованные 14,5% лежат внутри разброса
представительной выборки. Кластеризация её не раздувала.

А покрытие коридором опубликовано как 88% — это верх диапазона: при пересборке
выборки величина гуляет 83-88 при медиане около 86. Публикуется лучший прогон
из пяти как единственный. Правка самих чисел лэндинга — отдельным заходом.

УМОЛЧАНИЕ НЕ ТРОНУТО. Докстринг _sample_sql обещает дефолтному пути побайтово
тот же SQL ради замороженного регресс-гейта; смена умолчания молча обнулила бы
сравнимость всей истории замеров. Режим выбирается флагом --spread.

Порядок по md5(id||seed), а не random(): нужен ВОСПРОИЗВОДИМЫЙ порядок, иначе
два прогона отличаются и из-за правки, и из-за состава выборки, и разделить
вклады нечем.

Тест держит обе стороны и проверен фальсификацией: сделать вразброс умолчанием
— падает identity-проверка (сравнение текстов её бы пропустило), заменить md5
на random() — падает проверка воспроизводимости.
2026-08-31 11:28:11 +05:00
2527068c45 подача лендинга: мобильный ритм, ровные заголовки, табличные цифры
All checks were successful
CI Trade-In / changes (pull_request) Successful in 13s
CI Trade-In / backend-tests (pull_request) Has been skipped
CI Trade-In / browser-tests (pull_request) Has been skipped
CI / changes (pull_request) Successful in 15s
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 1m15s
Только оформление: ни одного утверждения, числа или секции не тронуто.

- text-wrap: balance на заголовках секций — на 375px они уходят в 2-3 строки
  и оставляли висячее слово.
- artTitle подтянут к общему полу 26px (был 24px — последняя секция читалась
  мельче остальных).
- внутренние отступы карточек стали responsive (clamp): на 375px под текст
  оставалось 279px из 375, четверть экрана уходила в поля. На десктопе
  значения прежние.
- font-variant-numeric: tabular-nums на крупных значениях (плитки сверки,
  плитки цены ошибки, отклонение в строке) — разряды встают в колонку.
- «Все статьи» имела высоту нажатия 23px; паддинг гасится отрицательным
  полем, макет не сдвигается. Ховер переведён с нижней границы на
  подчёркивание, иначе линия легла бы по краю паддинга.
2026-08-31 11:24:52 +05:00
28bf3a82d7 fix(mera-public): плитки точности в один ряд, «Расхождение» по одному краю
All checks were successful
CI Trade-In / changes (pull_request) Successful in 9s
CI Trade-In / backend-tests (pull_request) Has been skipped
CI Trade-In / browser-tests (pull_request) Has been skipped
CI / changes (pull_request) Successful in 11s
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 1m21s
Пятая плитка (тёмная, из /stats) не влезала в грид: контейнер 1168px,
minmax(220px) + gap 20px требуют 1180px — плитка падала на вторую строку
одна и узкая, читалось как обрыв вёрстки. Заменил грид на flex-wrap с общим
базисом 200px: пять плиток встают в ряд, четыре — тоже, а на узких ширинах
остаток растягивается на всю строку вместо огрызка слева.

Значения столбца «Расхождение» стояли по левому краю ячейки, а заголовок —
по правому, из-за чего столбец читался пустым. Выровнял значения вправо,
по краю заголовка; на мобильном брейке text-align по-прежнему сбрасывается
в left (карточки с data-label не тронуты).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-31 11:24:11 +05:00
e45b05845e fix(mera-landing): наличие схемы улицы входит в полноту строки витрины
All checks were successful
CI Trade-In / changes (pull_request) Successful in 11s
CI Trade-In / browser-tests (pull_request) Has been skipped
CI / changes (pull_request) Successful in 13s
CI Trade-In / frontend-checks (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 / backend-tests (pull_request) Successful in 5m14s
Первой строкой витрины и первым раундом игры «Проверьте себя» стояла
единственная из двадцати сделка БЕЗ улицы: у неё вместо схемы улиц
рисовался полигон района. Причина — `completeness()` считала район, этаж
и этажность, но не улицу, хотя именно она решает, будет ли у строки карта.

Схема улицы — такое же ВИДИМОЕ поле, как район: строка, которой нечем
нарисовать карту, полнее строки с картой быть не может. Признак берётся
из уже загружаемого индекса улиц (`StreetIndex.lookup`, поиск в памяти);
индекс поднят выше отбора, дорогие пространственные запросы остались в
`_schemes_for` и по-прежнему считаются только для показанных строк.

Отбор по ВЕЛИЧИНЕ ОШИБКИ не введён и введён быть не может: строка
с отклонением +75,7% остаётся в витрине, просто больше не открывает её.
Прежнее правило «наличие схемы на отбор не влияет» в докстринге
`_schemes_for` заменено с разбором, почему оно давало этот дефект.

Тест двусторонний: при прочих равных строка со схемой выше строки без
неё, а строка без улицы остаётся в витрине. Фальсифицирован — снятие
`row.has_street` из `completeness` даёт красное ПО ЗНАЧЕНИЮ ([9, 8]
вместо [8, 9]), не по исключению.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-31 11:22:39 +05:00
189ae63e53 Merge pull request 'fix(tradein/domclick): бан сайдкара наследуется от httpx-ошибки и уезжал в транспортные сбои (#3283)' (#3287) from fix/3283b-sidecar-ban-is-httpx-subclass into main
All checks were successful
Deploy Trade-In / changes (push) Successful in 12s
Deploy Trade-In / build-browser (push) Has been skipped
Deploy Trade-In / deploy (push) Successful in 4m5s
Deploy Trade-In / build-frontend (push) Has been skipped
Deploy Trade-In / test (push) Successful in 4m6s
Deploy Trade-In / build-backend (push) Successful in 1m3s
Deploy Trade-In / deploy-status (push) Successful in 1s
Deploy Trade-In / perimeter-smoke (push) Successful in 11s
2026-08-30 20:25:23 +00:00
bot-backend
1e02badbe9 fix(tradein/domclick): бан сайдкара наследуется от httpx-ошибки и уезжал в транспортные сбои (#3283)
All checks were successful
CI Trade-In / changes (pull_request) Successful in 9s
CI Trade-In / frontend-checks (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 / browser-tests (pull_request) Has been skipped
CI / changes (pull_request) Successful in 11s
CI / backend-tests (pull_request) Has been skipped
CI Trade-In / backend-tests (pull_request) Successful in 5m5s
Правка #3286 разделила отказы площадки и сбои нашей стороны по природе
исключения: httpx-ошибка в цепочке причин = транспорт. Прод показал дыру
на первом же прогоне (5406):

  СБОЙ #1/400 (подряд=1/10, http=401, kind=platform, не блок площадки):
  DomClick detail: sidecar detected platform refusal

Заголовок «не блок площадки» стоит над записью, где kind=platform и код 401,
то есть над самым что ни на есть отказом площадки. Причина в иерархии:
SidecarBanPageError объявлен как подкласс httpx.HTTPStatusError, поэтому
проверка на httpx, стоявшая первой, забирала генуинный бан себе.

Порядок проверок перевёрнут: бан сайдкара отсекается ДО общей httpx-ветки.
Остальное поведение #3286 не тронуто — обычная 500 от сайдкара по-прежнему
транспортный сбой.

Тесты: +4, включая закрепление самой предпосылки (issubclass проверяется
явно, чтобы смена иерархии не отключила проверку молча) и страховку, что
обычная 500 осталась сбоем. Проверено мутацией: снятие порядка роняет тест
и печатает самопротиворечивый лог «10 сбоев подряд без единого отказа
площадки, диагнозы: {'platform': 10}». Набор целиком — 5210 passed.
2026-08-30 17:02:46 +03:00
03d04f13b5 Merge pull request 'fix(tradein/domclick): таймаут сайдкара и пустой пул считались отказами площадки (#3283)' (#3286) from fix/3283-non-blocks-counted-as-blocks into main
All checks were successful
Deploy Trade-In / changes (push) Successful in 14s
Deploy Trade-In / build-frontend (push) Has been skipped
Deploy Trade-In / build-browser (push) Has been skipped
Deploy Trade-In / deploy (push) Successful in 7m33s
Deploy Trade-In / deploy-status (push) Successful in 1s
Deploy Trade-In / test (push) Successful in 4m5s
Deploy Trade-In / build-backend (push) Successful in 1m4s
Deploy Trade-In / perimeter-smoke (push) Successful in 11s
2026-08-30 13:42:10 +00:00
bot-backend
42913d2843 fix(tradein/domclick): таймаут сайдкара и пустой пул считались отказами площадки (#3283)
All checks were successful
CI Trade-In / changes (pull_request) Successful in 8s
CI / changes (pull_request) Successful in 10s
CI Trade-In / browser-tests (pull_request) Has been skipped
CI Trade-In / frontend-checks (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 / backend-tests (pull_request) Successful in 4m56s
Прогон 5399 умер по правилу «3 блока подряд», не обогатив ни одной карточки
из 400. Отказом Домклика не был ни один из трёх: два — HTTP 500 от сайдкара
(таймаут навигации), третий — пустой пул, при котором запрос к площадке не
отправлялся вовсе. Лог абортa сам это печатал: диагнозы {'unknown': 3}.

Различать по HTTP-статусу нельзя: настоящий QRATOR-челлендж приходит без
статуса и неотличим от таймаута — на этом и стояли прежние тесты. Различима
природа исключения, причём разделение уже проведено в fetch_detail: генуинный
бан приезжает через SidecarBanPageError или маркеры в parse_detail_html, а
транспорт — через  с , то есть с
httpx-ошибкой в цепочке причин.

Три правки:
* пустой пул (NoProxyAvailableError в цепочке) — не блок, а остановка прогона:
  продолжать бессмысленно, каждая следующая карточка упрётся в то же. Прогон
  уходит в failed, а не banned — запись не должна утверждать про площадку то,
  чего не было;
* транспортные сбои идут в failed, туда же, куда давно идёт DomClickParseError
  («schema drift, not a block»), и счётчик блоков не трогают;
* отдельный сторож на молчаливый отказ: max_consecutive_soft_failures=10, иначе
  снятие хайртриггера оставило бы прогон без тормоза вовсе.

Тесты: 10 проверок, включая дословный сценарий 5399 и страховку «генуинные
блоки по-прежнему рвут прогон после трёх». Проверено мутациями: возврат пустого
пула в блоки роняет 2, возврат транспорта — 6, снятие сторожа — 2. Четыре
существовавших теста на генуинный блок продолжают проходить без правки — это и
показывает, что разделение проведено по верному признаку. Набор целиком —
5206 passed, 37 skipped.
2026-08-30 16:33:56 +03:00
cb9dc1505a Merge pull request 'feat(tradein/cian): у Циана не было добора карточек — только побочный эффект задачи про историю (#3284)' (#3285) from feat/3284-cian-detail-backfill into main
All checks were successful
Deploy Trade-In / changes (push) Successful in 13s
Deploy Trade-In / build-frontend (push) Has been skipped
Deploy Trade-In / build-browser (push) Has been skipped
Deploy Trade-In / test (push) Successful in 4m10s
Deploy Trade-In / build-backend (push) Successful in 1m6s
Deploy Trade-In / deploy (push) Successful in 2m4s
Deploy Trade-In / deploy-status (push) Successful in 0s
Deploy Trade-In / perimeter-smoke (push) Successful in 12s
2026-08-30 12:41:36 +00:00
bot-backend
5f9dc5d512 feat(tradein/cian): у Циана не было добора карточек — только побочный эффект задачи про историю (#3284)
All checks were successful
CI Trade-In / changes (pull_request) Successful in 10s
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 / browser-tests (pull_request) Has been skipped
CI / changes (pull_request) Successful in 12s
CI Trade-In / frontend-checks (pull_request) Has been skipped
CI Trade-In / backend-tests (pull_request) Successful in 5m2s
Карточки Циана доставались побочным эффектом cian_history_backfill, а её
выборка ключуется по offer_price_history. Следствия на 30.08: карточка есть
у 4494 из 25222 объявлений (17.8% — последнее место при втором месте по
объёму), 19046 без истории при квоте 100/сутки (190 дней на остаток, тогда
как очередь растёт вдвадцатеро быстрее), и 1697 объявлений с историей и без
карточки, которые исторической выборке недостижимы в принципе.

Фетчер при этом исправен: прогоны 5154/5240/5328 дали 100/100, 99/100,
100/100. Чинить нечего — не выдана мощность.

Добавлен второй режим выборки (listings_pending="detail", по
detail_enriched_at, свежие первыми) и второе расписание поверх ТОГО ЖЕ тела:
машинерия работает, дублировать её новым модулем незачем. Историческая
выборка оставлена побайтово — по ней живёт суточный прогон.

batch_size=400 не на глаз: замеренный темп ~28с на объявление, порог
reap_zombies 6ч по heartbeat, бюджетного сторожа у задачи нет — 400×28с≈3.1ч
проходит, 800 как у Яндекса (≈6.2ч) убивало бы жнецом.

Расписание засеяно enabled=false, как domclick_detail_backfill в миграции
175: это третий круглосуточный добор на общий пул из четырёх узлов, влияние
на соседей надо посмотреть, а не предположить.

Тесты: 13 проверок, ключ выборки / порядок / неизменность прежнего режима /
проводка параметров через посредника / регистрация обоих source. Проверено
мутациями: снятие ORDER BY, молчаливый дефолт вместо ValueError и потеря
listings_pending в посреднике роняют по 2-3 теста каждая. Набор целиком —
5196 passed, 37 skipped.
2026-08-30 15:34:36 +03:00
f31cb56081 прод: лендинг ходил в чужой бэкенд — имя сервиса двоится между продуктами
All checks were successful
CI Trade-In / backend-tests (pull_request) Has been skipped
CI Trade-In / browser-tests (pull_request) Has been skipped
CI / changes (pull_request) Successful in 11s
CI Trade-In / frontend-checks (pull_request) Has been skipped
CI / openapi-codegen-check (pull_request) Successful in 2m12s
CI / backend-tests (pull_request) Successful in 17m35s
CI Trade-In / changes (pull_request) Successful in 8s
CI / frontend-tests (pull_request) Successful in 1m11s
Публичный лендинг отдавался БЕЗ витрины: без ленты сделок, без строк сверки
«прогноз против факта», без подписи разброса. Страница про точность — без
единого доказательства. Отдавалось 106 КБ вместо 241 КБ.

Причина. ПТИЦА и МЕРА — разные compose-проекты, но оба назвали свой сервис
backend и оба подключены к общей сети gendesign_shared. Изнутри фронта:

    backend         → 172.18.0.6 (МЕРА) + 172.18.0.9 (ПТИЦА)
    tradein-backend → 172.18.0.6

BACKEND_URL=http://backend:8000 уводил серверный рендер в бэкенд ПТИЦЫ, тот
отвечал 401 no authenticated user, и страница рендерилась пустой.

Отказ тихий вдвойне. fetch не бросает — приходит валидный HTTP-ответ, просто
чужой. И имя двоится, поэтому часть перегенераций попадала в правильный адрес:
утром страница была с данными, к обеду без них, и это выглядело случайной
поломкой, а не ошибкой конфигурации.

DATABASE_URL болен тем же: @postgres:5432 мог уйти в базу ПТИЦЫ. Там спасало
лишь несовпадение кредов — отказ вместо тихого чтения не тех данных. Полагаться
на это нельзя: защита держится на том, что у чужой базы нет пользователя с
нашим паролем. Переведён на однозначное имя во всех трёх сервисах.

Гейт check-compose-ambiguous-hosts.py: пересечение имён сервисов обоих compose
и запрет ссылаться на них как на хост. Селфтест по конвенции соседних гейтов —
он провалился дважды на моих же фикстурах (в них не было общего имени, то есть
ловить было нечего), и это ровно то, ради чего селфтест и нужен.

Фальсификация на настоящем файле: возврат backend:8000 даёт точную строку 479,
возврат @postgres — все четыре ссылки.
2026-08-30 16:07:41 +05:00
999f10e78b Merge pull request 'контраст: 32 → 2 → 0, проверено на живой странице; сторож теперь ловит выбор токена, а не только его значение' (#3281) from fix/mera-contrast-two-leftovers into main
All checks were successful
Deploy Trade-In / deploy (push) Successful in 58s
Deploy Trade-In / deploy-status (push) Successful in 1s
Deploy Trade-In / perimeter-smoke (push) Successful in 10s
Deploy Trade-In / changes (push) Successful in 12s
Deploy Trade-In / test (push) Has been skipped
Deploy Trade-In / build-browser (push) Has been skipped
Deploy Trade-In / build-backend (push) Has been skipped
Deploy Trade-In / build-frontend (push) Successful in 2m1s
2026-08-30 10:54:58 +00:00
3b09368669 контраст: два оставшихся нарушения на живой странице + сторож по секциям
All checks were successful
CI Trade-In / changes (pull_request) Successful in 9s
CI Trade-In / backend-tests (pull_request) Has been skipped
CI / changes (pull_request) Successful in 10s
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 1m0s
Проверка axe-правилом по ОТРЕНДЕРЕННЫМ узлам прода дала 32 → 2. Обе
оставшиеся показательны, и одну из них завёл мой же вчерашний батч.

.tickerNote (3.06) — подпись под тикером. Её добавила одна ветка, токены
чинила другая; каждая по отдельности была права, вместе дали дефект: подпись
взяла --b2c-muted (токен для СВЕТЛОГО фона) и легла на тёмную плашку #121A1D,
где шкала перевёрнута. Красится --b2c-muted-dark, 6.20.

.stepsLabelAccent (4.48) — «ШАГ 3 · 150 ₽» на карточке #EAF5F7. Сторож знал
эту поверхность, но проверял accentDeep только как ЗАЛИВКУ (белый по нему), а
CSS использует его ещё и как ЦВЕТ ТЕКСТА. accentDeep #0C7B8B → #0B7382:
минимальный шаг, проходит текстом на всех трёх светлых поверхностях
(4.99/5.15/5.54) и заодно улучшает главную кнопку — белый по нему 4.97 → 5.54.

Две правки сторожа, обе про механизм, а не про случай:
1. accentDeep проверяется и как текст: токен, используемый двумя способами,
   обязан проверяться обоими.
2. Новый тест «в тёмных секциях не используются светлофоновые токены». Он
   ловит промах в ВЫБОРЕ токена, а не в его значении — тот класс, который и
   прошёл мимо. Список тёмных секций явный, но это снимок СЕКЦИЙ, а не
   нарушений: новое правило внутри известной секции ловится без правки списка.

Фальсификация обеих: возврат accentDeep даёт «4.4775 >= 4.5», возврат
.tickerNote на muted даёт «.tickerNote → --b2c-muted». Первую попытку
фальсификации засчитывать было нельзя — подмена не сработала из-за
добавленного комментария, и тест остался зелёным по построению.
2026-08-30 15:51:25 +05:00
de31f2791b Merge pull request '#3194: ключ шифрования кук и сами куки больше не уезжают в GlitchTip' (#3275) from fix/3194-hide-sql-parameters into main
All checks were successful
Deploy / changes (push) Successful in 9s
Deploy / build-frontend (push) Has been skipped
Deploy / deploy-caddy (push) Has been skipped
Deploy Trade-In / changes (push) Successful in 14s
Deploy Trade-In / build-frontend (push) Has been skipped
Deploy Trade-In / build-browser (push) Has been skipped
Deploy / build-backend (push) Successful in 2m1s
Deploy / build-worker (push) Successful in 3m22s
Deploy Trade-In / test (push) Successful in 4m8s
Deploy / deploy (push) Successful in 1m18s
Deploy / deploy-status (push) Successful in 1s
Deploy / perimeter-smoke (push) Successful in 13s
Deploy Trade-In / build-backend (push) Successful in 1m8s
Deploy Trade-In / deploy (push) Successful in 6m36s
Deploy Trade-In / deploy-status (push) Successful in 1s
Deploy Trade-In / perimeter-smoke (push) Successful in 11s
2026-08-30 10:42:00 +00:00
65dfdee63d Merge pull request 'лендинг: этаж перестал теряться на переходе к проверке' (#3279) from fix/mera-keep-floor-in-draft into main
All checks were successful
Deploy Trade-In / changes (push) Successful in 13s
Deploy Trade-In / build-backend (push) Has been skipped
Deploy Trade-In / test (push) Has been skipped
Deploy Trade-In / build-browser (push) Has been skipped
Deploy Trade-In / build-frontend (push) Successful in 2m9s
Deploy Trade-In / deploy (push) Successful in 58s
Deploy Trade-In / deploy-status (push) Successful in 1s
Deploy Trade-In / perimeter-smoke (push) Successful in 12s
2026-08-30 10:33:34 +00:00
f3e05e1907 Merge branch 'main' into fix/mera-keep-floor-in-draft
All checks were successful
CI Trade-In / changes (pull_request) Successful in 13s
CI / changes (pull_request) Successful in 16s
CI Trade-In / backend-tests (pull_request) Has been skipped
CI Trade-In / browser-tests (pull_request) Has been skipped
CI Trade-In / frontend-checks (pull_request) Successful in 2m21s
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
2026-08-30 10:23:10 +00:00
8fb5587888 Merge branch 'main' into fix/3194-hide-sql-parameters
All checks were successful
CI Trade-In / changes (pull_request) Successful in 11s
CI / changes (pull_request) Successful in 19s
CI Trade-In / browser-tests (pull_request) Has been skipped
CI Trade-In / frontend-checks (pull_request) Has been skipped
CI / frontend-tests (pull_request) Has been skipped
CI / openapi-codegen-check (pull_request) Successful in 3m10s
CI Trade-In / backend-tests (pull_request) Successful in 5m56s
CI / backend-tests (pull_request) Successful in 18m10s
2026-08-30 10:23:05 +00:00
98325d33a9 Merge pull request 'тикер: разброс показанных строк под лентой — она больше не опровергает заголовок' (#3278) from fix/mera-ticker-context into main
All checks were successful
Deploy Trade-In / changes (push) Successful in 12s
Deploy Trade-In / build-browser (push) Has been skipped
Deploy Trade-In / build-frontend (push) Successful in 3m36s
Deploy Trade-In / test (push) Successful in 4m45s
Deploy Trade-In / build-backend (push) Successful in 34s
Deploy Trade-In / deploy (push) Successful in 2m5s
Deploy Trade-In / deploy-status (push) Successful in 1s
Deploy Trade-In / perimeter-smoke (push) Successful in 11s
2026-08-30 10:22:51 +00:00
619e38b1e7 Merge branch 'main' into fix/mera-ticker-context
All checks were successful
CI Trade-In / changes (pull_request) Successful in 12s
CI Trade-In / backend-tests (pull_request) Has been skipped
CI / changes (pull_request) Successful in 14s
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 1m15s
2026-08-30 10:15:23 +00:00
53a1b9ba89 Merge pull request 'лендинг: 32 нарушения контраста WCAG AA — затемнены токены, поставлен сторож' (#3277) from fix/mera-public-contrast into main
Some checks failed
Deploy Trade-In / perimeter-smoke (push) Blocked by required conditions
Deploy Trade-In / deploy-status (push) Blocked by required conditions
Deploy Trade-In / changes (push) Successful in 18s
Deploy Trade-In / build-browser (push) Has been skipped
Deploy Trade-In / build-frontend (push) Successful in 2m18s
Deploy Trade-In / test (push) Successful in 4m20s
Deploy Trade-In / build-backend (push) Successful in 1m8s
Deploy Trade-In / deploy (push) Has been cancelled
2026-08-30 10:15:14 +00:00
be59ca4452 Merge branch 'main' into fix/mera-public-contrast
All checks were successful
CI Trade-In / changes (pull_request) Successful in 12s
CI Trade-In / backend-tests (pull_request) Has been skipped
CI Trade-In / browser-tests (pull_request) Has been skipped
CI / changes (pull_request) Successful in 14s
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 1m20s
2026-08-30 10:13:25 +00:00
c53a967f49 Merge pull request 'подсказки адреса: пустые части адреса выпадают, а не печатаются' (#3276) from fix/mera-suggest-formatting into main
Some checks failed
Deploy Trade-In / build-backend (push) Blocked by required conditions
Deploy Trade-In / deploy (push) Blocked by required conditions
Deploy Trade-In / perimeter-smoke (push) Blocked by required conditions
Deploy Trade-In / deploy-status (push) Blocked by required conditions
Deploy Trade-In / changes (push) Successful in 16s
Deploy Trade-In / build-browser (push) Has been skipped
Deploy Trade-In / build-frontend (push) Has been cancelled
Deploy Trade-In / test (push) Has been cancelled
2026-08-30 10:13:01 +00:00
70df446d09 Merge pull request 'лендинг: имя боевого сервера убрано из пользовательской копии + гейт' (#3273) from fix/mera-drop-prod-hostname into main
Some checks failed
Deploy Trade-In / test (push) Blocked by required conditions
Deploy Trade-In / build-backend (push) Blocked by required conditions
Deploy Trade-In / build-frontend (push) Blocked by required conditions
Deploy Trade-In / build-browser (push) Blocked by required conditions
Deploy Trade-In / deploy (push) Blocked by required conditions
Deploy Trade-In / perimeter-smoke (push) Blocked by required conditions
Deploy Trade-In / deploy-status (push) Blocked by required conditions
Deploy Trade-In / changes (push) Has been cancelled
2026-08-30 10:12:55 +00:00
df53ff5a5f лендинг: этаж перестал теряться на переходе к проверке
All checks were successful
CI Trade-In / changes (pull_request) Successful in 10s
CI Trade-In / backend-tests (pull_request) Has been skipped
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 1m5s
Этаж — обязательное поле карточки: без него форма не отправляется. При этом
saveDraft его не клал, а на целевой странице поля этажа нет вовсе. Комментарий
объяснял это тем, что «повторно набирать одно короткое поле дешевле, чем
хранить лишнее» — довод неверен: переспросить негде, и обязательное поле
работало чистой помехой.

Схема бэкенда этаж принимает (TradeInEstimateInput.floor), и на цену он влияет
(первый и последний этаж). Хранится теперь по тому же доводу, что и состояние:
выбросить уже полученный ответ и спросить второй раз хуже, чем донести.

Тест — через САМУ ФОРМУ, и это не формальность. Первая попытка защитить правку
звала saveDraft({floor}) напрямую: она проверяла round-trip хранилища и
оставалась зелёной, когда из FreeCheckCard убирали передачу этажа, то есть
ровно при возврате чинимого дефекта. Сторож, который не сторожит. Теперь форма
заполняется и отправляется целиком; снятие проводки даёт «expected undefined to
be 7/16» — красное по значению.

Плюс три случая на само хранилище: старый черновик без поля переживает выкатку,
нестроковое значение выпадает не унося остальное.
2026-08-30 15:11:40 +05:00
663d63aea4 fix(tradein): подсказки адреса — пустые части адреса выпадают, а не печатаются
All checks were successful
CI Trade-In / changes (pull_request) Successful in 9s
CI Trade-In / browser-tests (pull_request) Has been skipped
CI Trade-In / frontend-checks (pull_request) Has been skipped
CI / changes (pull_request) Successful in 16s
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 / backend-tests (pull_request) Successful in 5m50s
Прод отдавал «г Екатеринбург, ул Фролова , д. 29, корп.»: реестровый
readable_address (ЕГРН) приходит УЖЕ склеенным вместе с пустыми частями —
маркер без значения печатается, лишний пробел перед запятой остаётся, и все
тиры /suggest (cadastral / geoportal / houses / DaData / Nominatim) пропускали
строку насквозь.

Чиним склейку, а не конкретный случай: `tidy_address()` — один проход по
частям (схлопнуть пробелы, выбросить пустые и маркер-без-номера:
корп./стр./лит./кв./оф./пом. и пр.), склейка обратно. Применяется в
`GeocodeSuggestion.__post_init__` — единственной точке, через которую проходят
все тиры, включая локальные, которые питают и `geocode()`.

Тест на функцию склейки, фальсифицирован снятием фильтра пустых: краснеет по
значению строки (10 из 14), а не исключением.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-30 14:58:03 +05:00
8aac93ee9b fix(mera-public): контраст WCAG AA на публичном лендинге
All checks were successful
CI Trade-In / changes (pull_request) Successful in 14s
CI / changes (pull_request) Successful in 17s
CI Trade-In / backend-tests (pull_request) Has been skipped
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 2m3s
axe 30.08 нашёл 32 узла color-contrast (все serious). Причина одна на все:
пары «цвет × фон» подбирались глазами, а числа в комментариях писались по
памяти — шапка b2c-tokens.ts утверждала «onAccent на accentDeep 4.6:1», тогда
как реальный замер 4.41, то есть главная кнопка призыва не проходила норму, а
документация уверяла, что проходит.

Затемнены четыре токена до запаса на худшем светлом фоне (surfaceSoft, он
темнее pageBg): accentDeep 4.41→4.97, muted 4.45→5.36, success 4.04→4.96,
danger 4.60→5.23. Оттенок сохранён, фирменный вид не меняется.

Отдельный класс — светлый токен на тёмной плашке surfaceDark, где шкала
перевёрнута: метки тикера красились muted (2.7) и accentText (2.85), стрелка
между прогнозом и фактом — линейным #2c3a3f (1.50). Переведены на mutedDark
(6.2) и accent (6.24). Заодно убраны сырые hex #9fb0b4 (2.24 на светлом —
.artSoon, .gameScale, .repPaidFine, .artFootnote; 7.84 на тёмном) — палитра
запрещает hex в CSS именно потому, что мимо токена величина не считается
никаким аудитом.

Регресс ловится без браузера: contrast-tokens.test.ts считает яркость по
формуле WCAG прямо на значениях токенов и проверяет ОБА фона страницы, плюс
сторож на новые сырые hex в CSS. Проверен фальсификацией: возврат muted к
#667579 красит тест.
2026-08-30 14:57:21 +05:00
7d6caed5fb МЕРА: лента над первым экраном получает контекст разброса
All checks were successful
CI Trade-In / changes (pull_request) Successful in 12s
CI / changes (pull_request) Successful in 19s
CI Trade-In / backend-tests (pull_request) Has been skipped
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 1m45s
Над лентой стояло «медианное расхождение с ценой ДКП — 14,5 % по 327
сделкам», а в самой ленте 5 строк из 20 расходились больше чем на 30 %
(75,7 · 63,6 · 47,4 · 41,4 · 38,5). Первое, что видел посетитель страницы
про точность, — крупный промах без единой цифры контекста.

Промахи не прячутся: строки витрины отобраны по ПОЛНОТЕ и СВЕЖЕСТИ
(_sort_key в app/tasks/landing_showcase_deals.py), отбор по величине
ошибки был дефектом и снят. Лечится контекстом — под лентой печатается
тот же разброс ПОКАЗАННЫХ строк, что уже стоит под таблицей сверок:
медиана модуля и худшая, обе из shownSpread() (deal-view.ts), второго
расчёта не заводится. Вывода вида «зато обычно точно» в подписи нет: он
протух бы на первом пересчёте витрины, а два числа рядом — нет.

Разметка: бегущая часть выделена в .tickerStrip — position/overflow
нужны только ей, иначе абсолютный бейдж растянулся бы и на подпись.

Проверка (landing-v3-render.test.tsx): те же строки с худшей и без неё
дают РАЗНЫЕ числа в подписи — она сосчитана по показанному, а не вписана.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-30 14:54:52 +05:00