Commit graph

4 commits

Author SHA1 Message Date
bot-backend
51c79f9324 fix(tradein/estimator): analogs cards match n_analogs, no cross-source dups
All checks were successful
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 55s
CI Trade-In / changes (pull_request) Successful in 8s
CI / changes (pull_request) Successful in 8s
CI / backend-tests (pull_request) Has been skipped
CI / frontend-tests (pull_request) Has been skipped
Two display-layer bugs surfaced by pre-launch smoke (golden-path address
"Екатеринбург, улица Малышева, 51"):

1. n_analogs (same-building anchor path) was computed from the post-MAD-clip
   comp population (_compute_same_building_anchor: n = len(surviving ppm2)),
   but the displayed analogs cards were built from the ORIGINAL, un-clipped
   anchor_comps list. A MAD-clip-excluded price outlier (e.g. a cross-source
   duplicate priced ~4.5x above the rest) never affected the median/n_analogs,
   yet still showed up as a card.

   Fix: _compute_same_building_anchor now returns the final surviving "comps"
   list (len == n), and the caller sets anchor_comps_used = anchor["comps"]
   instead of the raw pre-clip anchor_comps.

2. The statistical cross-source dedup (_dedup_cross_source) requires the same
   price_bucket (rounded price_rub) to consider two listings duplicates. Real
   cross-posts of the same physical unit almost always have a small asking-
   price drift between platforms, which can straddle a bucket boundary and
   let the duplicate survive into both the price population and the UI.

   Fix: a new display-only dedup pass (_dedup_display_lots /
   _union_find_phys_dedup) uses the same physical key (cadnum-or-street +
   floor + area_bucket) but WITHOUT price_bucket, applied only when building
   the displayed analogs_lots — never touches n_analogs/median/cv. To avoid
   over-merging genuinely distinct same-building units that happen to share
   floor/area, it requires the two lots to come from DIFFERENT sources
   (require_diff_source guard) — same-source pairs are left untouched.

The radius-path (non-anchor) branch had a related count-consistency gap:
n_analogs counted only PRICED listings_clean entries, while the displayed
cards were sliced from the full (unfiltered) listings_clean, occasionally
letting price-less entries inflate the card count beyond n_analogs. Cards
are now built from the same priced subset.

Frozen backtest regression gate (tests/test_backtest_regression_gate.py,
hermetic replay of committed fixture) is byte-identical after this change —
zero delta on median/expected_sold/coverage/calibration, confirming this is
display-only and does not touch pricing.

Added tests/test_estimator_analogs_display_consistency.py: full-pipeline
regression for both root causes (outlier duplicate pair fully excluded from
both count and cards; non-outlier duplicate pair collapses in cards only,
honestly documenting len(analogs) <= n_analogs when the display-only dedup
catches a residual cross-source dup the stat dedup missed) + unit tests on
_dedup_display_lots. Updated test_estimator_quarter_index.py's hand-rolled
_compute_same_building_anchor test double to match the new "comps" contract.
2026-07-13 23:04:33 +03:00
d22e0e00ae tech-debt(tradein/estimator): collapse won estimate_* flags into defaults (#1970) (#2475)
All checks were successful
Deploy Trade-In / changes (push) Successful in 10s
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 45s
Deploy Trade-In / build-backend (push) Successful in 58s
Deploy Trade-In / deploy (push) Successful in 47s
2026-07-12 12:46:18 +00:00
3f31d1f409 fix(estimator): sanity-clamp quarter-index factor (#859) (#863)
All checks were successful
Deploy Trade-In / changes (push) Successful in 5s
Deploy Trade-In / test (push) Successful in 28s
Deploy Trade-In / build-frontend (push) Has been skipped
Deploy Trade-In / build-backend (push) Successful in 39s
Deploy Trade-In / deploy (push) Successful in 34s
Co-authored-by: bot-backend <bot-backend@gendsgn.local>
Co-committed-by: bot-backend <bot-backend@gendsgn.local>
2026-05-31 07:20:59 +00:00
b16a45ef87 feat(tradein): per-cadastral-quarter price index in estimator (#764) (#858)
All checks were successful
Deploy Trade-In / changes (push) Successful in 5s
Deploy Trade-In / build-frontend (push) Has been skipped
Deploy Trade-In / test (push) Successful in 28s
Deploy Trade-In / build-backend (push) Successful in 40s
Deploy Trade-In / deploy (push) Successful in 34s
Co-authored-by: bot-backend <bot-backend@gendsgn.local>
Co-committed-by: bot-backend <bot-backend@gendsgn.local>
2026-05-31 06:53:21 +00:00