5a: _load_sber_index_series логирует warning если latest месяц серии
старее sber_index_max_age_days (дефолт 35) — расчёт не блокируется.
5b: AvitoImvSummary.thin_market (bool, дефолт False) — True когда
market_count < avito_imv_thin_market_threshold (дефолт 10). Все три
точки конструирования AvitoImvSummary обновлены. Warning при thin.
sigma=0 guard: safe_area_sigma2/safe_floor_sigma2 предотвращает div/0 при
нулевом sigma из конфига. Post-weight MAD-clip (estimate_sb_clip_after_weight,
дефолт True) выполняется ПОСЛЕ Gaussian weighting — видовые/топ-юниты
с высоким ppm² больше не выкидываются до учёта similarity. За флагом.
_fetch_price_trend(freshness_months) — новый параметр, дефолт из
settings.estimate_price_trend_max_age_months (6 мес).
WHERE scraped_at > now() - N months исключает устаревшие items
(yandex_valuation 2024 и т.д.) из house_placement_history fallback.
houses_price_dynamics (Source 1) не затронут. psycopg v3 CAST syntax.
- types/trade-in.ts: добавлен AnalogTier тип и analog_tier? поле в AggregatedEstimate (опциональное, graceful при absent/null)
- HeroTransparency: resolveCompsTier() предпочитает analog_tier (структурный, без парсинга строки), fallback на compsTier() эвристику при absent/null; добавлена строка «Точность адреса» в collapsible «Как рассчитано» из address_precision с предупреждением при low+approximate
- HeroSummary: третий бар «Ожидаемая цена сделки» (expected_sold_price_rub/low/high) с отличным цветом (viz-5/6) — graceful при null; ratio_basis показывается всегда: per_rooms→«по сделкам той же планировки», global_fallback→прежний текст
Добавляет AggregatedEstimate.analog_tier — стабильный enum для фронта:
same_building (Tier A), micro_radius (Tier C), district (S/H/0), city (W),
null (нет данных). Фронт не парсит tier из explanation.
address_precision уже был в схеме (подтверждено: line 208). Explanation не
удаляется — фронт fallback'ает на него.
Якорь с confidence=low ИЛИ (n<gate_min_n И FSD>gate_max_fsd) не заменяет
headline — fallback на radius-median. Дефолты (min_n=3, max_fsd=0.20) не
режут здоровые якоря (n≥4, FSD<0.15 проходят). За флагом
estimate_sb_low_conf_gate_enabled (дефолт True). Логируется с причиной.
- browser/server.py: GET /pacing и PUT /pacing — read/write _MIN_PAGE_INTERVAL_BY_PROVIDER
in-memory; валидация source in PROVIDERS, interval_s >= 0; логирует изменения; сбрасывается
к env-дефолту на рестарте by design
- backend/admin.py: GET /scraper/pacing — прокси к browser /pacing, PacingResponse pydantic;
PUT /scraper/pacing/{source} — прокси PUT с валидацией ge=0 le=120; 502/503 при недоступности
- backend/admin.py: GET /scraper/data-quality — single-pass FILTER-агрегаты по listings WHERE
is_active GROUP BY source (description/photo_urls/address/lat/lon/kitchen_area_m2/living_area_m2/
ceiling_height/ceiling_height_m/metro_stations); houses (total/avito_validated_at%/rating_score%/
house_type%); house_reviews count
- browser/test_server_pacing.py: 10 новых тестов GET+PUT /pacing (16 total, все зелёные)
- backend/tests/test_scraper_admin_apis.py: тесты pacing-прокси + data-quality shape/pct-range
(21 total, все зелёные)
- pyproject.toml: httpx[socks]>=0.27.0 — тянет socksio, socks5:// прокси в _probe_current_ip работает прозрачно
- admin.py list_scrape_runs_unified: status Literal["done","running","banned","zombie","failed","cancelled"] вместо str|None — невалидные значения → 422
- avito_houses.py save_house_catalog_enrichment: гард ext_id=0 + нет адреса → skip without DB touch; два id-less novostroyka URL не схлопываются в bogus avito:0 в house_sources
- тесты: test_unified_runs_invalid_status_422 + test_unified_runs_valid_statuses_200; test_save_house_catalog_enrichment_skips_zero_ext_id_no_address + *_with_address_persists
- cian/page.tsx: отдельный queryKey ["cian-test-auth", "manual"] для ручного
testAuthQuery в CianCookiesSection — устраняет кросс-контаминацию с автопуллингом
useTestAuth() (refetchInterval:60s) и ручной кнопкой "Test Current Session"
- RunsTable.tsx, ScraperPage.tsx (RunsLogSection), ProxyHealthCard.tsx:
scope="col" на все <th> в thead — соответствие WCAG SC 1.3.1 (Info and Relationships)
- Topbar.tsx: aria-current="page" на активный nav-link вместо tablist/tabpanel —
корректный паттерн для link-based навигации между отдельными страницами
- ProxyHealthCard.tsx: role="img" + aria-label на цветовые dot-индикаторы статуса
browser-инстансов — цвет больше не единственный носитель смысла (WCAG 1.4.1)
#1803 HeroTransparency: formatRuDateTime добавляет timeZone:"UTC" (SSR Node UTC
vs клиент Europe/Moscow давали разный час → React minified error #418).
Date.now() fallback (data_freshness_minutes без last_scraped_at) вынесен в
useEffect/useState — не выполняется при SSR.
#1804 PhotoUpload: guard isRealEstimateId() проверяет UUID4 regex и отклоняет
preview-0000-... — GET/POST /photos с фейковым ID больше не слаются → нет 422.
Счётчик показывает «— / 12» вместо «0 / 12», input disabled в preview-режиме.
ceiling_height на detail-странице лежит в offer.building.ceilingHeight,
а не offer.ceilingHeight (всегда null) → было 0% покрытия. repairType
часто пустой, структурное значение приходит как offer.decoration
('preFine'/...) — читаем оба + добавлен preFine->needs_repair и
case-insensitive lookup в нормализаторе. kitchen/description пути уже
верны (offer.kitchenArea/offer.description) — низкое покрытие = мёртвый
CIAN_PROXY_URL, не маппинг. Регресс-тест на реальной карточке 330982715.
The geoportal serves a Russian national-CA (Минцифры) TLS cert absent from
httpx's default trust store → CERTIFICATE_VERIFY_FAILED, loader fetched 0.
Public read-only data → verify=False (same as the curl -k used in recon).
#1786 merged before the test fix landed → main red on
test_geocode_uses_cadastral_before_yandex. The new geoportal house-match
tier runs first in geocode(); this legacy cadastral test must mock it to
None so it exercises the cadastral forward path (else the MagicMock db row
leaks through the new tier as lat=1.0).
The realtime FK mirror (base.py:607-616) only landed 2026-06-17 (e63b21e).
Listings matched into house_sources before that — notably 9205 cian novostroyki
frozen at 2026-05-31 — never had house_id_fk mirrored back, breaking the
canonical "same-building via house_id_fk" estimator path (93% of active cian
novostroyki had NULL fk citywide).
Add data/sql/130_backfill_listings_house_id_fk.sql: deterministic source-id
backfill via house_sources (ext_source, ext_id → house_id), idempotent
(WHERE house_id_fk IS NULL), no fuzzy/address fallback. Prod (read-only):
9235/9235 target rows resolve deterministically, zero unresolvable. One-time
backlog drain; future rows linked in realtime by the e63b21e mirror.