- cian_detail.fetch_detail: add browser_fetcher keyword param (BrowserFetcher|None).
When provided, HTML is fetched via camoufox instead of curl_cffi. Parse path
is identical — only the HTML source changes.
- _extract_price_changes: extend to also look at offerData.priceChanges (browser
HTML location) and handle nested priceData.price format (proven on prod 2026-06-16:
listing 328647045 yields 10 entries).
- cian_history_backfill.backfill_cian_history: open one BrowserFetcher for the
batch and pass browser_fetcher=bf to each fetch_detail call; single-listing
failure does not abort the run.
- Tests: 6 new tests for browser_fetcher param + priceData.price format; 32 pass
total. Full gate: 1840 passed, 2 deselected.
Добавлено поле kitchen_area_m2 в DetailEnrichment dataclass,
извлечение через _parse_float(offer.get("kitchenArea")) в fetch_detail,
и COALESCE(CAST(:ka AS double precision), kitchen_area_m2) в UPDATE listings
внутри save_detail_enrichment.
Имя поля kitchenArea — стандартное cian offer API (live-verify не делался,
прокси недоступен в dev-окружении).
Closes#1553