feat(site-finder): §4.3 тренд из цен предложения Объектива при устаревших сделках (#2178) #2190

Merged
bot-backend merged 1 commit from feat/market-trend-objective-2178 into main 2026-07-02 18:33:17 +00:00
Collaborator

Summary

  • «Тренд рынка» больше не тупик: когда сделки Росреестра устарели (max 2026-01), карточка показывает динамику цен предложения из objective_lots_history — новый статус offer_only (медиана ₽/м², delta-бейдж, SVG-спарклайн по снапшотам, полная подпись источника + caveat про устаревший Росреестр). При свежих сделках offer-тренд идёт компакт-строкой под основным. source_stale остаётся только когда нет вообще ничего.
  • compute_offer_price_trend: ЖК того же 3км-радиуса → mapping → лоты → история; дедуп задвоенного снапшота 22.06 (DISTINCT ON + fetched_at DESC), фильтры «в продаже» + вменяемость цены, медиана PERCENTILE_CONT per snapshot.
  • Предохранитель прод-латентности: SET LOCAL statement_timeout 8s вокруг offer-запроса (EXPLAIN на плотном центре ЕКБ: холодный ~5.5 с / тёплый ~1 с; sparse ~2.6/0.4 с) — при таймауте откат savepoint и прежнее поведение. Follow-up прекомпьюта per-complex медиан — если латентность проявится в реальном трафике.
  • Прод-smoke (участок 66:41:0204016:10): 6 точек 17.05–30.06, 7 ЖК, ~1.5k лотов, медиана 146 841 → 134 983 ₽/м² (−8.1%).

Test plan

  • backend: 197 passed (12 новых unit на SQL-форму/дедуп/медианы/graceful), ruff clean
  • frontend: tsc clean, eslint clean; guard от старого бандла существовал и до PR
  • code-reviewer ⚠️→resolved (перф-флаг закрыт таймаутом; EXPLAIN ANALYZE на прод-БД)
  • post-deploy: скриншот §4.3 на 66:41:0204016:10 — карточка offer_only вместо «Источник устарел»

Refs #2178

## Summary - «Тренд рынка» больше не тупик: когда сделки Росреестра устарели (max 2026-01), карточка показывает **динамику цен предложения из objective_lots_history** — новый статус `offer_only` (медиана ₽/м², delta-бейдж, SVG-спарклайн по снапшотам, полная подпись источника + caveat про устаревший Росреестр). При свежих сделках offer-тренд идёт компакт-строкой под основным. `source_stale` остаётся только когда нет вообще ничего. - `compute_offer_price_trend`: ЖК того же 3км-радиуса → mapping → лоты → история; дедуп задвоенного снапшота 22.06 (DISTINCT ON + fetched_at DESC), фильтры «в продаже» + вменяемость цены, медиана PERCENTILE_CONT per snapshot. - Предохранитель прод-латентности: `SET LOCAL statement_timeout 8s` вокруг offer-запроса (EXPLAIN на плотном центре ЕКБ: холодный ~5.5 с / тёплый ~1 с; sparse ~2.6/0.4 с) — при таймауте откат savepoint и прежнее поведение. Follow-up прекомпьюта per-complex медиан — если латентность проявится в реальном трафике. - Прод-smoke (участок 66:41:0204016:10): 6 точек 17.05–30.06, 7 ЖК, ~1.5k лотов, медиана 146 841 → 134 983 ₽/м² (**−8.1%**). ## Test plan - [x] backend: 197 passed (12 новых unit на SQL-форму/дедуп/медианы/graceful), ruff clean - [x] frontend: tsc clean, eslint clean; guard от старого бандла существовал и до PR - [x] code-reviewer ⚠️→resolved (перф-флаг закрыт таймаутом; EXPLAIN ANALYZE на прод-БД) - [ ] post-deploy: скриншот §4.3 на 66:41:0204016:10 — карточка offer_only вместо «Источник устарел» Refs #2178
bot-backend added 1 commit 2026-07-02 18:17:59 +00:00
feat(site-finder): тренд §4.3 из цен предложения Объектива при устаревших сделках (#2178)
All checks were successful
CI / frontend-tests (pull_request) Successful in 1m7s
CI / openapi-codegen-check (pull_request) Successful in 2m0s
CI / backend-tests (pull_request) Successful in 14m20s
CI / changes (pull_request) Successful in 6s
252affa139
rosreestr_deals встали на 2026-01 → карточка «Тренд рынка» почти всегда
source_stale-тупик. Добавлен второй источник: медианная динамика ₽/м² по
objective_lots_history для ЖК того же 3км-радиуса (через
objective_complex_mapping, как в best_layouts).

- compute_offer_price_trend: дедуп задвоенного снапшота (DISTINCT ON +
  fetched_at DESC), фильтры активных лотов и вменяемости цены, медиана
  PERCENTILE_CONT per snapshot, delta_pct
- эндпоинт: саб-блок offer_trend при ok; новый статус offer_only когда
  сделки stale но предложение живо; source_stale — только когда нет ничего;
  SET LOCAL statement_timeout 8s вокруг offer-запроса (холодный прогон на
  плотном центре ~5.5с — при таймауте честный откат к прежнему поведению)
- фронт: карточка offer_only (медиана + delta-бейдж + SVG-спарклайн +
  полная подпись источника и caveat), компакт-строка под ok-трендом
- 12 unit-тестов backend; smoke на прод-БД: 6 точек, 7 ЖК, 146.8k→135.0k
  ₽/м² (−8.1%) для участка 66:41:0204016:10
bot-backend merged commit a3db6e4158 into main 2026-07-02 18:33:17 +00:00
bot-backend deleted branch feat/market-trend-objective-2178 2026-07-02 18:33:17 +00:00
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
1 participant
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#2190
No description provided.