Commit graph

1355 commits

Author SHA1 Message Date
7f732ff24d ci: drop push-on-feature-branch trigger to kill duplicate CI runs (#1709)
Some checks failed
CI / changes (pull_request) Successful in 6s
CI / frontend-tests (pull_request) Successful in 59s
CI / openapi-codegen-check (pull_request) Failing after 1m42s
CI / backend-tests (pull_request) Failing after 8m50s
Каждый коммит в ветку с открытым PR триггерил ДВА прогона ci.yml на один
SHA: push-событие (github.ref=refs/heads/<branch>) и pull_request-событие
(github.ref=refs/pull/<N>/merge). Разный github.ref → разные concurrency-
группы → прогоны не отменяли друг друга → 2x нагрузка на и так дефицитные
2 раннера (CI-шторм 2026-06-17, деплой tradein #1699 простоял 17 мин).

В bot-пайплайне каждый коммит идёт через PR, поэтому pull_request гейтит
его полностью; push-прогон был чистым дублем. Оставляю только pull_request:
теперь github.ref стабилен на весь PR и concurrency cancel-in-progress
корректно отменяет superseded-прогоны при новом пуше.

Refs #1709
2026-06-17 22:09:01 +03:00
0fb70f2f90 Merge pull request 'fix(sql): EMISS PK includes period_type so yearly+Q1 coexist (#1606 follow-up)' (#1706) from fix/emiss-pk-granularity-1687 into main
Some checks failed
Deploy / changes (push) Successful in 7s
Deploy / build-backend (push) Successful in 1m45s
Deploy / build-frontend (push) Has been skipped
Deploy / deploy (push) Has been cancelled
Deploy / build-worker (push) Has been cancelled
2026-06-17 18:46:00 +00:00
2659600374 fix(sql): emiss backfill period_type='quarter' to match scraper (#1606 review)
Some checks failed
CI / changes (push) Successful in 9s
CI / changes (pull_request) Successful in 7s
CI / frontend-tests (push) Has been skipped
CI / openapi-codegen-check (push) Failing after 1m37s
CI / frontend-tests (pull_request) Has been skipped
CI / openapi-codegen-check (pull_request) Failing after 1m35s
CI / backend-tests (push) Failing after 8m53s
CI / backend-tests (pull_request) Failing after 8m41s
2026-06-17 21:45:12 +03:00
8022be6b2f Merge pull request 'fix(leads): replace ::interval cast with make_interval (psycopg v3 trap) (#1383 follow-up)' (#1707) from fix/admin-leads-interval-cast-1694 into main
Some checks failed
Deploy / changes (push) Successful in 7s
Deploy / build-backend (push) Has been cancelled
Deploy / build-worker (push) Has been cancelled
Deploy / build-frontend (push) Has been cancelled
Deploy / deploy (push) Has been cancelled
2026-06-17 18:42:11 +00:00
16990af11c Merge pull request 'docs(estimator): DKP corridor described as P10/P90 not min/max in schema+TS (#1520 follow-up)' (#1708) from fix/dkp-corridor-doc-p10p90-1695 into main
Some checks failed
Deploy / changes (push) Waiting to run
Deploy / build-backend (push) Blocked by required conditions
Deploy / build-worker (push) Blocked by required conditions
Deploy / build-frontend (push) Blocked by required conditions
Deploy / deploy (push) Blocked by required conditions
Deploy Trade-In / changes (push) Successful in 7s
Deploy Trade-In / test (push) Has been cancelled
Deploy Trade-In / build-backend (push) Has been cancelled
Deploy Trade-In / build-frontend (push) Has been cancelled
Deploy Trade-In / build-browser (push) Has been cancelled
Deploy Trade-In / deploy (push) Has been cancelled
2026-06-17 18:42:10 +00:00
584aa46f6f Merge pull request 'fix(admin-scrape): ge=1 on /failures limit + enforce LLM finish_reason' (#1701) from fix/admin-scrape-validation into main
Some checks are pending
Deploy / changes (push) Waiting to run
Deploy / build-backend (push) Blocked by required conditions
Deploy / build-worker (push) Blocked by required conditions
Deploy / build-frontend (push) Blocked by required conditions
Deploy / deploy (push) Blocked by required conditions
2026-06-17 18:35:35 +00:00
6bf1042171 Merge pull request 'fix(llm): word-boundary INN match, tighten edge cases (#1640 follow-up)' (#1703) from fix/inn-regex-word-boundary-1682 into main
Some checks are pending
Deploy / changes (push) Waiting to run
Deploy / build-backend (push) Blocked by required conditions
Deploy / build-worker (push) Blocked by required conditions
Deploy / build-frontend (push) Blocked by required conditions
Deploy / deploy (push) Blocked by required conditions
2026-06-17 18:34:52 +00:00
3d2d6d5da2 Merge pull request 'fix(exporters): annotate scenario deficit horizon in excel too (#1590 follow-up)' (#1702) from fix/excel-deficit-horizon-1590 into main
Some checks are pending
Deploy / changes (push) Waiting to run
Deploy / build-backend (push) Blocked by required conditions
Deploy / build-worker (push) Blocked by required conditions
Deploy / build-frontend (push) Blocked by required conditions
Deploy / deploy (push) Blocked by required conditions
2026-06-17 18:34:47 +00:00
9e6b0b1786 Merge pull request 'fix(weather): wind_d returns None when no valid samples, not fabricated 0.0°' (#1700) from fix/weather-wind-d-allnone into main
Some checks are pending
Deploy / changes (push) Waiting to run
Deploy / build-backend (push) Blocked by required conditions
Deploy / build-worker (push) Blocked by required conditions
Deploy / build-frontend (push) Blocked by required conditions
Deploy / deploy (push) Blocked by required conditions
2026-06-17 18:34:45 +00:00
be33faf73e Merge pull request 'fix(scrapers): narrow domrf Level-1 status badge-class regex (#1609 follow-up)' (#1704) from fix/domrf-badge-regex-narrow-1686 into main
Some checks are pending
Deploy / changes (push) Waiting to run
Deploy / build-backend (push) Blocked by required conditions
Deploy / build-worker (push) Blocked by required conditions
Deploy / build-frontend (push) Blocked by required conditions
Deploy / deploy (push) Blocked by required conditions
2026-06-17 18:34:32 +00:00
ae6d86d9cc Merge pull request 'test(site-finder): cover is_residential_zone raw_props/subcategory branch (#1353 follow-up)' (#1705) from test/residential-zone-rawprops-1681 into main
Some checks are pending
Deploy / build-backend (push) Blocked by required conditions
Deploy / build-worker (push) Blocked by required conditions
Deploy / deploy (push) Blocked by required conditions
Deploy / changes (push) Waiting to run
Deploy / build-frontend (push) Blocked by required conditions
2026-06-17 18:34:30 +00:00
e5d78b5e53 Merge pull request 'feat(yandex): route gate-API fetch through camoufox (sustainable, no proxy burn)' (#1699) from feat/yandex-camoufox-transport into main
Some checks are pending
Deploy Trade-In / changes (push) Waiting to run
Deploy Trade-In / test (push) Blocked by required conditions
Deploy Trade-In / build-backend (push) Blocked by required conditions
Deploy Trade-In / build-browser (push) Blocked by required conditions
Deploy Trade-In / deploy (push) Blocked by required conditions
Deploy Trade-In / build-frontend (push) Blocked by required conditions
2026-06-17 18:28:50 +00:00
c514b992ee Merge pull request 'fix(site-finder): remove dead sat_factor (computed+written, never applied) (#1509)' (#1698) from fix/score-sat-factor-1509 into main
Some checks are pending
Deploy / changes (push) Waiting to run
Deploy / build-backend (push) Blocked by required conditions
Deploy / build-worker (push) Blocked by required conditions
Deploy / build-frontend (push) Blocked by required conditions
Deploy / deploy (push) Blocked by required conditions
2026-06-17 18:28:45 +00:00
5170107405 fix(sql): EMISS PK includes period_type so yearly+Q1 coexist (#1606 follow-up)
Some checks failed
CI / backend-tests (push) Has been cancelled
CI / frontend-tests (push) Has been cancelled
CI / openapi-codegen-check (push) Has been cancelled
CI / changes (push) Has been cancelled
CI / changes (pull_request) Successful in 6s
CI / backend-tests (pull_request) Has been cancelled
CI / frontend-tests (pull_request) Has been cancelled
CI / openapi-codegen-check (pull_request) Has been cancelled
Adds period_type TEXT NOT NULL DEFAULT 'unknown' to macro_indicator and
widens the PRIMARY KEY to (indicator_type, region, obs_date, period_type).

Before: yearly aggregate ('год'→obs_date YYYY-01-01) and Q1 ('I квартал'→
same date) shared the same PK slot → ON CONFLICT DO UPDATE made them
overwrite each other despite the in-memory dedup fix in #1687.

After: each EmissRow carries period_type from _emiss_period_granularity
('year'/'quarter'/'month'); DB ON CONFLICT targets include it, so
yearly+Q1 rows genuinely coexist.

Non-EMISS sources (CBR, rosstat open-data, domrf) use period_type='unknown'
(literal in SQL) — they are disambiguated by obs_date already, so the
wider PK is backward-compatible. All ON CONFLICT clauses in
cbr_macro_sync.py and rosstat_macro_sync.py updated accordingly.

Migration: 163_emiss_pk_period_type.sql (idempotent BEGIN/COMMIT).
Tests: 49 passed (emiss + rosstat suite), ruff clean, py_compile OK.
2026-06-17 21:27:34 +03:00
4309a12c67 fix(llm): word-boundary INN match, tighten edge cases (#1640 follow-up)
Some checks failed
CI / backend-tests (push) Has been cancelled
CI / frontend-tests (push) Has been cancelled
CI / openapi-codegen-check (push) Has been cancelled
CI / changes (push) Has been cancelled
CI / changes (pull_request) Has been cancelled
CI / backend-tests (pull_request) Has been cancelled
CI / frontend-tests (pull_request) Has been cancelled
CI / openapi-codegen-check (pull_request) Has been cancelled
Replace (?<!\d)/(?!\d) lookarounds on the digit block in _INN_RE with
(?<!\w)/(?!\w). The old (?<!\d) did not block alpha-prefixed tokens
(e.g. «ИНН ref7707083893»), and (?!\d) did not block alpha-suffixed
tokens (e.g. «ИНН 7707083893more»). \b is unsuitable here because
Python \w covers both letters and digits, so there is no \b boundary
between an alpha char and a digit char. The (?<!\w)/(?!\w) pair
correctly anchors the 10/12-digit INN block to non-word boundaries on
both sides. Context anchor and checksum gate from #1640 are unchanged.

Adds 6 regression tests covering: alpha-prefix, alpha-suffix,
embedded mid-token, 12-digit alpha-prefix, punctuation separator
(should match), and end-of-string (should match).
2026-06-17 21:24:59 +03:00
c54502ebf8 fix(exporters): annotate scenario deficit horizon in excel too (#1590 follow-up)
Some checks failed
CI / backend-tests (push) Has been cancelled
CI / frontend-tests (push) Has been cancelled
CI / openapi-codegen-check (push) Has been cancelled
CI / changes (push) Has been cancelled
CI / changes (pull_request) Has been cancelled
CI / backend-tests (pull_request) Has been cancelled
CI / frontend-tests (pull_request) Has been cancelled
CI / openapi-codegen-check (pull_request) Has been cancelled
excel.py рендерил _scenario_deficit_index (скаляр) в таблицу сценариев под
шапкой «(12 мес)» — при fallback на другой горизонт подпись лгала (то же что
docx/pptx до 764db617). Добавлены _scenario_deficit_horizon и
_scenario_deficit_cell (зеркало report_pdf.py/764db617): при fallback ячейка
несёт «(гор. N мес)». _build_scenarios_sheet переключён на _scenario_deficit_cell.
Тесты: два новых кейса — fallback (6 мес → аннотация) и primary (12 мес → скаляр).
2026-06-17 21:23:57 +03:00
145dc62e0b fix(admin-scrape): ge=1 on count param + enforce LLM finish_reason (#review-followup)
Some checks failed
CI / changes (push) Has been cancelled
CI / backend-tests (push) Has been cancelled
CI / frontend-tests (push) Has been cancelled
CI / openapi-codegen-check (push) Has been cancelled
CI / backend-tests (pull_request) Has been cancelled
CI / frontend-tests (pull_request) Has been cancelled
CI / openapi-codegen-check (pull_request) Has been cancelled
CI / changes (pull_request) Has been cancelled
- admin_scrape.py /failures limit: ge=0 → ge=1 (returning 0 rows is nonsensical for a list endpoint)
- orchestrator.py: check result.finish_reason after ok=True; 'length'/'content_filter' and any
  other non-stop reason triggers deterministic fallback with reason=finish_reason:<value>
  (LLMResult docstring mandated this but no consumer enforced it)
2026-06-17 21:23:13 +03:00
bcb348da40 fix(leads): replace ::interval cast with make_interval (psycopg v3 trap) (#1383 follow-up)
Some checks failed
CI / changes (push) Has been cancelled
CI / backend-tests (push) Has been cancelled
CI / frontend-tests (push) Has been cancelled
CI / openapi-codegen-check (push) Has been cancelled
CI / changes (pull_request) Successful in 8s
CI / backend-tests (pull_request) Has been cancelled
CI / frontend-tests (pull_request) Has been cancelled
CI / openapi-codegen-check (pull_request) Has been cancelled
(:bind || ' months')::interval is a psycopg v3 SyntaxError — the driver
sees '::' immediately after the bind placeholder token and chokes.
Replace all 6 occurrences (admin_leads.py + analytics_queries.py) with
make_interval(months => :bind) which is unambiguous to the parser and
semantically identical.
2026-06-17 21:22:53 +03:00
f1c5056397 docs(estimator): DKP corridor described as P10/P90 not min/max in schema+TS (#1520 follow-up)
Some checks failed
CI / backend-tests (push) Has been cancelled
CI / frontend-tests (push) Has been cancelled
CI / openapi-codegen-check (push) Has been cancelled
CI / changes (push) Has been cancelled
CI / backend-tests (pull_request) Has been cancelled
CI / frontend-tests (pull_request) Has been cancelled
CI / openapi-codegen-check (pull_request) Has been cancelled
CI / changes (pull_request) Has been cancelled
2026-06-17 21:22:49 +03:00
6cf65eb26b fix(weather): wind_d returns None when no valid samples, not fabricated 0.0° (#weather-cache)
Some checks failed
CI / changes (push) Has been cancelled
CI / backend-tests (push) Has been cancelled
CI / frontend-tests (push) Has been cancelled
CI / openapi-codegen-check (push) Has been cancelled
CI / backend-tests (pull_request) Has been cancelled
CI / frontend-tests (pull_request) Has been cancelled
CI / openapi-codegen-check (pull_request) Has been cancelled
CI / changes (pull_request) Has been cancelled
When all winddirection_10m_dominant samples were None (or the key was
absent), atan2(0, 0) produced 0.0° (due north) as a fabricated value.
Root causes:
  1. [None, None, ...] is truthy → entered circular-mean branch, but
     filtered sums x=y=0 → atan2(0,0)=0 → 0.0°
  2. Empty list → else 0.0 branch → same fabrication

Fix: filter None from wind_d before aggregation (consistent with t_max /
t_min / uv). Only compute circular mean when at least one valid sample
exists; otherwise dominant_direction_deg and dominant_direction_label are
None. Adds TestWindDirectionAllNone covering all-None, missing key, valid
samples sanity, and mixed None+valid cases.
2026-06-17 21:22:31 +03:00
827459e72a test(site-finder): cover is_residential_zone raw_props/subcategory branch (#1353 follow-up)
Some checks failed
CI / changes (push) Has been cancelled
CI / backend-tests (push) Has been cancelled
CI / frontend-tests (push) Has been cancelled
CI / openapi-codegen-check (push) Has been cancelled
CI / changes (pull_request) Successful in 5s
CI / frontend-tests (pull_request) Has been skipped
CI / openapi-codegen-check (pull_request) Failing after 1m46s
CI / backend-tests (pull_request) Failing after 8m53s
2026-06-17 21:22:04 +03:00
c3c89646ce fix(scrapers): narrow domrf Level-1 status badge-class regex (#1609 follow-up)
Some checks failed
CI / changes (push) Successful in 8s
CI / changes (pull_request) Has been cancelled
CI / backend-tests (pull_request) Has been cancelled
CI / frontend-tests (pull_request) Has been cancelled
CI / openapi-codegen-check (pull_request) Has been cancelled
CI / backend-tests (push) Has been cancelled
CI / frontend-tests (push) Has been cancelled
CI / openapi-codegen-check (push) Has been cancelled
_STATUS_BADGE_CLS_RE was too broad: `status|badge|tag|chip|label` matched
generic UI elements (e.g. <span class="label">, <span class="chip">) that
are unrelated to the sale-status badge, risking picking the wrong block.

Narrowed to `(?<![a-z])status(?![a-z])` — requires the literal token
"status" as a hyphen-delimited component of the CSS class (matches
`status-badge`, `flat-status-tag`, `object-status` but not bare `label`,
`tag`, `chip`, `badge`).

Adds regression test: page with generic label/tag/chip/badge elements
containing "В продаже" must NOT activate Level-1; only the real
`status-badge` block ("Продана") should be returned → status=sold.
2026-06-17 21:21:56 +03:00
a8d7be68ad feat(yandex): route gate-API fetch through camoufox BrowserFetcher
Some checks failed
CI / changes (push) Has been cancelled
CI / backend-tests (push) Has been cancelled
CI / frontend-tests (push) Has been cancelled
CI / openapi-codegen-check (push) Has been cancelled
CI / changes (pull_request) Has been cancelled
CI / backend-tests (pull_request) Has been cancelled
CI / frontend-tests (pull_request) Has been cancelled
CI / openapi-codegen-check (pull_request) Has been cancelled
Replace the system-curl SOCKS5 subprocess transport with the shared
BrowserFetcher (camoufox). camoufox's real-browser fingerprint is not
tarpitted by yandex and does not burn the mobile-proxy IP; raw system-curl
got the proxy IP flagged.

One BrowserFetcher is opened per scraper session in __aenter__ and reused
across all page fetches. _http_get now fetches via the browser, extracts the
gate-API JSON from camoufox's HTML <pre> wrapper, and returns it as the body
of a _CurlResponse (status 200 on success, 0 on fetch/extraction failure) so
all existing callers and the tarpit retry/rotate logic keep working unchanged.

URL building, _parse_gate_json, pagination, combos and field mapping are
untouched. Removed the dead curl subprocess constants/method.
2026-06-17 21:16:48 +03:00
f55e83a150 Merge pull request 'fix(site-finder): NO_ENGINEERING_NEARBY is a warning, not a verdict blocker (#1617)' (#1697) from fix/gate-verdict-no-blocker-1617 into main
Some checks are pending
Deploy / changes (push) Waiting to run
Deploy / build-backend (push) Blocked by required conditions
Deploy / build-worker (push) Blocked by required conditions
Deploy / build-frontend (push) Blocked by required conditions
Deploy / deploy (push) Blocked by required conditions
2026-06-17 18:11:44 +00:00
9e5086890f fix(site-finder): remove dead sat_factor (computed+written, never applied) (#1509)
Some checks failed
CI / changes (pull_request) Has been cancelled
CI / backend-tests (pull_request) Has been cancelled
CI / frontend-tests (pull_request) Has been cancelled
CI / openapi-codegen-check (pull_request) Has been cancelled
CI / changes (push) Successful in 8s
CI / backend-tests (push) Has been cancelled
CI / frontend-tests (push) Has been cancelled
CI / openapi-codegen-check (push) Has been cancelled
sat_factor = 1 + ((sold_pct-50)/100)*0.30 was computed in 09_macro_and_trend.py,
written to district_economics.sat_factor, and fetched in server.py and 10_score_v2.py
— but never multiplied into any score. The live market sub-score uses a separate
sat_score = min(100, sold_pct*100/70) directly, so sat_factor was dead code that
would double-count absorption if ever wired in.

- 09_macro_and_trend.py: remove sat_factor computation, ALTER TABLE column, UPDATE
  binding, and debug print column
- 10_score_v2.py: remove sat_factor from SELECT and unpacking
- server.py: remove sat_factor variable assignment and from macro_factors response
- static/index.html: remove sat_factor documentation row
- data/sql/162_drop_district_economics_sat_factor.sql: DROP COLUMN IF EXISTS
2026-06-17 21:08:54 +03:00
96f42cd033 Merge pull request 'fix(forecasting): thread room_bucket velocity into format ranking (#1593)' (#1696) from fix/base-pace-room-bucket-1593 into main
Some checks are pending
Deploy / changes (push) Waiting to run
Deploy / build-backend (push) Blocked by required conditions
Deploy / build-worker (push) Blocked by required conditions
Deploy / build-frontend (push) Blocked by required conditions
Deploy / deploy (push) Blocked by required conditions
2026-06-17 18:08:26 +00:00
ec0d80c1e9 fix(forecasting): wrap long lines, guard window_months=0, correct base_pace fallback comment (#1593 review)
Some checks failed
CI / backend-tests (push) Has been cancelled
CI / frontend-tests (push) Has been cancelled
CI / openapi-codegen-check (push) Has been cancelled
CI / changes (push) Has been cancelled
CI / backend-tests (pull_request) Has been cancelled
CI / changes (pull_request) Has been cancelled
CI / openapi-codegen-check (pull_request) Has been cancelled
CI / frontend-tests (pull_request) Has been cancelled
- Add window_months > 0 guard to vel_by_room dict comprehension (mirrors _monthly_rate)
- Correct outer comment in recommendation.py: honest-zero for known-zero buckets,
  fallback only when velocity_by_room=None or bucket absent from _FORECAST_TO_METRIC_BUCKETS
- Add comment in as_dict() noting velocity_by_room is intentionally not serialized
  (internal pipeline attr consumed directly by recommendation.py)
2026-06-17 21:07:55 +03:00
7fdbca2666 Merge pull request 'fix(leads): window revenue_total/deals_total to leads_window (#1383)' (#1694) from fix/leads-stats-window-1383 into main
Some checks are pending
Deploy / changes (push) Waiting to run
Deploy / build-backend (push) Blocked by required conditions
Deploy / build-worker (push) Blocked by required conditions
Deploy / build-frontend (push) Blocked by required conditions
Deploy / deploy (push) Blocked by required conditions
2026-06-17 18:05:51 +00:00
624c88c13a Merge pull request 'fix(site-finder): apply 12mo cutoff to n_lots/sold_pct/price in enrich economics (#1513)' (#1691) from fix/enrich-economics-window-1513 into main 2026-06-17 18:05:45 +00:00
262adbf762 Merge pull request 'fix(estimator): DKP corridor uses P10/P90 not min/max (#1520)' (#1695) from fix/dkp-corridor-percentile-1520 into main
Some checks are pending
Deploy Trade-In / changes (push) Waiting to run
Deploy Trade-In / test (push) Blocked by required conditions
Deploy Trade-In / build-backend (push) Blocked by required conditions
Deploy Trade-In / build-frontend (push) Blocked by required conditions
Deploy Trade-In / build-browser (push) Blocked by required conditions
Deploy Trade-In / deploy (push) Blocked by required conditions
2026-06-17 18:05:39 +00:00
1fffb7a0a7 Merge pull request 'fix(sql): restore partial WHERE is_active predicate on listings indexes (#1398)' (#1693) from fix/listings-partial-indexes-1398 into main
Some checks are pending
Deploy Trade-In / changes (push) Waiting to run
Deploy Trade-In / test (push) Blocked by required conditions
Deploy Trade-In / build-backend (push) Blocked by required conditions
Deploy Trade-In / build-frontend (push) Blocked by required conditions
Deploy Trade-In / build-browser (push) Blocked by required conditions
Deploy Trade-In / deploy (push) Blocked by required conditions
2026-06-17 18:05:30 +00:00
4d878bd11d Merge pull request 'fix(site-finder): smart_suggestions filter parcels above documented score threshold (#1503)' (#1692) from fix/smart-suggestions-threshold-1503 into main 2026-06-17 18:05:23 +00:00
40c58c15b1 Merge pull request 'fix(site-finder): volume-weighted median_price_m2 (#1511) + consistent-period MTS (#1512)' (#1690) from fix/match-economics-1511-1512 into main 2026-06-17 18:05:14 +00:00
ac19ef4823 fix(site-finder): NO_ENGINEERING_NEARBY is a warning, not a verdict blocker (#1617)
Some checks failed
CI / changes (push) Successful in 9s
CI / changes (pull_request) Successful in 7s
CI / frontend-tests (push) Has been skipped
CI / backend-tests (pull_request) Has been cancelled
CI / openapi-codegen-check (push) Failing after 1m40s
CI / frontend-tests (pull_request) Has been cancelled
CI / openapi-codegen-check (pull_request) Has been cancelled
CI / backend-tests (push) Failing after 8m47s
Introduce INFORMATIONAL_WARNING_CODES frozenset; verdict assembly now only
downgrades to «С ограничениями» when verdict-relevant warnings exist.
NO_ENGINEERING_NEARBY still appears in warnings[] for display but a clean
residential parcel (Ж-zone, no ЗОУИТ) correctly receives verdict_label=«Можно».
2026-06-17 20:59:32 +03:00
86d0475f45 Merge pull request 'fix(forecasting): deal_count confidence note carries «за N мес» window (#1637)' (#1684) from fix/confidence-deal-count-window-1637 into main
Some checks are pending
Deploy / build-frontend (push) Blocked by required conditions
Deploy / deploy (push) Blocked by required conditions
Deploy / build-backend (push) Blocked by required conditions
Deploy / build-worker (push) Blocked by required conditions
Deploy / changes (push) Successful in 8s
2026-06-17 17:57:41 +00:00
ac47cd73a6 fix(forecasting): wire deal_count_months from market window into confidence note (#1637)
Some checks failed
CI / changes (push) Successful in 9s
CI / changes (pull_request) Successful in 8s
CI / backend-tests (push) Has been skipped
CI / frontend-tests (push) Has been skipped
CI / openapi-codegen-check (push) Has been skipped
CI / frontend-tests (pull_request) Has been skipped
CI / openapi-codegen-check (pull_request) Successful in 1m39s
CI / backend-tests (pull_request) Has been cancelled
`_build_confidence` was calling `compute_report_confidence` without
`deal_count_months`, so the «за N мес» suffix never appeared in
production. Add `_deal_count_months(market_metrics)` extractor
(reads `window_months`, same key as `_history_months`) and pass it.
Also fix pre-existing UP038 violations (isinstance tuple → X | Y).
2026-06-17 20:57:05 +03:00
9a0ca9336f Merge pull request 'fix(scrapers): scope+stem domrf status classification (#1609)' (#1686) from fix/domrf-status-classify-1609 into main
Some checks are pending
Deploy / build-frontend (push) Blocked by required conditions
Deploy / deploy (push) Blocked by required conditions
Deploy / changes (push) Waiting to run
Deploy / build-backend (push) Blocked by required conditions
Deploy / build-worker (push) Blocked by required conditions
2026-06-17 17:55:42 +00:00
5c44233ed6 Merge pull request 'fix(scrapers): cian _walk_price_range stop silently truncating tail (#1393)' (#1689) from fix/cian-paginate-tail-1393 into main
Some checks are pending
Deploy Trade-In / test (push) Blocked by required conditions
Deploy Trade-In / build-backend (push) Blocked by required conditions
Deploy Trade-In / build-frontend (push) Blocked by required conditions
Deploy Trade-In / build-browser (push) Blocked by required conditions
Deploy Trade-In / deploy (push) Blocked by required conditions
Deploy Trade-In / changes (push) Successful in 7s
2026-06-17 17:55:36 +00:00
cc6ef80d07 fix(forecasting): thread room_bucket into base_pace/compute_market_metrics for real format ranking (#1593)
Some checks failed
CI / backend-tests (push) Blocked by required conditions
CI / frontend-tests (push) Blocked by required conditions
CI / openapi-codegen-check (push) Blocked by required conditions
CI / changes (push) Successful in 8s
CI / changes (pull_request) Successful in 8s
CI / frontend-tests (pull_request) Has been skipped
CI / openapi-codegen-check (pull_request) Successful in 1m42s
CI / backend-tests (pull_request) Has been cancelled
Add `velocity_by_room: dict[str, float] | None` to `MarketMetrics` — per-bucket
unit velocity (ед./мес) derived from the existing `sold_by_room` ROLLUP data that
`_query_sales_window` already returns. No new SQL required.

Thread per-bucket velocity through `_demand_only_overlay` via the new
`_FORECAST_TO_METRIC_BUCKETS` constant that maps each forecast bucket to its
market_metrics room-bucket keys. "80+ м²" sums "4" + "5+" keys. Fallback to
aggregate `unit_velocity` when `velocity_by_room` is None (thin-data path).

Previously `base_pace` was identical for all 5 room-buckets, so §9.4 norm and §9.2
base_pace cancelled out in pace/max_pace and ranking was driven purely by §9.5
macro_coef (segment steepness proxy). Now §9.2 reflects real per-bucket observed
demand from objective_lots.contract_date data.

Callers of `compute_market_metrics` that don't use `velocity_by_room` are unaffected
(the new field is additive to the frozen dataclass). All existing callers verified —
none construct `MarketMetrics` directly except the one production site.
2026-06-17 20:55:34 +03:00
7d8d12f5a6 Merge pull request 'fix(sql): v_supply_layers_latest keep dev_group_name in DISTINCT ON key (#1650)' (#1688) from fix/supply-view-devgroup-key-1650 into main
Some checks are pending
Deploy / build-frontend (push) Blocked by required conditions
Deploy / deploy (push) Blocked by required conditions
Deploy / changes (push) Waiting to run
Deploy / build-backend (push) Blocked by required conditions
Deploy / build-worker (push) Blocked by required conditions
2026-06-17 17:55:31 +00:00
435f7249d0 Merge pull request 'fix(scrapers): disambiguate EMISS yearly vs Q1 in dedup key (#1606)' (#1687) from fix/emiss-period-dedup-1606 into main
Some checks are pending
Deploy / changes (push) Waiting to run
Deploy / build-backend (push) Blocked by required conditions
Deploy / build-worker (push) Blocked by required conditions
Deploy / build-frontend (push) Blocked by required conditions
Deploy / deploy (push) Blocked by required conditions
2026-06-17 17:55:27 +00:00
b92d3aeb65 Merge pull request 'fix(forecasting): correct _geo_weight unknown floor so far projects rank low (#1633)' (#1685) from fix/geo-weight-floor-1633 into main
Some checks are pending
Deploy / build-frontend (push) Blocked by required conditions
Deploy / deploy (push) Blocked by required conditions
Deploy / changes (push) Waiting to run
Deploy / build-backend (push) Blocked by required conditions
Deploy / build-worker (push) Blocked by required conditions
2026-06-17 17:55:17 +00:00
a1adf2fd19 Merge pull request 'fix(forecasting): count non-zero observations in normalize guard (#1638)' (#1683) from fix/normalize-zero-fill-guard-1638 into main
Some checks are pending
Deploy / changes (push) Waiting to run
Deploy / build-backend (push) Blocked by required conditions
Deploy / build-worker (push) Blocked by required conditions
Deploy / build-frontend (push) Blocked by required conditions
Deploy / deploy (push) Blocked by required conditions
2026-06-17 17:55:12 +00:00
c0454d8905 Merge pull request 'fix(llm): INN redaction requires context anchor, stop eating large numbers (#1640)' (#1682) from fix/inn-regex-context-1640 into main
Some checks are pending
Deploy / changes (push) Waiting to run
Deploy / build-backend (push) Blocked by required conditions
Deploy / build-worker (push) Blocked by required conditions
Deploy / build-frontend (push) Blocked by required conditions
Deploy / deploy (push) Blocked by required conditions
2026-06-17 17:55:06 +00:00
e075f01870 Merge pull request 'fix(site-finder): robust is_residential_zone detection for NSPD zone codes (#1353)' (#1681) from fix/residential-zone-detect-1353 into main
Some checks are pending
Deploy / changes (push) Waiting to run
Deploy / build-backend (push) Blocked by required conditions
Deploy / build-worker (push) Blocked by required conditions
Deploy / build-frontend (push) Blocked by required conditions
Deploy / deploy (push) Blocked by required conditions
2026-06-17 17:55:01 +00:00
f826a37345 Merge pull request 'fix(parcels): _score_label honor «хорошо»=25→«отлично» boundary (#1357)' (#1680) from fix/score-label-threshold-1357 into main
Some checks are pending
Deploy / changes (push) Waiting to run
Deploy / build-backend (push) Blocked by required conditions
Deploy / build-worker (push) Blocked by required conditions
Deploy / build-frontend (push) Blocked by required conditions
Deploy / deploy (push) Blocked by required conditions
2026-06-17 17:54:57 +00:00
7d5962e7b4 Merge pull request 'fix(site-finder): normalize POI weighted score to 0..100 on backend (#1486)' (#1674) from fix/poi-score-scale-1486 into main
Some checks are pending
Deploy / changes (push) Waiting to run
Deploy / build-backend (push) Blocked by required conditions
Deploy / build-worker (push) Blocked by required conditions
Deploy / build-frontend (push) Blocked by required conditions
Deploy / deploy (push) Blocked by required conditions
2026-06-17 17:54:52 +00:00
6d550e00b2 fix(site-finder): volume-weighted median_price_m2 (#1511) + consistent-period months_to_sellout (#1512)
All checks were successful
CI / changes (push) Successful in 7s
CI / changes (pull_request) Successful in 7s
CI / backend-tests (push) Has been skipped
CI / frontend-tests (push) Has been skipped
CI / openapi-codegen-check (push) Has been skipped
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
#1511: replace equal-weight per-row median with volume-weighted median
(sorted by price, cumulative sold_volume_m2 weight, stop at 50th percentile).
Each corpus×month row now counts proportionally to its deal volume instead of
contributing equal weight regardless of how many flats were sold.

#1512: pin latest_stock to the single most-recent month in the window (last3[0])
instead of per-corpus ROW_NUMBER latest. Stale stock from inactive corpuses no
longer inflates the MTS numerator; stock and sold_volume_m2 denominator now
refer to the same consistent period.

Also clean pre-existing ruff E401/E701/E702/E722 violations (no logic change).
2026-06-17 20:52:47 +03:00
403020ad56 fix(sql): restore partial predicate on 5 listings indexes (#1398)
All checks were successful
CI / changes (push) Successful in 7s
CI / changes (pull_request) Successful in 8s
CI / backend-tests (push) Has been skipped
CI / frontend-tests (push) Has been skipped
CI / openapi-codegen-check (push) Has been skipped
CI / frontend-tests (pull_request) Has been skipped
CI / backend-tests (pull_request) Has been skipped
CI / openapi-codegen-check (pull_request) Has been skipped
097_index_hygiene.sql de-partialized 5 listings indexes on the false premise
that is_active=100% true. 104_index_hygiene_geom_dedup.sql acknowledged the
premise is stale (49% active on prod, 2026-06-13) but only cleaned up the
redundant geom duplicate, leaving 3 composite indexes full.

Restore WHERE is_active=true on the composite hot-path indexes:
- listings_active_filter_idx (rooms, price_rub, area_m2, scraped_at DESC)
- listings_house_price_idx   (house_id_fk, price_rub)
- listings_rooms_area_idx    (rooms, area_m2)

Excluded: listings_geom_active_idx (dropped by 104, listings_geom_idx covers it),
listings_scraped_desc_idx (not in issue #1398 suggested fix scope).

CONCURRENTLY not used — migration runner wraps in BEGIN/COMMIT (see 117 note).
2026-06-17 20:50:51 +03:00
de8bfdf884 fix(site-finder): smart_suggestions filter parcels above documented score threshold (#1503)
All checks were successful
CI / changes (push) Successful in 7s
CI / changes (pull_request) Successful in 7s
CI / backend-tests (push) Has been skipped
CI / frontend-tests (push) Has been skipped
CI / openapi-codegen-check (push) Has been skipped
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
Add SCORE_THRESHOLDS constant (mirror of backend/app/api/v1/parcels.py) to server.py
and filter out weighted scores below SCORE_THRESHOLDS["хорошо"] (25.0) before appending
to the suggestions list, honouring the contract stated in the endpoint docstring.
2026-06-17 20:50:31 +03:00