feat(tradein): bulk sweep CLI for Yandex valuation house-history (EKB) #533
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#533
Loading…
Add table
Reference in a new issue
No description provided.
Delete branch "feat/tradein-yandex-valuation-bulk-sweep"
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
tradein-mvp/scripts/sweep-yandex-valuation-ekb.pylistings(source='yandex' AND region_code=66 AND is_active)_get_or_fetch_yandex_valuation_cached; pages 2..N go direct viaYandexValuationScraper.fetch_house_historyexternal_valuations.fetched_at < N daysCLI
Why now
With PRs #526 (parser fixes — removed_date, total_floors, NBSP) and #531 (house_id linking via
match_or_create_house) merged, one sweep will populatehouse_placement_historywith properly linked + complete rows. The current 160 orphan rows on prod (house_id=NULL,removed_date=NULL,total_floors=NULL) will be superseded as fresh runs hit those addresses again.Smoke validated
--helpparses, all CLI args wire correctlylocal-sweep-ekb-yandex.py)How to run (operator step, separate from this PR)
Deep Code Review — verdict ✅ APPROVE
Summary
Cross-file impact verified
app.services.estimator._get_or_fetch_yandex_valuation_cached— signature matches script call (db, kwaddress,offer_category,offer_type). Function commits internally + writesexternal_valuations.address✓ so theskip-recent-daysquery is sound.app.services.estimator._save_yandex_history_items— idempotent viaUNIQUE (source, ext_item_id),ON CONFLICT DO NOTHING. Re-runs are safe.app.services.scrapers.yandex_valuation.YandexValuationScraper.fetch_house_history(address, offer_category, offer_type, page)— matches script's page>=2 path.match_or_create_housealready serializes viapg_advisory_xact_lock(42, hashtext(fp))— concurrent sweeps for the SAME address won't dup-create houses.external_valuationsschema (sql/026):addresscolumn + partial idxev_address_idxcovers theNOT EXISTScorrelated subquery in_addresses_to_sweep.🟢 Strengths
try/except— one failure won't abort the run.--limit,--address,--skip-recent-days 0for force-reseed,--max-pagescap.--skip-recent-days 1skips already-processed addresses.🟡 Minor (informational, won't block)
tradein-mvp/scripts/sweep-yandex-valuation-ekb.py:106—_get_or_fetch_yandex_valuation_cachedis_underscore(module-private). Re-using it from an operator script is fine but creates a soft coupling; consider promoting to public name in a follow-up if these helpers grow more callers.tradein-mvp/scripts/sweep-yandex-valuation-ekb.py:127— early-break heuristiclen(result.history_items) < 13hardcodes Yandex page size. If Yandex changes page size, the sweep may stop early or burn extra page requests. Not a correctness bug; consider moving the magic number to a constant inyandex_valuation.pylater.--skip-recent-days 0only bypasses the address-selection skip; page=1 still goes through_get_or_fetch_yandex_valuation_cachedwhich honors the 24h cache TTL (expires_at > NOW()). So0does NOT force a Yandex fresh fetch on page 1 — it just re-saves already-cached items tohouse_placement_history. Behavior is fine + safe, but the help text could be clearer ("0 = no address-level skip; cache TTL still applies to page=1 fetch").tradein-mvp/scripts/sweep-yandex-valuation-ekb.py:122— broadexcept Exception: breakon per-page failure means a transient 429 on page 1 abandons the address entirely. Could be improved with one-shot retry, but operator can re-run with--skip-recent-days 1and the address will be retried. Acceptable for a manual script.🔒 Security: clean
text()bindparams.<PASS>placeholder.⚡ Performance: fine
SELECT DISTINCT address ... NOT EXISTS evcovered byev_address_idxpartial index.🧪 Tests
No tests added. Consistent with sibling
scripts/local-sweep-ekb-*.py— operator scripts are smoke-validated manually. Not blocking.Conventions
text()+ named bindparams ✓from __future__ import annotations✓tradein-mvp/scripts/✓weasyprint-stub +sys.pathinjection pattern fromlocal-sweep-ekb-yandex.py✓Recommended next steps (after merge)
--limit 5smoke on prod (per PR body).house_placement_historyfor the 160 orphan rows → expect new rows withhouse_idfilled.Complexity / blast radius