Commit graph

1604 commits

Author SHA1 Message Date
28b853bcdf feat(ptica): add ВРИ row to Градостроительство (real ЕГРН permitted_use)
All checks were successful
CI / changes (pull_request) Successful in 7s
CI / backend-tests (pull_request) Has been skipped
CI / frontend-tests (pull_request) Successful in 1m4s
CI / openapi-codegen-check (pull_request) Successful in 2m4s
Prototype's first ГРАДОСТРОИТЕЛЬСТВО row is ВРИ — prod lacked it. Add it from
the real egrn.permitted_use_text (e.g. «многоквартирные дома»); honest «нет
данных ЕГРН» fallback. Value wraps cleanly in the narrow card (verified, no
overflow).
2026-06-21 04:09:36 +05:00
701e8e9fe7 Merge pull request 'feat(ptica): map glyph pins + compass, equal-height grids, full-height rail; dark Site Finder' (#1861) from feat/ptica-map-glyphs-sitefinder-dark into main
All checks were successful
Deploy / changes (push) Successful in 7s
Deploy / build-backend (push) Has been skipped
Deploy / build-worker (push) Has been skipped
Deploy / build-frontend (push) Successful in 3m17s
Deploy / deploy (push) Successful in 1m8s
2026-06-20 22:41:18 +00:00
b3fd053e3d feat(ptica): map glyph pins + compass, equal-height grids, full-height rail; dark Site Finder
All checks were successful
CI / changes (pull_request) Successful in 6s
CI / backend-tests (pull_request) Has been skipped
CI / frontend-tests (pull_request) Successful in 55s
CI / openapi-codegen-check (pull_request) Successful in 1m58s
ПТИЦА cockpit:
- map: POI/competitors/connections now render as glyph divIcon pins (per-category
  glyph + color) with dashed connection lines + a compass — matches the prototype
  (was plain CircleMarker dots). Legend/zoom/scale/base-toggle/tools kept.
- lower+bottom grids: align-items stretch → equal-height rows; cards are flex
  columns with footer «Подробнее» pinned to bottom and sparse empty-states
  centred (fixes «выровняй тут все»).
- rail: dropped sticky+height:100vh so it stretches to full page height like the
  prototype (fixes «обрезан»).

Main Site Finder (entry landing) — restyled to the ПТИЦА dark cockpit theme,
scoped to .sfRoot[data-theme=dark] (no leak to light pages): dark CARTO tiles,
Leaflet attribution flag removed (prefix=false, © credit kept), dark markers /
filter chips / legend / recent list / drawer / cad input.
2026-06-21 03:41:13 +05:00
ff77987260 Merge pull request 'feat(ptica): live 3D massing in Инсоляция card + honest Recommended Product verdict' (#1860) from fix/ptica-3d-preview-product-verdict into main
All checks were successful
Deploy / build-worker (push) Has been skipped
Deploy / build-frontend (push) Successful in 3m23s
Deploy / deploy (push) Successful in 1m12s
Deploy / changes (push) Successful in 5s
Deploy / build-backend (push) Has been skipped
2026-06-20 22:11:20 +00:00
8c43410ad2 feat(ptica): live 3D massing in Инсоляция card + honest Recommended Product verdict
All checks were successful
CI / changes (pull_request) Successful in 6s
CI / backend-tests (pull_request) Has been skipped
CI / frontend-tests (pull_request) Successful in 57s
CI / openapi-codegen-check (pull_request) Successful in 1m59s
- MassingScene: preview prop — viewport-only, hands-off autorotate (OrbitControls
  input disabled, autoRotate on), canvas pointer-events:none; teardown preserved.
- InsolationCard: replaces the abstract SVG cube with a live autorotating massing
  built from real parcel area + НСПД max_far (farIsReal). «Открыть 3D» still opens
  the full interactive drawer.
- RecommendedProductCard: degenerate mix no longer shows «сигнал недоступен» —
  it shows the real advisory verdict «Избегать» + reason (затоварка · индекс
  дефицита из mix.deficit_index) + product_tz.gate_caveat. Meaningful mixes still
  render quartirography bars. «Подробнее» → product drawer (full reasons).
- drop dead iso-cube CSS (pticaIsoSpin/.isoBoxPreview/.isoPreview*); add
  .massingPreviewViewport + verdict styles (tokens, dark-scoped).
- forecast type: product_tz.gate_caveat.

Clickability sweep: no dead controls found; cockpit already cleanly wired.
2026-06-21 03:11:15 +05:00
2a40b4fcc6 Merge pull request 'fix(ptica): button font-size — :where() so component classes win over reset' (#1858) from fix/ptica-button-fontsize into main
All checks were successful
Deploy / build-backend (push) Has been skipped
Deploy / deploy (push) Successful in 1m9s
Deploy / changes (push) Successful in 7s
Deploy / build-worker (push) Has been skipped
Deploy / build-frontend (push) Successful in 3m20s
2026-06-20 21:35:51 +00:00
611c56a549 fix(ptica): button font-size — :where() so component classes win over reset
All checks were successful
CI / changes (pull_request) Successful in 7s
CI / frontend-tests (pull_request) Successful in 58s
CI / backend-tests (pull_request) Has been skipped
CI / openapi-codegen-check (pull_request) Successful in 1m59s
The scoped reset `.pticaRoot button { font: inherit }` had specificity (0,1,1),
beating single-class button rules like .navItem (9px), .tab (11px), .detailBtn
(9px), .ptab — so every cockpit button was forced back to the root 13px. The
oversized labels overflowed the 96px left rail (icons/text shoved right of
centre, «неровное») and bloated tabs/buttons across the cockpit.

Wrap the selector in :where(button) → specificity (0,1,0); the per-component
classes (later in source) now win their font-size, matching the prototype's
bare `button {}`. Verified on a live local render: rail labels 13→9px and every
item re-centres at 47.5px; tabs 11px; detail buttons 9px.
2026-06-21 02:35:33 +05:00
ea20d8688a Merge pull request 'fix(ptica): populate scan cards with real /analyze data + product tabs + map zoom' (#1857) from fix/ptica-parity-data-mapping into main
All checks were successful
Deploy / changes (push) Successful in 6s
Deploy / build-backend (push) Has been skipped
Deploy / build-worker (push) Has been skipped
Deploy / build-frontend (push) Successful in 3m41s
Deploy / deploy (push) Successful in 1m10s
2026-06-20 21:18:45 +00:00
5587154327 fix(ptica): populate scan cards with real /analyze data + product tabs + map zoom
All checks were successful
CI / changes (pull_request) Successful in 7s
CI / backend-tests (pull_request) Has been skipped
CI / frontend-tests (pull_request) Successful in 54s
CI / openapi-codegen-check (pull_request) Successful in 1m53s
Verified against a real captured /analyze+/forecast fixture rendered locally:
much of the cockpit's «—» was unmapped data, not missing data.

- РЫНОК: map Поглощение (market_pulse.avg_velocity_m2), add Конкурентов
  (market_pulse.competitors_total), Уровень спроса (market_trend.label);
  keep Медиана + Новых проектов. Prototype row order.
- СРЕДА (adaptEnvironmentCard now takes analysis): Шум (noise.estimated_db),
  Воздух PM2.5 (air_quality.pm2_5), Ветер (wind dir + max_speed), Водоёмы
  (hydrology nearest). Honest «—» where genuinely absent.
- ГРАДОСТРОИТЕЛЬСТВО: Пятно застройки = area × max_building_pct/100 (real).
- RECOMMENDED PRODUCT: prototype class tabs (обж_class present in mix),
  default = recommended class; per-class honest empty-state preserved.
- MAP: dark-styled ZoomControl (+/-) + ScaleControl, matching prototype.
- types: optional MarketPulse/MarketPrice on ParcelAnalysis (no any).

Economy/Investment-clearance stay «после финмодели §23» (not built); the
0%/«нельзя»/all-«избегать» verdict is the parcel's real result, not a bug.
2026-06-21 02:18:20 +05:00
01c91a9ea3 Merge pull request 'feat(ptica): slow turntable rotation on insolation preview cube' (#1856) from chore/ptica-iso-preview-spin into main
All checks were successful
Deploy / changes (push) Successful in 7s
Deploy / build-backend (push) Has been skipped
Deploy / build-worker (push) Has been skipped
Deploy / build-frontend (push) Successful in 3m10s
Deploy / deploy (push) Successful in 1m9s
2026-06-20 20:47:36 +00:00
829439a4fa feat(ptica): slow turntable rotation on insolation preview cube
All checks were successful
CI / backend-tests (pull_request) Has been skipped
CI / changes (pull_request) Successful in 7s
CI / openapi-codegen-check (pull_request) Successful in 1m51s
CI / frontend-tests (pull_request) Successful in 1m0s
The «Инсоляционная матрица» preview cube now gently rotates (rotateY
turntable with a constant rotateX tilt for depth) so the 3D module reads
as alive without opening the drawer. Pure CSS; honours prefers-reduced-motion.
2026-06-21 01:46:00 +05:00
9370c7af8e Merge pull request 'fix(ptica): load Inter, surface map legend, drop flag, honest product chart, home link' (#1855) from fix/ptica-inter-map-product into main
All checks were successful
Deploy / build-backend (push) Has been skipped
Deploy / changes (push) Successful in 8s
Deploy / build-worker (push) Has been skipped
Deploy / build-frontend (push) Successful in 3m13s
Deploy / deploy (push) Successful in 1m20s
2026-06-20 20:42:29 +00:00
f4b54671d9 fix(ptica): load Inter, surface map legend, drop flag, honest product chart, home link
All checks were successful
CI / changes (pull_request) Successful in 6s
CI / backend-tests (pull_request) Has been skipped
CI / frontend-tests (pull_request) Successful in 57s
CI / openapi-codegen-check (pull_request) Successful in 1m56s
Root causes behind the cockpit looking «криво/косо»:

- Inter was never loaded — app referenced literal "Inter" but only IBM Plex
  Mono went through next/font, so the whole cockpit rendered in -apple-system
  (wider metrics → rail labels overflow, tabular numbers misalign). Load Inter
  via next/font/google (latin+cyrillic) and wire --font-ui/body to it.
- Map legend overlay (z-index 4) was buried under Leaflet panes (200-700):
  give .leaflet-container its own stacking context (position:absolute; z-index:1)
  like the prototype, so the overlay + tools surface.
- Drop the Leaflet attribution flag/"Leaflet" prefix (prefix={false}) while
  keeping the © Esri/Maxar/CARTO data credits.
- RECOMMENDED PRODUCT rendered 15 degenerate full-red −1.00 bars: filter mix to
  the recommended class, show an honest empty state on degenerate signal, cap
  rows, and stop labels wrapping (nowrap+ellipsis).
- ПТИЦА wordmark is now a Link → /site-finder (home), with a focus ring.
2026-06-21 01:41:13 +05:00
721623bd0e Merge pull request 'fix(ptica): visual parity 1:1 with prototype (ОКС stretch + restored elements)' (#1854) from fix/ptica-visual-parity into main
All checks were successful
Deploy / changes (push) Successful in 7s
Deploy / build-worker (push) Has been skipped
Deploy / build-backend (push) Has been skipped
Deploy / build-frontend (push) Successful in 3m16s
Deploy / deploy (push) Successful in 1m10s
2026-06-20 20:10:43 +00:00
fcaa4d197b fix(ptica): visual parity 1:1 with prototype (incl. ОКС empty-card stretch)
All checks were successful
CI / changes (pull_request) Successful in 7s
CI / backend-tests (pull_request) Has been skipped
CI / frontend-tests (pull_request) Successful in 59s
CI / openapi-codegen-check (pull_request) Successful in 1m57s
Multi-region audit vs the prototype styles.css/dashboard.html → 22 CSS fixes +
markup. Headline: .lowerGrid/.bottomGrid align-items:start so the sparse ОКС
«нет данных» card no longer stretches into a huge void. Plus restore missing
prototype bits: topbar icon-buttons (Экспорт→Отчёты, Полный экран→fullscreen,
Настройки aria-disabled «скоро»), rail help-dot, app-footer (honest disclaimer,
no fabricated model/timestamp), invest-score sparkline (decorative, aria-hidden),
green/amber value tones, engineering status-row dots (from real nearest_m),
verdict-card gradient, scan-card status-rows, .canvas/.hbar/.mixHead spacing.

All new CSS scoped under .pticaRoot[data-theme=dark] (status-row classes
descendant-scoped under .scanCard — no collision with the drawer's). Environment
card stays honest kvrow placeholders (no fake dots). a11y: aria-labels on icon
buttons. TS strict, no any. tsc/lint/prettier/build green. code-reviewer .
2026-06-21 01:10:36 +05:00
5fb69b779e Merge pull request 'fix(ptica): left-rail — 7 icon+label items + working nav (match reference)' (#1853) from fix/ptica-left-rail into main
All checks were successful
Deploy / deploy (push) Successful in 1m8s
Deploy / build-frontend (push) Successful in 3m13s
Deploy / build-worker (push) Has been skipped
Deploy / changes (push) Successful in 7s
Deploy / build-backend (push) Has been skipped
2026-06-20 19:45:32 +00:00
ee155c9002 fix(ptica): restore left-rail to 7 icon+label items with working nav
All checks were successful
CI / frontend-tests (pull_request) Successful in 52s
CI / openapi-codegen-check (pull_request) Successful in 1m52s
CI / changes (pull_request) Successful in 7s
CI / backend-tests (pull_request) Has been skipped
The cockpit rail had 6 text-only items whose scrollToAnchor targeted
non-existent IDs (clicks did nothing) and diverged from the reference.
Replace with the prototype's 7 icon+label items (Участок/Потенциал/Продукт/
Экономика/Риски/Сравнение/Отчёты, icons ported from the kit). Discriminated
union RailItem {kind:'scroll'|'tab'}: scroll items activate the analysis tab
then scrollIntoView the matching section on the next frame; tab items switch
the top tab. Add ptica-hero/-potential/-product/-economy/-risks section IDs;
port the .nav-item active state (cyan accent + glow + left bar).
2026-06-21 00:45:24 +05:00
5374535e89 Merge pull request 'feat(ptica): complete cockpit — lower-grid + bottom-grid (Potential/Product/Clearance/Verdict)' (#1852) from feat/ptica-cockpit-complete-bottom into main
All checks were successful
Deploy / changes (push) Successful in 6s
Deploy / build-backend (push) Has been skipped
Deploy / build-worker (push) Has been skipped
Deploy / build-frontend (push) Successful in 3m27s
Deploy / deploy (push) Successful in 1m8s
2026-06-20 19:33:48 +00:00
24b5e6047f feat(ptica): complete cockpit lower-grid + bottom-grid sections
All checks were successful
CI / changes (pull_request) Successful in 6s
CI / backend-tests (pull_request) Has been skipped
CI / frontend-tests (pull_request) Successful in 1m6s
CI / openapi-codegen-check (pull_request) Successful in 2m1s
Port the prototype's missing sections — the React cockpit had only hero +
Development Scan, so the deployed page was incomplete («поплывшее»). Add:
- lower-grid: ОКС · Development Potential · Recommended Product (квартирография)
  · Инсоляционная матрица (opens 3D);
- bottom-grid: Investment Clearance · Buy Signal · Legal Status · Site Verdict
  («Приобретать/Нельзя/Нужна проверка» plaque + checklist).
Move ОКС + Инсоляция out of DevelopmentScan → scan = 7 cards (prototype IA).

Data honesty: Development Potential (real КСИТ/площадь/плотность), Recommended
Product (forecast product_tz), Buy Signal + Site Verdict (forecast deficit +
gate_verdict, real, three-state), Legal (zouit/red_lines/gate). Investment
Clearance all «—» «после финмодели (§23)» — no fabricated numbers. Typed
{value,isReal,caption} adapters; scoped dark CSS; forecast-pending safe.
Cleanup: drop orphaned adaptOksCard/adaptInsolationCard; add .metric/.bignum.
2026-06-21 00:33:15 +05:00
4205ecb483 Merge pull request 'feat(ptica): rich dark map (POI/connections/competitors/satellite) + ПТИЦА as default analysis route' (#1851) from feat/ptica-default-and-rich-map into main
All checks were successful
Deploy / changes (push) Successful in 7s
Deploy / build-backend (push) Has been skipped
Deploy / build-worker (push) Has been skipped
Deploy / build-frontend (push) Successful in 3m17s
Deploy / deploy (push) Successful in 1m10s
2026-06-20 19:06:08 +00:00
7866479653 Merge pull request 'feat(ptica): wire real КСИТ/height/zone/density into cockpit (frontend of #1843)' (#1849) from feat/ptica-real-ksit-frontend into main
Some checks failed
Deploy / deploy (push) Blocked by required conditions
Deploy / changes (push) Successful in 6s
Deploy / build-backend (push) Has been skipped
Deploy / build-worker (push) Has been skipped
Deploy / build-frontend (push) Has been cancelled
2026-06-20 19:05:39 +00:00
ba05a4cb62 feat(ptica): rich dark cockpit map + ПТИЦА as the default analysis route
All checks were successful
CI / changes (pull_request) Successful in 6s
CI / backend-tests (pull_request) Has been skipped
CI / frontend-tests (pull_request) Successful in 49s
CI / openapi-codegen-check (pull_request) Successful in 1m48s
Fix two regressions vs the prototype:
1. PticaMapInner: render real data layers over the dark base by REUSING the
   existing analysis-map components — POI by category, competitors/pipeline
   (MarketLayers), connection points + colored polylines (ConnectionPointsLayer),
   ЗОУИТ (ZouitLayer), custom POI add/edit/delete (CustomPoiLayer + mutation hooks).
   Add Спутник/Схема base toggle (Esri default + --map-filter-sat); legend rows
   toggle layers; «Точки подключения» driven by real CP data. Isochrones left
   «скоро» (ORS is on-demand, not in /analyze).
2. /site-finder/analysis/[cad] now renders the ПТИЦА cockpit — every parcel entry
   opens ПТИЦА, not the old design. [cad]/ptica redirects to the parent (single
   cockpit copy). Old AnalysisPageContent kept in repo; legacy UI at /legacy/site-finder.
3. Surface 3D massing: new «Инсоляция · 3D-масса» scan card + 3D legend row + 3D
   map tool all open the insolation/future3d drawers.

SSR-safe (Leaflet only behind dynamic ssr:false); real POI from score_breakdown;
no redirect loop. tsc/lint/prettier/build green. code-reviewer APPROVE.
2026-06-21 00:04:00 +05:00
167fcbace2 feat(ptica): wire real ПЗЗ regulation (КСИТ/height/zone/density) into cockpit
All checks were successful
CI / changes (pull_request) Successful in 6s
CI / backend-tests (pull_request) Has been skipped
CI / frontend-tests (pull_request) Successful in 51s
CI / openapi-codegen-check (pull_request) Successful in 1m46s
Read nspd_zoning.{max_far,max_height_m,max_floors,max_building_pct,
regulation_zone_index,regulation_source} (backend PR #1847) into the urban
scan-card, urban/buildability/potential drawers and the 3D massing КСИТ-target.
Defensive: every read is optional-chained + != null guarded → identical "—"
placeholders when fields absent, so the cockpit is unchanged until #1847 deploys,
then auto-lights-up. КСИТ density = area × max_far; пятно = area × max_building_pct
(percent 0..100, verified vs backend parser); sellable labeled estimate. 3D maxFar
= nspd_zoning.max_far ?? 3.5 (finite/>0 guarded). NspdZoning type +7 optional fields.
TS strict, no any.
2026-06-20 23:33:41 +05:00
09656077c1 Merge pull request 'fix(scrapers): avito ban-triggered IP rotation (#1790) разблокирует houses-enrichment (#1789) + rating_score' (#1848) from fix/avito-ban-rotation-houses into main
All checks were successful
Deploy Trade-In / changes (push) Successful in 10s
Deploy Trade-In / build-frontend (push) Has been skipped
Deploy Trade-In / build-browser (push) Has been skipped
Deploy Trade-In / test (push) Successful in 1m27s
Deploy Trade-In / build-backend (push) Successful in 49s
Deploy Trade-In / deploy (push) Successful in 47s
Reviewed-on: #1848
2026-06-20 18:28:29 +00:00
bf521dc838 Merge pull request 'feat(analyze): real ПЗЗ КСИТ/height into nspd_zoning (ПТИЦА оживление, #1843 Route 2)' (#1847) from feat/ptica-real-ksit-backend into main
All checks were successful
Deploy / changes (push) Successful in 7s
Deploy / build-frontend (push) Has been skipped
Deploy / build-backend (push) Successful in 2m3s
Deploy / build-worker (push) Successful in 2m59s
Deploy / deploy (push) Successful in 1m26s
Reviewed-on: #1847
2026-06-20 18:27:39 +00:00
33d7829221 feat(analyze): surface real ПЗЗ regulation (КСИТ/height) into nspd_zoning
All checks were successful
CI / changes (pull_request) Successful in 6s
CI / frontend-tests (pull_request) Has been skipped
CI / openapi-codegen-check (pull_request) Successful in 1m48s
CI / backend-tests (pull_request) Successful in 9m44s
Resolve numeric ПЗЗ limits (max_far/КСИТ, max_height_m, max_floors,
max_building_pct, min_parcel_area_m2) by parcel centroid via the coordinate
resolver get_or_fetch_zone_regulation (cache-first; bounded 3s live geoportal)
and merge into the /analyze nspd_zoning object. Powers the ПТИЦА cockpit's
real КСИТ/height/density (was placeholder). Flag-gated
(enable_zoning_regulation_in_analyze, default on) and hot-path-safe: any
exception/timeout → null fields, analyze never 500s or slow-fails (3s cap).
Additive — existing nspd_zoning keys untouched. 198 tests pass.

Note: zone_index_at is a live WFS call per analyze even on warm cache
(~0.3-0.5s healthy / 3s cap degraded) — optimization tracked as follow-up.
2026-06-20 23:24:22 +05:00
7f036a96af fix(scrapers): avito ban-triggered IP rotation (#1790) — changeip on block, bounded
All checks were successful
CI / changes (pull_request) Successful in 6s
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
- Добавлен `_rotate_proxy_ip()` в scrape_pipeline.py: вызывает changeip-URL
  (settings.avito_proxy_rotate_url) + settle-sleep
  (settings.avito_proxy_rotate_settle_s, default 9s), логирует old→new IP.
- В `run_avito_pipeline` (Steps 4/5/5b) и `run_avito_city_sweep` (Phase 4/5/5b):
  при достижении consecutive-block порога — сначала ротация IP, сброс счётчика,
  продолжение; только при исчерпании бюджета (enrich_rotations_done >=
  avito_proxy_max_rotations) — abort (bounded). #1820 graceful сохранён: один
  блок ниже порога ротацию не вызывает.
- Добавлено `avito_proxy_rotate_settle_s: float = 9.0` в config.py
  (ENV: AVITO_PROXY_ROTATE_SETTLE_S). avito_proxy_max_rotations был 4 (с #1731).
- Тесты: rotation_called / bounded_abort / single_block_no_rotation.
2026-06-20 21:24:12 +03:00
f80bdd751b Merge pull request 'fix(ptica): drawer modal a11y (focus-trap + restore) + polish' (#1842) from feat/ptica-a11y-polish into main
All checks were successful
Deploy / changes (push) Successful in 7s
Deploy / build-backend (push) Has been skipped
Deploy / build-worker (push) Has been skipped
Deploy / build-frontend (push) Successful in 3m20s
Deploy / deploy (push) Successful in 1m12s
Reviewed-on: #1842
2026-06-20 18:02:38 +00:00
b57bd2e3be Merge pull request 'fix(site_finder): read real NSPD territorial-zone keys (nspd_zoning.zone_code was always null)' (#1844) from fix/nspd-zoning-zone-code-keys into main
Some checks failed
Deploy / deploy (push) Blocked by required conditions
Deploy / changes (push) Successful in 6s
Deploy / build-frontend (push) Has been skipped
Deploy / build-backend (push) Has been cancelled
Deploy / build-worker (push) Has been cancelled
Reviewed-on: #1844
2026-06-20 18:02:19 +00:00
482ddc794e Merge pull request 'fix(tradein/yandex): инкрементальный per-combo save + bounded gate-timeout (анти-зомби city_sweep)' (#1845) from fix/tradein-yandex-sweep-robustness into main
All checks were successful
Deploy Trade-In / changes (push) Successful in 8s
Deploy Trade-In / build-frontend (push) Has been skipped
Deploy Trade-In / build-browser (push) Has been skipped
Deploy Trade-In / test (push) Successful in 1m24s
Deploy Trade-In / build-backend (push) Successful in 56s
Deploy Trade-In / deploy (push) Successful in 50s
Reviewed-on: #1845
2026-06-20 18:01:55 +00:00
37f12f6303 fix(tradein/yandex): инкрементальный per-combo save + bounded gate-timeout (анти-зомби city_sweep)
All checks were successful
CI / changes (pull_request) Successful in 6s
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
2026-06-20 20:57:41 +03:00
cbe509f092 fix(site_finder): read real NSPD territorial-zone keys in _get_zoning
All checks were successful
CI / changes (pull_request) Successful in 6s
CI / frontend-tests (pull_request) Has been skipped
CI / openapi-codegen-check (pull_request) Successful in 1m51s
CI / backend-tests (pull_request) Successful in 8m52s
_get_zoning() read non-existent props (top-level reg_numb_border / zone_code /
type_zone / name) so nspd_zoning.zone_code & zone_name were NULL on every parcel.
Real dump props (verified prod, 796 features) carry only the registration number,
duplicated across descr / label / externalKey / options.reg_numb_border (no human
zone name exists in the NSPD dump). Map both fields to that reg-number with safe
nested narrowing (isinstance options dict) + legacy fallbacks; honest — no
fabricated name. Surfacing reg_numb_border also unblocks the КСИТ crosswalk (#1843).
Regression tests use the real prop shape (full / nested-only / opaque→None).
2026-06-20 20:29:45 +05:00
88865bf6a7 fix(ptica): drawer modal a11y (focus-trap + restore) + polish
All checks were successful
CI / changes (pull_request) Successful in 5s
CI / backend-tests (pull_request) Has been skipped
CI / frontend-tests (pull_request) Successful in 57s
CI / openapi-codegen-check (pull_request) Successful in 1m52s
PticaDrawer: proper modal focus management —
- focus-trap: Tab/Shift+Tab wrap inside the dialog (focusables re-queried per
  Tab so it survives lazy panels/sub-tabs), focus-already-outside pulled back in;
- focus-restore: the trigger element is captured on open and re-focused on close
  (guards null + detached node);
- onClose held in a ref so the effect depends on [open] only — fixes focus
  thrashing when the host's URL/searchParams change mid-open.
Esc/scrim close, body-scroll-lock, role=dialog/aria-modal preserved.

Cleanups (code-review follow-ups):
- MassingScene: drop duplicate initial mass build (floors/sections effect owns
  it); corrected the effect-ordering comment.
- Static inline styles → CSS-module classes (scan/gauge/score/spaced rows).
- DrawerPrimitives: remove !important on .dtabActive via specificity
  (.dtabs button.dtabActive).
- Remove unused SoonCard component + its CSS.

tsc/lint/prettier clean; next build green (route bundled). ptica-only, no any.
2026-06-20 20:13:26 +05:00
06fa5b4910 Merge pull request 'feat(tradein): бэкфилл координат листингов из ekb_geoportal_buildings (street+house match)' (#1841) from feat/tradein-backfill-coords-geoportal into main
All checks were successful
Deploy Trade-In / changes (push) Successful in 7s
Deploy Trade-In / build-browser (push) Successful in 28s
Deploy Trade-In / build-frontend (push) Successful in 28s
Deploy Trade-In / test (push) Successful in 1m23s
Deploy Trade-In / build-backend (push) Successful in 50s
Deploy Trade-In / deploy (push) Successful in 47s
Reviewed-on: #1841
2026-06-20 14:14:12 +00:00
97d74e07a7 Merge pull request 'feat(tradein/avito): per-card ЕКБ гео-фильтр (отсечь padding по России)' (#1840) from feat/tradein-avito-ekb-filter-room-split into main
Some checks failed
Deploy Trade-In / changes (push) Successful in 6s
Deploy Trade-In / test (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
Deploy Trade-In / build-backend (push) Has been cancelled
Reviewed-on: #1840
2026-06-20 14:14:02 +00:00
261f3a33e6 Merge pull request 'fix(ci): deploy-tradein paths-filter base = last deployed SHA (накопленный diff, fail-safe build-all)' (#1839) from fix/deploy-tradein-cumulative-base into main
Some checks failed
Deploy Trade-In / changes (push) Successful in 7s
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
Deploy Trade-In / test (push) Has been cancelled
Reviewed-on: #1839
2026-06-20 14:13:53 +00:00
d35e61be16 feat(tradein): бэкфилл координат листингов из ekb_geoportal_buildings (street+house match)
All checks were successful
CI / changes (pull_request) Successful in 6s
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
2026-06-20 17:08:46 +03:00
f026423715 feat(tradein/avito): per-card ЕКБ гео-фильтр (отсечь padding по России) + сплит комнат 4/5+
All checks were successful
CI / changes (pull_request) Successful in 5s
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
FIX 1: в _parse_html добавлен гео-фильтр per-card source_url. При
avito_serp_ekb_only=True (ENV AVITO_SERP_EKB_ONLY, дефолт True) карточки без
/ekaterinburg/ в source_url отбрасываются — Авито добивает выдачу
«по всей России» при малом числе ЕКБ-результатов (rooms=4 давал 96% не-ЕКБ).
Карточки без распознанного city-slug пропускаются консервативно.
Лог: «avito SERP: dropped N non-EKB cards (padding)».

FIX 2 (анализ): ROOM_SLUGS уже содержит отдельные бакеты «4-комн.» и «5+комн.»
(разбиты ранее). rooms-значение берётся из текста заголовка карточки
(_extract_rooms_from_title: regex «(\d)-к. квартира»), а не из бакета —
4/5/6 различаются по факту парсинга. Сплит slug'ов был сделан ранее, регрессий нет.

Тесты: 4 новых unit-теста в test_avito_ekb_geo_filter.py покрывают:
EKB+non-EKB → только EKB; ekb_only=False → все проходят;
без city-slug → консервативно оставляем; все EKB → ничего не дропается.
2026-06-20 16:59:12 +03:00
febc88d37b fix(ci): deploy-tradein paths-filter base = last deployed SHA (накопленный diff, fail-safe build-all)
All checks were successful
CI / changes (pull_request) Successful in 5s
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
При быстрых мержах dorny/paths-filter без explicit base диффает per-merge-commit
(parent of merge), а не накопленно от последнего деплоя. Итог: backend-мерж #1829
не попадает в diff frontend-мержа #1830 → build-backend skipped, образа нет.

Решение (host-file mechanism):
- deploy-джоба пишет `echo "$GITHUB_SHA" > /opt/gendesign/.tradein-deployed-sha`
  в самом конце SSH-скрипта — только после успешного up+миграций.
- changes-джоба читает файл по SSH (те же DEPLOY_* секреты), валидирует SHA как
  40-char hex + git merge-base --is-ancestor HEAD, передаёт в `base:` paths-filter.
- Если файл отсутствует / SHA не предок HEAD / SSH недоступен → FAIL-SAFE:
  step `set-all` эмитит все outputs=true, paths-filter пропускается,
  все образы собираются (better safe than sorry).

Почему host-file, не git-ref: в workflows не используется `gitea.token` /
`GITHUB_TOKEN` с contents:write — добавлять новое разрешение ради ref push
ненужный риск. DEPLOY_* секреты уже есть, SSH уже есть.

Не изменено: concurrency.cancel-in-progress=false, workflow_dispatch форс,
логика build/deploy/migrations.
2026-06-20 16:05:19 +03:00
8bf3d24190 Merge pull request 'feat(tradein/scrapers): detail_backfill через curl_cffi+backconnect вместо браузера/auv (развязка прокси)' (#1838) from feat/tradein-detail-backfill-curl into main
All checks were successful
Deploy Trade-In / changes (push) Successful in 7s
Deploy Trade-In / build-frontend (push) Has been skipped
Deploy Trade-In / build-browser (push) Has been skipped
Deploy Trade-In / test (push) Successful in 1m22s
Deploy Trade-In / build-backend (push) Successful in 52s
Deploy Trade-In / deploy (push) Successful in 47s
Reviewed-on: #1838
2026-06-20 12:59:56 +00:00
cc3ff7c3d2 feat(tradein/scrapers): detail_backfill через curl_cffi+backconnect вместо браузера/auv (развязка прокси)
All checks were successful
CI / changes (pull_request) Successful in 7s
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
SERP (full_load/city_sweep) и detail_backfill делили один прокси-аккаунт auv (~5 коннектов).
Browser-фетч в backfill открывал десятки CONNECT-туннелей → cap превышался → HTTP 500/краши.

- config.py: avito_detail_backfill_use_curl=True (ENV AVITO_DETAIL_BACKFILL_USE_CURL)
- avito_detail_backfill.py: browser_mode гейтится флагом; use_curl=True → session=None,
  browser_fetcher=None → fetch_detail строит _build_detail_session() через scraper_proxy_url
  (backconnect mproxy, авто-ротация, 1 коннект/запрос)
- tests: 2 новых теста (use_curl=True → BrowserFetcher не создаётся; False → создаётся)
2026-06-20 15:55:24 +03:00
cf032182ed Merge pull request 'feat(ptica): 3D building-massing module (Three.js) [PR#5]' (#1835) from feat/ptica-cockpit-pr5-3d into main
All checks were successful
Deploy / build-worker (push) Has been skipped
Deploy / changes (push) Successful in 6s
Deploy / build-backend (push) Has been skipped
Deploy / build-frontend (push) Successful in 5m0s
Deploy / deploy (push) Successful in 1m8s
Reviewed-on: #1835
2026-06-20 12:33:50 +00:00
f6922e5527 Merge pull request 'feat(ptica): detail drawer system + 17 drawers [PR#4]' (#1834) from feat/ptica-cockpit-pr4-drawers into main
Some checks failed
Deploy / deploy (push) Blocked by required conditions
Deploy / changes (push) Successful in 7s
Deploy / build-backend (push) Has been skipped
Deploy / build-worker (push) Has been skipped
Deploy / build-frontend (push) Has been cancelled
Reviewed-on: #1834
2026-06-20 12:33:37 +00:00
708d8b5aed Merge pull request 'feat(ptica): Отчёты + Сравнение cockpit tabs [PR#3]' (#1833) from feat/ptica-cockpit-pr3-reports-compare into main
Some checks failed
Deploy / deploy (push) Blocked by required conditions
Deploy / changes (push) Successful in 7s
Deploy / build-backend (push) Has been skipped
Deploy / build-worker (push) Has been skipped
Deploy / build-frontend (push) Has been cancelled
Reviewed-on: #1833
2026-06-20 12:33:18 +00:00
76311cbfe8 Merge pull request 'feat(ptica): Сценарии tab (§22 forecast) + real hero invest-score [PR#2]' (#1832) from feat/ptica-cockpit-pr2-scenarios into main
Some checks failed
Deploy / changes (push) Successful in 8s
Deploy / build-backend (push) Has been skipped
Deploy / build-worker (push) Has been skipped
Deploy / deploy (push) Has been cancelled
Deploy / build-frontend (push) Has been cancelled
Reviewed-on: #1832
2026-06-20 12:33:08 +00:00
47187fe4f3 Merge pull request 'feat(site-finder): ПТИЦА dark cockpit — increment 1 (shell + hero + Development Scan)' (#1831) from feat/ptica-cockpit-pr1 into main
Some checks failed
Deploy / changes (push) Successful in 8s
Deploy / deploy (push) Blocked by required conditions
Deploy / build-backend (push) Has been skipped
Deploy / build-worker (push) Has been skipped
Deploy / build-frontend (push) Has been cancelled
Reviewed-on: #1831
2026-06-20 12:32:55 +00:00
7b69e5a675 Merge pull request 'feat(scrapers/ui): backfill+full-load триггеры, source-фильтр, pacing-слайдер, coverage-таблица' (#1830) from feat/scrapers-ui-completeness into main
All checks were successful
Deploy Trade-In / changes (push) Successful in 8s
Deploy Trade-In / test (push) Has been skipped
Deploy Trade-In / build-browser (push) Has been skipped
Deploy Trade-In / build-backend (push) Has been skipped
Deploy Trade-In / build-frontend (push) Successful in 1m51s
Deploy Trade-In / deploy (push) Successful in 55s
Reviewed-on: #1830
2026-06-20 12:32:04 +00:00
93783602c5 Merge pull request 'feat(scrapers): live pacing-регулятор + data-quality coverage API' (#1829) from feat/scrapers-config-apis into main
Some checks failed
Deploy Trade-In / build-backend (push) Blocked by required conditions
Deploy Trade-In / deploy (push) Blocked by required conditions
Deploy Trade-In / changes (push) Successful in 7s
Deploy Trade-In / build-frontend (push) Has been skipped
Deploy Trade-In / build-browser (push) Has been cancelled
Deploy Trade-In / test (push) Has been cancelled
Reviewed-on: #1829
2026-06-20 12:31:47 +00:00
56e1c6e62d Merge pull request 'feat(trade-in/ui): transparency «Мера» — analog_tier, address_precision, expected_sold бар, ratio_basis' (#1837) from feat/estimator-ui-transparency into main
Some checks failed
Deploy Trade-In / deploy (push) Blocked by required conditions
Deploy Trade-In / changes (push) Successful in 6s
Deploy Trade-In / test (push) Has been skipped
Deploy Trade-In / build-browser (push) Has been skipped
Deploy Trade-In / build-backend (push) Has been skipped
Deploy Trade-In / build-frontend (push) Has been cancelled
Reviewed-on: #1837
2026-06-20 12:31:19 +00:00
485a3eb253 Merge pull request 'fix(estimator): топ-5 фиксов аудита «Мера» (anchor gate, analog_tier, freshness, MAD-order, data-age)' (#1836) from feat/estimator-audit-top5 into main
All checks were successful
Deploy Trade-In / build-frontend (push) Has been skipped
Deploy Trade-In / build-browser (push) Has been skipped
Deploy Trade-In / deploy (push) Successful in 44s
Deploy Trade-In / changes (push) Successful in 6s
Deploy Trade-In / test (push) Successful in 1m19s
Deploy Trade-In / build-backend (push) Successful in 1m21s
Reviewed-on: #1836
2026-06-20 12:27:13 +00:00