fix(tradein/estimator): remove dead tier-aware-ratio path — truncation artifact + footgun (#2002) #2015

Merged
lekss361 merged 1 commit from fix/tradein-remove-tier-ratio-footgun into main 2026-06-27 17:34:54 +00:00
Owner

Summary

Removes the dormant tier_aware_ratio_enabled price-tier ratio path (#928) — a proven statistical artifact and a latent footgun. Behavior-neutral at default: the flag shipped False, so the active path is unchanged → the regression baseline is byte-identical (not in the diff). −780 lines of dead code.

Why it's invalid (Monte-Carlo)

The tier derivation bins SOLD deals by sold-ppm² against ASKING-percentile bounds (t33/t66 of listings), then divides within-tier medians of mismatched populations — a ratio-of-truncated-medians artifact. A simulation with a constant true sold/asking = 0.84 reproduces the prod tier values (0.94/0.99/0.96) and the skewed deal split (57/27/15% vs listings 33/33/33) almost exactly → the 0.84→0.99 "premium sells closer to asking" gradient is 100% spurious. Correct binning (both sides by asking) is nearly flat (0.83→0.85).

Flipping the flag ON on a live 700-deal harness made prod worse: overall MAPE 14.6→17.2, эконом bias +5.8→+18.1 (it uniformly inflated expected_sold). The valid conditioning for price-segment correction is non-price observables — the per-rooms blend + the hedonic year+area (#2004). Full diagnosis in #2002.

Changes

  • estimator.py _get_asking_sold_ratio: deleted the entire tier branch (bounds read, t33/t66, asking_to_sold_ratios_tiered read, empirical-Bayes shrink) + the tier cache-key split; kept only the legacy per-rooms → global -1 lookup. Artifact note added.
  • config.py: removed tier_aware_ratio_enabled + tier_ratio_shrink_k (the only tier-only settings).
  • asking_to_sold_ratio.py (daily task): removed the tiered re-derivation (5 SQL constants + executes + counters) — stops refreshing the dead tier tables. Legacy ratio refresh untouched.
  • Tests: deleted the wholly-tier test file; updated 4 tests that referenced removed symbols (no unrelated assertions weakened).
  • git grep for all tier identifiers → zero remaining across app/tests/scripts.

Not in scope

Tier tables (asking_to_sold_ratios_tiered, asking_to_sold_tier_bounds, mig 098) left inert — a destructive DROP migration is an optional follow-up. The now-vestigial anchor_ppm2 param is retained for call-site compat (documented).

Test plan

  • regression gate byte-identical (baseline untouched — flag was False)
  • full suite 2504 passed / 2 skipped (1 pre-existing unrelated test_search_cache_hit 401, verified on clean base)
  • legacy resolver value-parity confirmed (per-rooms 0.74, global 0.79, cache)
  • ruff strict clean

Refs #2002

## Summary Removes the dormant `tier_aware_ratio_enabled` price-tier ratio path (#928) — a proven statistical artifact and a latent footgun. **Behavior-neutral at default**: the flag shipped `False`, so the active path is unchanged → the regression baseline is **byte-identical** (not in the diff). −780 lines of dead code. ## Why it's invalid (Monte-Carlo) The tier derivation bins SOLD deals by sold-ppm² against ASKING-percentile bounds (t33/t66 of listings), then divides within-tier medians of mismatched populations — a **ratio-of-truncated-medians artifact**. A simulation with a *constant* true sold/asking = 0.84 reproduces the prod tier values (0.94/0.99/0.96) and the skewed deal split (57/27/15% vs listings 33/33/33) almost exactly → the 0.84→0.99 "premium sells closer to asking" gradient is 100% spurious. Correct binning (both sides by asking) is nearly flat (0.83→0.85). Flipping the flag ON on a live 700-deal harness made prod **worse**: overall MAPE 14.6→17.2, эконом bias +5.8→+18.1 (it uniformly inflated `expected_sold`). The valid conditioning for price-segment correction is non-price observables — the per-rooms blend + the hedonic year+area (#2004). Full diagnosis in #2002. ## Changes - `estimator.py` `_get_asking_sold_ratio`: deleted the entire tier branch (bounds read, t33/t66, `asking_to_sold_ratios_tiered` read, empirical-Bayes shrink) + the tier cache-key split; kept only the legacy per-rooms → global `-1` lookup. Artifact note added. - `config.py`: removed `tier_aware_ratio_enabled` + `tier_ratio_shrink_k` (the only tier-only settings). - `asking_to_sold_ratio.py` (daily task): removed the tiered re-derivation (5 SQL constants + executes + counters) — stops refreshing the dead tier tables. Legacy ratio refresh untouched. - Tests: deleted the wholly-tier test file; updated 4 tests that referenced removed symbols (no unrelated assertions weakened). - `git grep` for all tier identifiers → **zero** remaining across app/tests/scripts. ## Not in scope Tier tables (`asking_to_sold_ratios_tiered`, `asking_to_sold_tier_bounds`, mig 098) left **inert** — a destructive `DROP` migration is an optional follow-up. The now-vestigial `anchor_ppm2` param is retained for call-site compat (documented). ## Test plan - [x] regression gate **byte-identical** (baseline untouched — flag was False) - [x] full suite **2504 passed / 2 skipped** (1 pre-existing unrelated `test_search_cache_hit` 401, verified on clean base) - [x] legacy resolver value-parity confirmed (per-rooms 0.74, global 0.79, cache) - [x] ruff strict clean Refs #2002
lekss361 added 1 commit 2026-06-27 17:34:44 +00:00
fix(tradein/estimator): remove dead tier-aware-ratio path — truncation artifact + footgun (#2002)
All checks were successful
CI / changes (pull_request) Successful in 6s
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
ac99886201
The tier_aware_ratio_enabled path (#928) binned SOLD deals by sold-ppm² against
ASKING-derived percentile bounds, then divided within-tier medians. That is a
ratio-of-truncated-medians ARTIFACT: a Monte-Carlo with a CONSTANT true
sold/asking=0.84 reproduced the prod tier values (0.94/0.99/0.96) and the skewed
deal split (57/27/15%) exactly — the "premium sells closer to asking" gradient is
100% spurious. Flipping the flag ON made prod WORSE (overall MAPE 14.6→17.2,
эконом bias +5.8→+18.1). It shipped dark (default False) but is a latent footgun.

A valid within-price-tier sold/asking is uncomputable from asking-less ДКП deals;
the per-rooms blend + the shipped hedonic (year+area) are the correct conditioning.
So the dead path is removed entirely, not just disabled.

- estimator._get_asking_sold_ratio: drop the tier branch (bounds read, t33/t66,
  asking_to_sold_ratios_tiered read, empirical-Bayes shrink) + the _legacy/tier
  cache-key split; keep only the legacy per-rooms → global -1 lookup. Cache key
  collapses to rooms bucket. anchor_ppm2 param retained for call-site compat (now
  unused).
- config: remove tier_aware_ratio_enabled + tier_ratio_shrink_k settings.
- tasks/asking_to_sold_ratio: drop the tiered refresh (DELETE/re-derive bounds +
  tier rows, tiered counters); the daily task no longer touches the dead tier
  tables. Legacy asking_to_sold_ratios DELETE+re-derive intact.
- tests: delete the tier-ratio unit test file (legacy path covered by
  test_estimator_expected_sold.py Layer 1); fix the daily-refresh fake-db
  (8→3 execute calls, 3 counter keys); drop the two segment-guard tests that
  asserted the removed tiered SQL; clean a dead per_rooms_tier basis in fixtures.

Tier tables asking_to_sold_ratios_tiered / asking_to_sold_tier_bounds + migration
098 are left in place (inert once nothing reads/writes them); a DROP migration is
a separate, optional follow-up.

Regression gate stays byte-identical (flag was False in prod → active path
unchanged). Refs #2002
lekss361 merged commit 50684ce87e into main 2026-06-27 17:34:54 +00:00
lekss361 deleted branch fix/tradein-remove-tier-ratio-footgun 2026-06-27 17:34:55 +00:00
lekss361 added the
priority/p2
scope/backend
tradein
labels 2026-06-27 17:34:55 +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#2015
No description provided.