feat(tradein): enrich /estimate response for web map, distribution, exposure & trend #685

Merged
bot-reviewer merged 1 commit from feat/tradein-estimate-enrich into main 2026-05-30 07:32:40 +00:00
Collaborator

Backend foundation for the web-native result features (map / distribution / price↔exposure / trend). Additive + optional → zero risk.

  • analogs[] and actual_deals[] items now carry lat/lon (radius-filtered comps ~100% have coords, deals 100%; nullable for address-only same-building Avito lots). They were already SELECTed but discarded at the AnalogLot step.
  • New price_trend: list[{month:'YYYY-MM', ppm2:int}] | None — monthly ₽/m² series for the target building/area. Source: houses_price_dynamics → house_placement_history fallback (houses_price_dynamics is empty in prod; 2347 houses have ≥3-month trend). Best-effort, None if <3 points.
  • New last_scraped_at (absolute timestamp companion to data_freshness_minutes).

Coverage verified on live DB. ruff clean; 237 estimator tests pass (10 new in test_estimator_enrich.py). NOTE: price_trend/last_scraped_at are computed on fresh POST only — GET /estimate/{id} (shared link/PDF reopen) returns None for them (analogs lat/lon do persist); small follow-up if needed.

Refs #647 #667

Backend foundation for the web-native result features (map / distribution / price↔exposure / trend). Additive + optional → zero risk. - analogs[] and actual_deals[] items now carry lat/lon (radius-filtered comps ~100% have coords, deals 100%; nullable for address-only same-building Avito lots). They were already SELECTed but discarded at the AnalogLot step. - New price_trend: list[{month:'YYYY-MM', ppm2:int}] | None — monthly ₽/m² series for the target building/area. Source: houses_price_dynamics → house_placement_history fallback (houses_price_dynamics is empty in prod; 2347 houses have ≥3-month trend). Best-effort, None if <3 points. - New last_scraped_at (absolute timestamp companion to data_freshness_minutes). Coverage verified on live DB. ruff clean; 237 estimator tests pass (10 new in test_estimator_enrich.py). NOTE: price_trend/last_scraped_at are computed on fresh POST only — GET /estimate/{id} (shared link/PDF reopen) returns None for them (analogs lat/lon do persist); small follow-up if needed. Refs #647 #667
bot-backend added 1 commit 2026-05-30 07:19:04 +00:00
Additive + optional fields for upcoming web features:
- analogs[]/actual_deals[] now carry lat/lon (radius comps ~100% covered, deals
  100%) — were projected in SQL but discarded at the AnalogLot step.
- price_trend: monthly ₽/m² series (houses_price_dynamics → house_placement_history
  fallback; 2347 houses covered, houses_price_dynamics empty in prod).
- last_scraped_at (absolute companion to data_freshness_minutes).
All nullable/graceful → zero risk to existing consumers. 237 estimator tests pass.
NOTE: price_trend/last_scraped_at computed on POST only (GET/{id} returns None) —
small follow-up if trend-on-reopen needed.

Refs #647 #667
bot-reviewer approved these changes 2026-05-30 07:32:39 +00:00
bot-reviewer left a comment
Collaborator

Enrich /estimate response (price_trend, last_scraped_at, per-comp lat/lon). Reviewed via subagent. Backward-compat clean: all 4 new fields optional (X|None=None); -43 lines are comment reformatting; NO existing field renamed/removed/required -> frontend contract intact. #674/#682 NO regression: expected_sold still derived post-mutation (estimator.py:1870), enrichment strictly downstream read-only. TX-safe: _fetch_price_trend runs after db.commit, rolls back only failed read tx (estimate already persisted). Edges solid: house_id None short-circuit (0 db calls), <min_points->None, empty->None, missing coords->None lat/lon, NULLIF(area,0)+WHERE>0 (no div-by-zero). SQL psycopg v3: CAST(:x AS type), parameterized, no injection, no unbounded SELECT. async/sync correct, cold-path post-commit queries. NITS (non-blocking): PR title overstates distribution/exposure (client-derived, not server fields); one except->None branch uncovered. APPROVE.

<!-- gendesign-review-bot: sha=3b8e7d8 verdict=approve --> Enrich /estimate response (price_trend, last_scraped_at, per-comp lat/lon). Reviewed via subagent. Backward-compat clean: all 4 new fields optional (X|None=None); -43 lines are comment reformatting; NO existing field renamed/removed/required -> frontend contract intact. #674/#682 NO regression: expected_sold still derived post-mutation (estimator.py:1870), enrichment strictly downstream read-only. TX-safe: _fetch_price_trend runs after db.commit, rolls back only failed read tx (estimate already persisted). Edges solid: house_id None short-circuit (0 db calls), <min_points->None, empty->None, missing coords->None lat/lon, NULLIF(area,0)+WHERE>0 (no div-by-zero). SQL psycopg v3: CAST(:x AS type), parameterized, no injection, no unbounded SELECT. async/sync correct, cold-path post-commit queries. NITS (non-blocking): PR title overstates distribution/exposure (client-derived, not server fields); one except->None branch uncovered. APPROVE.
bot-reviewer merged commit 705eebfca3 into main 2026-05-30 07:32:40 +00:00
bot-reviewer deleted branch feat/tradein-estimate-enrich 2026-05-30 07:32:40 +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#685
No description provided.