fix(yandex-valuation): parse removed_date, fix total_floors regex, normalize NBSP #526
No reviewers
Labels
No labels
admin
analytics
auth
automation
bug
business
chore
ci
compliance
data
data-moat
docs
duplicate
dx
enhancement
Fable 5 ревью
feedback/max
generative
GG-форсайт
needs-discussion
needs-human
observability
pause-bots
performance
priority/p0
priority/p1
priority/p2
priority/p3
scope/backend
scope/db
scope/devops
scope/frontend
scope/qa
scrapers
security
site-finder
stage/1
stage/2
status/blocked
status/done
status/needs-analysis
status/needs-fix
status/qa
status/ready
status/review
status/wip
tech-debt
tradein
ux
week ревью 1
wontfix
вторичка
ИРД
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference: lekss361/gendesign#526
Loading…
Add table
Reference in a new issue
No description provided.
Delete branch "feat/tradein-yandex-valuation-parser-fixes"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Summary
removed_datefield toValuationHistoryItem(extracts 2nd DD.MM.YYYY in chunk)RE_FLOORS: singularэтаж→ pluralэтажей(was matching item-floor instead of dom-meta floors)parse()before regex (fixes*_price_per_m2= NULL bug)ValuationHouseMeta.validate_match()for cross-checking against expected houseWhy
Bugs observed on prod: 160 rows in
house_placement_historywith allremoved_date=NULL,total_floors=NULL,*_price_per_m2=NULL.Root causes:
parse_dmy()only returned first date — second date (removed_date) silently dropped.Tests
Followups (separate PRs)
house_placement_history.house_idFK (currently always NULL)Deep Code Review — PR #526
Summary
Three fixes — assessment
1.
removed_dateparsing — correct at parser levelre.finditer(r"\d{2}\.\d{2}\.\d{4}")collects ALL dates in chunk; first →publish_date, second →removed_date. Clean two-date semantics.(publish_date, area_m2, floor)mitigates duplicate rows but not phantom removed_date assignment. Real-page chunks are typically larger, so probably fine in practice; worth a regression probe after first prod sweep.2.
RE_FLOORSplural fix — correct, with one Russian-grammar edge case(\d+)\s+этажmatched item-level "4 этаж" first → wrong. New(\d+)\s+этажейcorrectly targets dom-meta plural form. Tests confirm.r"(\d+)\s+этаж(?:а|ей)?\b"combined with a check that it isn't inside an item context. Not blocking — explicit trade-off.3. NBSP normalization — correctly placed
parse()entry on both raw HTML (line 216) and body_text (line 219). Belt-and-suspenders (handles literal\xa0in source + entity-decoded post-selectolax). All downstream regexes see clean spaces.html.replace("\xa0", " ")is the canonical fix.parse_rub(m.group(1).replace(" ", "")only strips regular space —\xa0survives, breaksint()). Out of scope for this PR but worth a tracking note for the next cleanup sweep.Important — Persistence gap (callout, not blocker)
estimator._save_yandex_history_itemsINSERT (estimator.py:457-476) binds only:source, ext_item_id, rooms, area_m2, floor, start_price, start_price_date, last_price, last_price_date, exposure_days, raw_payloadremoved_dateandtotal_floorsare NOT in the column list, and therowsdict (lines 446-455) does NOT include them. After this PR merges:start_price/last_pricecolumns get correct values (NBSP-bearing prices were silently failingint()→ NULL in DB). Net positive.removed_dateparsed → persisted only intoraw_payloadJSON, NOT to the dedicatedhouse_placement_history.removed_datecolumn. The 160-row NULL situation described in the PR body will persist for the DB column until persistence is updated.total_floors— parsed intoValuationHouseMeta.total_floors, lives inraw_payloadJSON, buthouse_placement_history.total_floorscolumn is not bound on INSERT.Author's Followups section mentions PR #2 (
house_idFK) and PR #3 (sweep). Suggest adding a followup: extend_save_yandex_history_itemscolumn list withremoved_date,total_floors, and ensurelast_price_date = removed_date OR publish_datesohph_removed_idxgets populated.Low —
validate_matchhas no consumer yetValuationHouseMeta.validate_match()has 4 dedicated tests but no caller in repo. Looks intended for a future estimator integration (ambiguous-address geocode disambiguation). Fine as long as the followup arrives soon; otherwise dead code.Cross-file impact
yandex_valuation.pyis consumed byestimator.py(cache + persistence) andadmin.py(admin trigger endpoint). Both consumeresult.history_itemsandresult.housevia Pydantic; the new optionalremoved_datefield is backward-compatible (default None). No schema migration needed — column already exists from 017.history_items_countstill int).external_valuations.raw_payload) stores full Pydantic dump viamodel_dump(mode="json")—removed_dateround-trips correctly.model_validate(payload_dict)→removed_datedefaults to None on missing key. Backward-compat OK.Vault cross-check
Schema_YandexRealty_Recon.mdsec 12.5 + 13.2 (yandex_valuationas 4th source forhouse_placement_history).Decision_TradeIn_DataQuality_8PR_Roadmap/Event_TradeIn_DataQuality_8PR_Done_May24— PR #508 coveredlisting_dateparsing; this PR (#526) continues the same Yandex-parser hardening line.Tests
validate_matchpaths. Comprehensive.Verdict reasoning
All three fixes are correct at the parser level, well-tested, and backward-compatible. The persistence gap is real but explicitly outside the parser scope per author's Followups. Approving — please bake the persistence-extension followup soon so the prod NULL situation actually clears.
Good scope discipline; tests are tight.