refactor(tradein/estimator): extract deterministic pricing into pure _price_from_inputs (#1966 foundation) #1976

Merged
lekss361 merged 2 commits from refactor/tradein-estimator-price-spine into main 2026-06-27 10:13:34 +00:00
Owner

Summary

Foundation refactor for #1966 (accuracy-loop → CI gate). Extracts the deterministic pricing orchestration out of the async estimate_quality into a new pure, synchronous _price_from_inputs() — single source of truth — so the pricing spine becomes unit-testable and reusable by an offline backtest harness.

  • All DB/network fetches stay in estimate_quality; their results are injected into the pure function: pre-fetched objects (dkp_raw, imv_anchor, anchor_comps, imv_eval, presence flags for yandex/cian) + 3 thin callables (ratio_resolver, quarter_index_lookup, quarter_indexes_lookup) for lookups whose arguments are computed mid-block.
  • PricingResult dataclass (19 fields) carries everything estimate_quality consumes downstream (DB INSERT, analogs/anchor selection, freshness, AggregatedEstimate).
  • Behavior-preserving MOVE, not a rewrite. Mutation order unchanged: median→repair→anchor(+gates)→IMV-blend→quarter-index→corridor-clamp→expected_sold→advisory→coarse-geo.

Test plan

  • Full suite green, no existing test modified: 2443 passed, 2 skipped, 0 failures. (5 collection errors are pre-existing site-finder tests outside tradein-mvp, env-only — unrelated.)
  • New tests/test_estimator_price_spine.py (401 lines, hermetic/no-DB) covers: radius-only, anchor Tier A, Tier C corridor gate, ghost-anchor, quarter-index (apply + Guard-2 skip), corridor clamp, expected_sold presence/absence, coarse-geo downgrade.
  • code-reviewer: APPROVE — zero output divergence across 7 risk vectors (ratio timing, IMV pre-fetch, cian/yandex presence, quarter guards, mutation order, PricingResult completeness, psycopg/ruff).
  • ruff clean.

Unblocks PR2 (backtest harness on _price_from_inputs + range-coverage + confidence-calibration + frozen baseline) and PR3 (CI regression gate).

Part of #1966 (PR 1/3). Refs #1966.

## Summary Foundation refactor for #1966 (accuracy-loop → CI gate). Extracts the deterministic pricing orchestration out of the async `estimate_quality` into a new **pure, synchronous** `_price_from_inputs()` — single source of truth — so the pricing spine becomes unit-testable and reusable by an offline backtest harness. - All DB/network fetches stay in `estimate_quality`; their results are injected into the pure function: pre-fetched objects (`dkp_raw`, `imv_anchor`, `anchor_comps`, `imv_eval`, presence flags for yandex/cian) + 3 thin callables (`ratio_resolver`, `quarter_index_lookup`, `quarter_indexes_lookup`) for lookups whose arguments are computed mid-block. - `PricingResult` dataclass (19 fields) carries everything `estimate_quality` consumes downstream (DB INSERT, analogs/anchor selection, freshness, `AggregatedEstimate`). - **Behavior-preserving MOVE, not a rewrite.** Mutation order unchanged: median→repair→anchor(+gates)→IMV-blend→quarter-index→corridor-clamp→expected_sold→advisory→coarse-geo. ## Test plan - [x] Full suite green, **no existing test modified**: 2443 passed, 2 skipped, 0 failures. (5 collection errors are pre-existing site-finder tests outside `tradein-mvp`, env-only — unrelated.) - [x] New `tests/test_estimator_price_spine.py` (401 lines, hermetic/no-DB) covers: radius-only, anchor Tier A, Tier C corridor gate, ghost-anchor, quarter-index (apply + Guard-2 skip), corridor clamp, expected_sold presence/absence, coarse-geo downgrade. - [x] `code-reviewer`: ✅ APPROVE — zero output divergence across 7 risk vectors (ratio timing, IMV pre-fetch, cian/yandex presence, quarter guards, mutation order, PricingResult completeness, psycopg/ruff). - [x] ruff clean. Unblocks **PR2** (backtest harness on `_price_from_inputs` + range-coverage + confidence-calibration + frozen baseline) and **PR3** (CI regression gate). Part of #1966 (PR 1/3). Refs #1966.
lekss361 added 2 commits 2026-06-27 10:12:13 +00:00
refactor(tradein/estimator): extract deterministic pricing into pure _price_from_inputs (#1966 foundation)
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
2ea49b637f
Behavior-preserving structural refactor: the ~870-line deterministic pricing
block inside estimate_quality() is extracted into a new pure synchronous function
_price_from_inputs() returning a PricingResult dataclass.

Key design decisions:
- All async DB fetches (imv_eval, yandex_val, cian_val) hoisted to estimate_quality
  BEFORE the call; passed as pre-fetched values / bool flags.
- DB-dependent helpers whose arguments are computed inside the block (_get_asking_sold_ratio,
  _lookup_quarter_index, _lookup_quarter_indexes) injected as Callable parameters
  (ratio_resolver, quarter_index_lookup, quarter_indexes_lookup).
- _fetch_house_imv_anchor called once in estimate_quality (was two separate conditional
  calls inside the block); single result passed as imv_anchor dict.
- _fetch_dkp_corridor and _fetch_anchor_comps hoisted to estimate_quality with
  identical guards.

All 2443 existing tests pass UNMODIFIED. 9 new hermetic unit tests added that
call _price_from_inputs directly with stub callables.
lekss361 added the
scope/backend
tech-debt
tradein
labels 2026-06-27 10:12:50 +00:00
lekss361 merged commit b60df61f6a into main 2026-06-27 10:13:34 +00:00
lekss361 deleted branch refactor/tradein-estimator-price-spine 2026-06-27 10:13:34 +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#1976
No description provided.