feat(tradein): premium_houses MV + premium_building flag (#2002) #2006

Merged
lekss361 merged 2 commits from feat/tradein-premium-flag into main 2026-06-27 16:40:39 +00:00
Owner

Summary

Data-derived premium-building identification for EKB (#2002 roadmap). Flags whether the target unit sits in a premium building — for manual-review routing (#4) and as honest context. Metadata only — does NOT change expected_sold (so the regression gate is unaffected).

  • premium_houses materialized view (data/sql/139_*.sql): premium houses by listing concentration — n≥4 active listings AND (median ppm² ≥220k OR ≥3 listings ≥20M₽). Dry-run on prod: 298 houses, covering ~65% of all ≥20M elite listings (surfaces the real premium core: Гоголя 21, Ельцина 6, Олимпийская наб, Хохрякова 48, Энергостроителей 7…). Refreshed by the existing refresh_search_matview task. Idempotent (IF NOT EXISTS). House_id dupes (imperfect dedup) kept on purpose — all variants stay in the set, so coverage isn't hurt.
  • Estimator: estimate_quality resolves target_house_id (already), then _is_premium_building(db, house_id)premium_building + premium_building_median_ppm2 on the AggregatedEstimate response. CAST(:hid AS bigint) (psycopg v3); wrapped in try/except → graceful (False, None) if the MV is missing, never breaks an estimate. Runs after db.commit() so a failed read can't poison the persisted estimate.

Why a flag, not an uplift

The research proved the elite point is unidentifiable from observable signals (premium = unit-level finish/class, not on deals). A premium-building flag → manual-review is the safe move; an auto-uplift would re-introduce overpay risk on an un-validatable magnitude. (An uplift could be revisited later with forward-logging validation.)

Test plan

  • MV dry-run on prod → 298 rows (rolled back, no prod change)
  • regression gate green (flag is outside the pure pricing path)
  • new tests/test_estimator_premium_building.py — 6 cases (premium→True/median, non-premium→False, None short-circuit, MV-missing graceful, NULL median, default serialization; asserts CAST not ::)
  • full tradein suite 2514 passed / 2 skipped (CI-equivalent)

Follow-up (#2002)

#4 manual-review flag consumes premium_building (+ high-value + low-confidence) → "ручная оценка" routing + frontend.

Refs #2002

## Summary Data-derived **premium-building identification** for EKB (#2002 roadmap). Flags whether the target unit sits in a premium building — for manual-review routing (#4) and as honest context. **Metadata only — does NOT change `expected_sold`** (so the regression gate is unaffected). - **`premium_houses` materialized view** (`data/sql/139_*.sql`): premium houses by listing concentration — `n≥4 active listings AND (median ppm² ≥220k OR ≥3 listings ≥20M₽)`. **Dry-run on prod: 298 houses, covering ~65% of all ≥20M elite listings** (surfaces the real premium core: Гоголя 21, Ельцина 6, Олимпийская наб, Хохрякова 48, Энергостроителей 7…). Refreshed by the existing `refresh_search_matview` task. Idempotent (`IF NOT EXISTS`). House_id dupes (imperfect dedup) kept on purpose — all variants stay in the set, so coverage isn't hurt. - **Estimator**: `estimate_quality` resolves `target_house_id` (already), then `_is_premium_building(db, house_id)` → `premium_building` + `premium_building_median_ppm2` on the `AggregatedEstimate` response. `CAST(:hid AS bigint)` (psycopg v3); wrapped in try/except → graceful `(False, None)` if the MV is missing, never breaks an estimate. Runs after `db.commit()` so a failed read can't poison the persisted estimate. ## Why a flag, not an uplift The research proved the elite **point** is unidentifiable from observable signals (premium = unit-level finish/class, not on deals). A premium-building **flag → manual-review** is the safe move; an auto-uplift would re-introduce overpay risk on an un-validatable magnitude. (An uplift could be revisited later with forward-logging validation.) ## Test plan - [x] MV dry-run on prod → 298 rows (rolled back, no prod change) - [x] regression gate green (flag is outside the pure pricing path) - [x] new `tests/test_estimator_premium_building.py` — 6 cases (premium→True/median, non-premium→False, None short-circuit, MV-missing graceful, NULL median, default serialization; asserts `CAST` not `::`) - [x] full tradein suite **2514 passed / 2 skipped** (CI-equivalent) ## Follow-up (#2002) **#4 manual-review flag** consumes `premium_building` (+ high-value + low-confidence) → "ручная оценка" routing + frontend. Refs #2002
lekss361 added 2 commits 2026-06-27 16:40:28 +00:00
feat(tradein/estimator): premium_building flag from premium_houses MV (#2002)
All checks were successful
CI / changes (pull_request) Successful in 7s
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
09f9dc131f
Read-only _is_premium_building(db, house_id) looks up target_house_id in the
premium_houses MV (data/sql/139) and surfaces premium_building +
premium_building_median_ppm2 on AggregatedEstimate. Metadata only for
manual-review routing (#4) — does NOT touch _price_from_inputs / expected_sold /
median / ranges, so the backtest regression gate is unaffected.

MV-missing / SQL errors degrade to (False, None) with a rollback so an estimate
never breaks where the MV does not yet exist.
lekss361 merged commit 840d64a4a0 into main 2026-06-27 16:40:39 +00:00
lekss361 deleted branch feat/tradein-premium-flag 2026-06-27 16:40:39 +00:00
lekss361 added the
analytics
priority/p2
scope/backend
tradein
labels 2026-06-27 16:40:40 +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#2006
No description provided.