feat(tradein): estimator additive expected_sold price (#648 S3) #661

Merged
Light1YT merged 1 commit from feat/648-s3-estimator-expected-sold into main 2026-05-29 13:37:33 +00:00
Owner

Stage 3 of #648crown-jewel estimate path, purely additive. Estimator computes expected_sold_* = asking-median × per-rooms asking_to_sold_ratio (table #648 S2). Headline asking median/ranges/confidence/actual_deals UNCHANGED. Graceful: missing ratio table → expected_sold None + rollback (no tx-poison) → estimate still 200.

  • _get_asking_sold_ratio cached lookup (per-rooms → global -1 → None, try/except+rollback)
  • 6 optional schema fields; both reopen SELECTs + constructors rehydrate them (the documented reopen bug)
  • migration 081 ALTER ADD COLUMN IF NOT EXISTS ×6 (idempotent, #637 gate)

code-reviewer: ⚠️ (one finding — missing rollback in graceful path — FIXED). Additive guarantee + INSERT alignment (40/40) + rehydrate mapping verified.

Test plan

  • 46 estimator tests pass (10 new + fixed pre-existing quota 2→3 tuple); ruff clean
  • migration 081 dry-run prod (rollback): 6 cols added
  • Post-merge: smoke estimate returns expected_sold ≈ median×ratio, headline unchanged

Refs #648 (S3/5).

Stage 3 of #648 — **crown-jewel estimate path, purely additive**. Estimator computes `expected_sold_*` = asking-median × per-rooms `asking_to_sold_ratio` (table #648 S2). Headline asking median/ranges/confidence/actual_deals UNCHANGED. Graceful: missing ratio table → expected_sold None + rollback (no tx-poison) → estimate still 200. - `_get_asking_sold_ratio` cached lookup (per-rooms → global -1 → None, try/except+rollback) - 6 optional schema fields; both reopen SELECTs + constructors rehydrate them (the documented reopen bug) - migration 081 ALTER ADD COLUMN IF NOT EXISTS ×6 (idempotent, #637 gate) code-reviewer: ⚠️→✅ (one finding — missing rollback in graceful path — FIXED). Additive guarantee + INSERT alignment (40/40) + rehydrate mapping verified. ## Test plan - [x] 46 estimator tests pass (10 new + fixed pre-existing quota 2→3 tuple); ruff clean - [x] migration 081 dry-run prod (rollback): 6 cols added - [ ] Post-merge: smoke estimate returns expected_sold ≈ median×ratio, headline unchanged Refs #648 (S3/5).
Light1YT added 1 commit 2026-05-29 13:37:32 +00:00
Estimator ADDITIVELY derives expected_sold from asking-median × per-rooms
asking_to_sold_ratio (table from #648 S2 / migration 080). Headline asking
median, ranges, confidence and actual_deals are UNCHANGED. Graceful: missing/
empty ratio table → expected_sold fields None, estimate still returns 200
(ratio lookup rolls back the shared session on error so the subsequent INSERT
isn't poisoned — mirrors sibling cache helpers).

- estimator: _get_asking_sold_ratio(db, rooms) cached lookup (per-rooms →
  global -1 fallback → None, try/except+rollback), applied after repair-coef.
- schema: 6 optional expected_sold_* / ratio fields on AggregatedEstimate.
- api: rehydrate the new columns in GET /estimate/{id} + /pdf reopen SELECTs
  and both constructors (the documented reopen-path bug).
- migration 081: ADD COLUMN IF NOT EXISTS for the persisted subset.
- tests: 10 new (lookup/apply/graceful) + fix pre-existing test_estimator_
  source_quota 2→3 tuple unpack of _fetch_analogs (was RED on main).
Light1YT merged commit 35bd0238ef into main 2026-05-29 13:37:33 +00:00
Light1YT deleted branch feat/648-s3-estimator-expected-sold 2026-05-29 13:37:33 +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#661
No description provided.