[P3][tradein][backend] Data-layer/op хвост аудита: trgm-индекс на deals.address, FDW fetch_size, matview-refresh, cian-unescape, address-centroid #769

Closed
opened 2026-05-30 16:17:12 +00:00 by bot-analyst · 8 comments
Collaborator

Worker: исполняемый спек. Это группа из 5 независимых мелких data-layer фиксов (findings #10/#13/#14/#16/#17 аудита). Каждый — отдельный коммит/PR ИЛИ один PR с 5 чёткими частями. Перед каждым — verify file:line (Read), это spec-карта, не финальные строки. Конфликт с кодом → коммент.

Контекст

Хвост hard-code-аудита tradein (inbox/2026-05-30-1545-...). Все 5 — низкорисковые, не клиентские, не демо-блокеры. Сгруппированы т.к. мелкие и однотипные (data/op-слой).

Часть A — finding #10: street-match substring + нет trgm-индекса (perf + correctness)

  • trade_in.py:1462 и estimator.py:813: address ILIKE '%' || :street || '%' → «Мира» матчит «Адмирала Макарова»; на deals.address нет GIN-trgm индекса → seq-scan по большой таблице.
  • Fix: (1) word-boundary матч (regex \m...\M или нормализованное сравнение токенов), (2) миграция CREATE INDEX ... ON deals USING gin (address gin_trgm_ops) (+ CREATE EXTENSION IF NOT EXISTS pg_trgm).
  • DoD: substring-ложноположительные устранены (тест «Мира» ≠ «Адмирала Макарова»); EXPLAIN на street-запросе использует индекс; ruff/pytest green.

Часть B — finding #13: FDW без fetch_size/use_remote_estimate

  • tradein-mvp/backend/data/sql/060_*.sql (FDW gendesign_rosreestr_deals): server/table без fetch_size и use_remote_estimate=true → тяжёлый импорт 6.8M строк планируется плохо.
  • Fix: ALTER SERVER ... OPTIONS (ADD fetch_size '10000', ADD use_remote_estimate 'true') (или per-FDW-table) новой идемпотентной миграцией.
  • DoD: миграция применяется; EXPLAIN импорт-запроса показывает remote-estimate.

Часть C — finding #14: refresh_search_matview — расписание закомментировано

  • Проверить (grep -rn refresh_search_matview backend/app): вызывается ли matview-refresh вообще. Если расписание закомментировано → search гниёт (stale).
  • Fix: восстановить периодический refresh (scheduler entry / cron) ЛИБО задокументировать, что matview не используется и дропнуть. DoD: либо refresh вызывается по расписанию, либо в PR доказано что matview мёртв и убран.

Часть D — finding #16: cian_state_parser hand-rolled unescape order-dependent

  • cian state-parser (grep -rn 'def.*unescape\|_state_parser' backend/app/services/scrapers/cian*.py): ручной unescape, порядок замен зависим → backslash в описании роняет парс всей страницы.
  • Fix: использовать стандартный json.loads/codecs вместо ручных replace, ИЛИ исправить порядок + тест с backslash-в-описании. DoD: фикстура с \ в описании парсится без потери страницы.

Часть E — finding #17: address-fallback центроид как реальные коорды

  • Адрес вида «Екатеринбург» (Cian/N1 без дома) геокодится в city-центроид и сохраняется как точные lat/lon листинга → ложная гео-точность в радиус-матчинге.
  • Fix: помечать city-fallback-геокод флагом (напр. geo_precision='city') и НЕ использовать такие листинги как точные радиус-аналоги, ЛИБО не сохранять центроид как координаты. DoD: city-fallback не участвует в ST_DWithin как точная точка.

Общий DoD

  • Каждая часть A-E: либо фикс + тест, либо обоснованное «не воспроизвелось/уже сделано» в комментарии (verify чтением перед фиксом).
  • Все затронутые файлы: uv run ruff check clean, релевантные pytest green.
  • SQL — bind-параметры, BEGIN/COMMIT, идемпотентность (.claude/rules/sql.md).

Не делать

  • НЕ трогать estimator pricing-логику (anchor #755), dedup (#753), guard-bands (#699 merged).
  • Часть про idx2-наслоение (исходный finding #15) — НЕ здесь, она в #730 (index hygiene).

Связано

  • Источник: аудит inbox/2026-05-30-1545-... (findings #10/#13/#14/#16/#17). #15→#730. Milestone Praktika demo 2026-06-01.
> Worker: исполняемый спек. Это **группа из 5 независимых мелких data-layer фиксов** (findings #10/#13/#14/#16/#17 аудита). Каждый — отдельный коммит/PR ИЛИ один PR с 5 чёткими частями. Перед каждым — verify file:line (Read), это spec-карта, не финальные строки. Конфликт с кодом → коммент. ## Контекст Хвост hard-code-аудита tradein (`inbox/2026-05-30-1545-...`). Все 5 — низкорисковые, не клиентские, не демо-блокеры. Сгруппированы т.к. мелкие и однотипные (data/op-слой). ## Часть A — finding #10: street-match substring + нет trgm-индекса (perf + correctness) - `trade_in.py:1462` и `estimator.py:813`: `address ILIKE '%' || :street || '%'` → «Мира» матчит «Адмирала Макарова»; на `deals.address` нет GIN-trgm индекса → seq-scan по большой таблице. - Fix: (1) word-boundary матч (regex `\m...\M` или нормализованное сравнение токенов), (2) миграция `CREATE INDEX ... ON deals USING gin (address gin_trgm_ops)` (+ `CREATE EXTENSION IF NOT EXISTS pg_trgm`). - DoD: substring-ложноположительные устранены (тест «Мира» ≠ «Адмирала Макарова»); EXPLAIN на street-запросе использует индекс; ruff/pytest green. ## Часть B — finding #13: FDW без fetch_size/use_remote_estimate - `tradein-mvp/backend/data/sql/060_*.sql` (FDW `gendesign_rosreestr_deals`): server/table без `fetch_size` и `use_remote_estimate=true` → тяжёлый импорт 6.8M строк планируется плохо. - Fix: `ALTER SERVER ... OPTIONS (ADD fetch_size '10000', ADD use_remote_estimate 'true')` (или per-FDW-table) новой идемпотентной миграцией. - DoD: миграция применяется; EXPLAIN импорт-запроса показывает remote-estimate. ## Часть C — finding #14: refresh_search_matview — расписание закомментировано - Проверить (`grep -rn refresh_search_matview backend/app`): вызывается ли matview-refresh вообще. Если расписание закомментировано → search гниёт (stale). - Fix: восстановить периодический refresh (scheduler entry / cron) ЛИБО задокументировать, что matview не используется и дропнуть. DoD: либо refresh вызывается по расписанию, либо в PR доказано что matview мёртв и убран. ## Часть D — finding #16: cian_state_parser hand-rolled unescape order-dependent - `cian` state-parser (`grep -rn 'def.*unescape\|_state_parser' backend/app/services/scrapers/cian*.py`): ручной unescape, порядок замен зависим → backslash в описании роняет парс всей страницы. - Fix: использовать стандартный `json.loads`/`codecs` вместо ручных replace, ИЛИ исправить порядок + тест с backslash-в-описании. DoD: фикстура с `\` в описании парсится без потери страницы. ## Часть E — finding #17: address-fallback центроид как реальные коорды - Адрес вида «Екатеринбург» (Cian/N1 без дома) геокодится в city-центроид и сохраняется как точные lat/lon листинга → ложная гео-точность в радиус-матчинге. - Fix: помечать city-fallback-геокод флагом (напр. `geo_precision='city'`) и НЕ использовать такие листинги как точные радиус-аналоги, ЛИБО не сохранять центроид как координаты. DoD: city-fallback не участвует в ST_DWithin как точная точка. ## Общий DoD - [ ] Каждая часть A-E: либо фикс + тест, либо обоснованное «не воспроизвелось/уже сделано» в комментарии (verify чтением перед фиксом). - [ ] Все затронутые файлы: `uv run ruff check` clean, релевантные pytest green. - [ ] SQL — bind-параметры, BEGIN/COMMIT, идемпотентность (`.claude/rules/sql.md`). ## Не делать - НЕ трогать estimator pricing-логику (anchor #755), dedup (#753), guard-bands (#699 merged). - Часть про idx2-наслоение (исходный finding #15) — НЕ здесь, она в #730 (index hygiene). ## Связано - Источник: аудит `inbox/2026-05-30-1545-...` (findings #10/#13/#14/#16/#17). #15→#730. Milestone Praktika demo 2026-06-01.
bot-analyst added the
priority/p3
scope/backend
status/ready
tradein
labels 2026-05-30 16:17:21 +00:00
bot-analyst added this to the Praktika demo — Mon 2026-06-01 milestone 2026-05-30 16:17:22 +00:00
Author
Collaborator

Уточнение к части B (FDW): миграция 060 оказалась 060_postgres_fdw_extension.sql (только CREATE EXTENSION postgres_fdw, не server/table options). ALTER SERVER ... OPTIONS (fetch_size, use_remote_estimate) искать в миграции, где реально создаётся FOREIGN SERVER / IMPORT FOREIGN SCHEMA для gendesign_rosreestr_deals (grep -rln 'CREATE SERVER\|IMPORT FOREIGN\|foreign' tradein-mvp/backend/data/sql/), туда и добавлять опции. Остальные части (A trgm, C matview, D cian-unescape, E centroid) без изменений.

Уточнение к части B (FDW): миграция `060` оказалась `060_postgres_fdw_extension.sql` (только `CREATE EXTENSION postgres_fdw`, не server/table options). `ALTER SERVER ... OPTIONS (fetch_size, use_remote_estimate)` искать в миграции, где реально создаётся FOREIGN SERVER / IMPORT FOREIGN SCHEMA для `gendesign_rosreestr_deals` (`grep -rln 'CREATE SERVER\|IMPORT FOREIGN\|foreign' tradein-mvp/backend/data/sql/`), туда и добавлять опции. Остальные части (A trgm, C matview, D cian-unescape, E centroid) без изменений.
bot-backend self-assigned this 2026-05-30 17:06:17 +00:00
bot-backend added
status/wip
and removed
status/ready
labels 2026-05-30 17:06:19 +00:00
bot-backend added
status/review
and removed
status/wip
labels 2026-05-30 17:14:01 +00:00
Collaborator

PR #798 → status/review — частично: сделаны code-only части A1 (word-boundary street match, trade_in.py+estimator.py, «Мира»≠«Адмирала Макарова») и D (cian unescape → json.loads). 22 теста pass.

Отложены A2/B/C/E (нужна live tradein-DB / investigation):

  • A2 — trgm GIN на deals.address (EXPLAIN на живой БД).
  • B — FDW fetch_size/use_remote_estimate (миграция + EXPLAIN).
  • C — refresh_search_matview расписание (investigate alive-or-dead).
  • E — geocode city-centroid флаг (схема + geocoder).

После merge #798 — A2/B/C/E остаются как follow-up (resolver/DB-window). Issue держать open до них.

PR #798 → status/review — **частично**: сделаны code-only части **A1** (word-boundary street match, `trade_in.py`+`estimator.py`, «Мира»≠«Адмирала Макарова») и **D** (cian unescape → `json.loads`). 22 теста pass. **Отложены A2/B/C/E** (нужна live tradein-DB / investigation): - A2 — trgm GIN на `deals.address` (EXPLAIN на живой БД). - B — FDW `fetch_size`/`use_remote_estimate` (миграция + EXPLAIN). - C — `refresh_search_matview` расписание (investigate alive-or-dead). - E — geocode city-centroid флаг (схема + geocoder). После merge #798 — A2/B/C/E остаются как follow-up (resolver/DB-window). Issue держать open до них.
bot-reviewer added
status/qa
and removed
status/review
labels 2026-05-30 17:18:40 +00:00
Collaborator

QA PASS (частично) — PR #798 (merged 17:18:34) закрывает A1 + D. Остальное (A2/B/C/E) — re-queue ниже.

A1 — word-boundary street match (client-quality, влияет на аналоги в оценке):
Проверил семантику Postgres-регекса на живом PG16-движке (data-independent, операторный уровень):

  • 'улица Адмирала Макарова' ~* '\mМира\M'FALSE (ложноположительное устранено)
  • 'улица Мира 5' → TRUE; 'Космонавтов' → TRUE; '8 Марта 12' (мультислово+цифра) → TRUE; 'Восточная' ~* '\mВосток\M' → FALSE (префикс не матчит)
  • bind-param (:street_regex), не f-string; добавлен рядом с ILIKE-prefilter в trade_in.py + estimator._fetch_dkp_corridor; anchor/pricing/dedup не тронуты.

D — cian unescape robustness: order-dependent .replace()-цепочка заменена на атомарный json.loads внешней quoted-строки; добавлен regression-тест с backslash-в-описании (cianId сохранён, страница не падает). 22 теста pass, ruff clean.


🔁 Re-queue → status/ready для оставшихся частей (НЕ переделывать A1/D — они merged в #798):

  • A2 — trgm GIN-индекс на deals.address (миграция CREATE EXTENSION pg_trgm + CREATE INDEX ... USING gin (address gin_trgm_ops); EXPLAIN-верификация — на QA после merge).
  • B — FDW fetch_size/use_remote_estimate на FOREIGN SERVER gendesign_rosreestr_deals (см. уточнение аналитика выше — искать миграцию где реально CREATE SERVER/IMPORT FOREIGN, не 060).
  • Crefresh_search_matview расписание: investigate alive-or-dead → восстановить refresh ЛИБО доказать что matview мёртв и дропнуть.
  • E — geocode city-centroid флаг (geo_precision='city'), не использовать city-fallback как точную точку в ST_DWithin.

A2/B — это идемпотентные SQL-миграции, worker-actionable без live-DB (EXPLAIN-проверку делает QA пост-merge). C — investigation. E — схема+geocoder.

✅ **QA PASS (частично)** — PR #798 (merged 17:18:34) закрывает **A1 + D**. Остальное (A2/B/C/E) — re-queue ниже. **A1 — word-boundary street match** (client-quality, влияет на аналоги в оценке): Проверил семантику Postgres-регекса на живом PG16-движке (data-independent, операторный уровень): - `'улица Адмирала Макарова' ~* '\mМира\M'` → **FALSE** (ложноположительное устранено) ✅ - `'улица Мира 5'` → TRUE; `'Космонавтов'` → TRUE; `'8 Марта 12'` (мультислово+цифра) → TRUE; `'Восточная' ~* '\mВосток\M'` → FALSE (префикс не матчит) ✅ - bind-param (`:street_regex`), не f-string; добавлен **рядом** с ILIKE-prefilter в `trade_in.py` + `estimator._fetch_dkp_corridor`; anchor/pricing/dedup не тронуты. ✅ **D — cian unescape robustness**: order-dependent `.replace()`-цепочка заменена на атомарный `json.loads` внешней quoted-строки; добавлен regression-тест с backslash-в-описании (`cianId` сохранён, страница не падает). 22 теста pass, ruff clean. ✅ --- 🔁 **Re-queue → `status/ready`** для оставшихся частей (НЕ переделывать A1/D — они merged в #798): - **A2** — trgm GIN-индекс на `deals.address` (миграция `CREATE EXTENSION pg_trgm` + `CREATE INDEX ... USING gin (address gin_trgm_ops)`; EXPLAIN-верификация — на QA после merge). - **B** — FDW `fetch_size`/`use_remote_estimate` на FOREIGN SERVER `gendesign_rosreestr_deals` (см. уточнение аналитика выше — искать миграцию где реально `CREATE SERVER`/`IMPORT FOREIGN`, не `060`). - **C** — `refresh_search_matview` расписание: investigate alive-or-dead → восстановить refresh ЛИБО доказать что matview мёртв и дропнуть. - **E** — geocode city-centroid флаг (`geo_precision='city'`), не использовать city-fallback как точную точку в `ST_DWithin`. A2/B — это идемпотентные SQL-миграции, worker-actionable без live-DB (EXPLAIN-проверку делает QA пост-merge). C — investigation. E — схема+geocoder.
bot-qa added
status/ready
and removed
status/qa
labels 2026-05-30 17:26:18 +00:00
bot-backend added
status/wip
and removed
status/ready
labels 2026-05-30 17:33:55 +00:00
bot-backend added
status/review
and removed
status/wip
labels 2026-05-30 17:38:54 +00:00
Collaborator

PR #803 (A2+B+C) → status/review. A2 trgm index (086), B FDW options ADD-or-SET (087), C — listings_search_mv оказался live но никогда не рефрешился → trigger + dispatch + seed (088, ночное расписание). E (geocode centroid) отложен — client-facing radius-match, отдельный follow-up. A1+D ранее в #798.

PR #803 (A2+B+C) → status/review. A2 trgm index (086), B FDW options ADD-or-SET (087), C — `listings_search_mv` оказался **live но никогда не рефрешился** → trigger + dispatch + seed (088, ночное расписание). E (geocode centroid) отложен — client-facing radius-match, отдельный follow-up. A1+D ранее в #798.
bot-reviewer added
status/qa
and removed
status/review
labels 2026-05-30 17:41:03 +00:00
Collaborator

QA PASS — A2+B+C (PR #804, merged 17:40:54). (NB: воркер в комменте написал «#803» — это опечатка, #803 = a11y preview для #801; реальный PR этой партии = #804, проверено по merge-коммиту a9e4aecb.)

Верифицировано по merged diff (runtime EXPLAIN — tradein-DB+deploy-gated, postgres-tradein в этом окне нет; миграции идемпотентны, раскатятся на деплое):

  • A2 (086): CREATE EXTENSION IF NOT EXISTS pg_trgm + CREATE INDEX IF NOT EXISTS deals_address_trgm_idx ON deals USING gin (address gin_trgm_ops) — идемпот, BEGIN/COMMIT. gin_trgm_ops обслуживает И ILIKE-prefilter, И ~*-регекс из A1 (pg_trgm поддерживает regex-операторы) → индекс реально полезен для актуального запроса.
  • B (087): DO-блок читает pg_foreign_server.srvoptions → ADD-if-absent / SET-if-present / no-op-if-correct (обходит ADD-vs-SET ERROR-trap, честно идемпотентно); fetch_size=10000 + use_remote_estimate=true на gendesign_remote; RAISE если сервер отсутствует.
  • C (scheduler.py + 088): trigger_refresh_search_matview_run (atomic _claim_run, executor для sync REFRESH CONCURRENTLY, mark_done/failed, по образцу asking_to_sold_ratio) + dispatch-ветка + seed ON CONFLICT DO NOTHING, enabled, 03:00-04:00 UTC, next_run на завтра. Investigation: listings_search_mv жив (читается search_query.py) но никогда не рефрешился → правильное решение = восстановить refresh, не дропать.

«Не делать» соблюдено (anchor/dedup/guard-bands не тронуты).

Post-deploy QA TODO (когда будет DB-окно tradein): EXPLAIN (ANALYZE,BUFFERS) ... FROM deals WHERE address ILIKE '%улица%' → Bitmap Index Scan на deals_address_trgm_idx; FDW-импорт-план → remote-estimate.


🔁 Re-queue → status/ready — остался только Part E (последняя из 6 частей; A1/D в #798, A2/B/C в #804):

  • E (finding #17) — geocode city-centroid флаг: адрес без дома («Екатеринбург») геокодится в city-центроид и пишется как точные lat/lon → ложная гео-точность в ST_DWithin. Fix: geo_precision='city' флаг + не использовать city-fallback как точную радиус-точку (схема + geocoder + ST_DWithin-фильтр).
  • ⚠️ E — client-facing (влияет на отбор радиус-аналогов → точность цены, demo-killer-фактор 2026-06-01). Воркер дважды откладывал как «отдельный follow-up». Если объём/риск великоват для grab-bag — вынести E в собственный issue с priority/p2 и пометить на review-внимание (меняет money-path behavior). Reviewer гейтит итоговый E-PR.
✅ **QA PASS — A2+B+C** (PR **#804**, merged 17:40:54). _(NB: воркер в комменте написал «#803» — это опечатка, #803 = a11y preview для #801; реальный PR этой партии = #804, проверено по merge-коммиту `a9e4aecb`.)_ Верифицировано по merged diff (runtime EXPLAIN — tradein-DB+deploy-gated, postgres-tradein в этом окне нет; миграции идемпотентны, раскатятся на деплое): - **A2** (`086`): `CREATE EXTENSION IF NOT EXISTS pg_trgm` + `CREATE INDEX IF NOT EXISTS deals_address_trgm_idx ON deals USING gin (address gin_trgm_ops)` — идемпот, BEGIN/COMMIT. gin_trgm_ops обслуживает И `ILIKE`-prefilter, И `~*`-регекс из A1 (pg_trgm поддерживает regex-операторы) → индекс реально полезен для актуального запроса. ✅ - **B** (`087`): `DO`-блок читает `pg_foreign_server.srvoptions` → ADD-if-absent / SET-if-present / no-op-if-correct (обходит ADD-vs-SET ERROR-trap, честно идемпотентно); `fetch_size=10000` + `use_remote_estimate=true` на `gendesign_remote`; RAISE если сервер отсутствует. ✅ - **C** (`scheduler.py` + `088`): `trigger_refresh_search_matview_run` (atomic `_claim_run`, executor для sync REFRESH CONCURRENTLY, mark_done/failed, по образцу asking_to_sold_ratio) + dispatch-ветка + seed `ON CONFLICT DO NOTHING`, enabled, 03:00-04:00 UTC, next_run на завтра. Investigation: `listings_search_mv` жив (читается `search_query.py`) но никогда не рефрешился → правильное решение = восстановить refresh, не дропать. ✅ «Не делать» соблюдено (anchor/dedup/guard-bands не тронуты). **Post-deploy QA TODO** (когда будет DB-окно tradein): `EXPLAIN (ANALYZE,BUFFERS) ... FROM deals WHERE address ILIKE '%улица%'` → Bitmap Index Scan на `deals_address_trgm_idx`; FDW-импорт-план → remote-estimate. --- 🔁 **Re-queue → `status/ready`** — остался **только Part E** (последняя из 6 частей; A1/D в #798, A2/B/C в #804): - **E** (finding #17) — geocode city-centroid флаг: адрес без дома («Екатеринбург») геокодится в city-центроид и пишется как точные lat/lon → ложная гео-точность в `ST_DWithin`. Fix: `geo_precision='city'` флаг + не использовать city-fallback как точную радиус-точку (схема + geocoder + ST_DWithin-фильтр). - ⚠️ **E — client-facing** (влияет на отбор радиус-аналогов → точность цены, demo-killer-фактор 2026-06-01). Воркер дважды откладывал как «отдельный follow-up». Если объём/риск великоват для grab-bag — вынести E в собственный issue с priority/p2 и пометить на review-внимание (меняет money-path behavior). Reviewer гейтит итоговый E-PR.
bot-qa added
status/ready
and removed
status/qa
labels 2026-05-30 17:47:50 +00:00
bot-backend added
status/wip
and removed
status/ready
labels 2026-05-30 18:08:28 +00:00
bot-backend added
status/review
and removed
status/wip
labels 2026-05-30 18:22:43 +00:00
Collaborator

PR (E) → status/review. Все 5 частей закрыты: A1+D (#798), A2+B+C (#804), теперь E — geo_precision='city' флаг + исключение city-centroid из radius-аналогов (Tier H+W, IS DISTINCT FROM → NULL проходит, сдвига до backfill нет). Pricing не тронут. 270 тестов pass. Backfill существующих city-coords — ops follow-up (в миграции 089 отмечено).

PR (E) → status/review. **Все 5 частей закрыты**: A1+D (#798), A2+B+C (#804), теперь **E** — geo_precision='city' флаг + исключение city-centroid из radius-аналогов (Tier H+W, `IS DISTINCT FROM` → NULL проходит, сдвига до backfill нет). Pricing не тронут. 270 тестов pass. Backfill существующих city-coords — ops follow-up (в миграции 089 отмечено).
lekss361 modified the milestone from Praktika demo — Mon 2026-06-01 to Night batch — 2026-05-31 2026-05-30 19:39:07 +00:00
lekss361 added
status/qa
and removed
status/review
labels 2026-06-06 18:43:18 +00:00
Owner

Status actualize (06.06): все части влиты в main#798 (A1+D), #804 (A2+B+C), #811 (Part E). Открытых PR нет. status/reviewstatus/qa.

Status actualize (06.06): все части влиты в `main` — #798 (A1+D), #804 (A2+B+C), #811 (Part E). Открытых PR нет. `status/review` → `status/qa`.
Collaborator

Already-done (verified prod 2026-06-13). Аудит-карта May30 устарела целиком — все 5 частей реализованы в PR #804 (a9e4aec) + b736d7b:

  • A word-boundary regex (trade_in.py/estimator.py используют ~* '\m<street>\M') + trgm-индекс deals_address_trgm_idx (на prod). «Мира» ≠ «Адмирала Макарова», тест есть.
  • B FDW gendesign_remote srvoptions = fetch_size=10000, use_remote_estimate=true (миграция 087, на prod).
  • C matview-refresh scheduler разведён (trigger + dispatch + seed 088). ⚠️ ops-нюанс: на prod scrape_schedules.refresh_search_matview.enabled=false (runtime toggle, часть общей scraping-паузы) — re-enable = ops-решение, не code. matview активно читается search_query.py (не мёртв).
  • D cian unescape → json.loads (cian_state_parser.py), тест с backslash есть.
  • E geo_precision колонка (миграция 089), city-центроиды исключены из radius-аналогов (estimator.py). Prod: city=769/house=5447/NULL=32899.

ruff/pytest: 33 passed на затронутых сьютах. Закрываю.

**Already-done (verified prod 2026-06-13).** Аудит-карта May30 устарела целиком — все 5 частей реализованы в PR #804 (`a9e4aec`) + `b736d7b`: - **A** word-boundary regex (`trade_in.py`/`estimator.py` используют `~* '\m<street>\M'`) + trgm-индекс `deals_address_trgm_idx` (на prod). «Мира» ≠ «Адмирала Макарова», тест есть. - **B** FDW `gendesign_remote` srvoptions = fetch_size=10000, use_remote_estimate=true (миграция 087, на prod). - **C** matview-refresh scheduler разведён (trigger + dispatch + seed 088). ⚠️ ops-нюанс: на prod `scrape_schedules.refresh_search_matview.enabled=false` (runtime toggle, часть общей scraping-паузы) — re-enable = ops-решение, не code. matview активно читается `search_query.py` (не мёртв). - **D** cian unescape → `json.loads` (`cian_state_parser.py`), тест с backslash есть. - **E** `geo_precision` колонка (миграция 089), city-центроиды исключены из radius-аналогов (`estimator.py`). Prod: city=769/house=5447/NULL=32899. ruff/pytest: 33 passed на затронутых сьютах. Закрываю.
Sign in to join this conversation.
No project
No assignees
4 participants
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference: lekss361/gendesign#769
No description provided.