# ACO: глубокий разбор 16.10.2026 — выборка объявлений, цены, карты; план по фазам С1–С6

Разбор сделан на срезе `a26bb5a` ветки `claude/release-1.0-fixes` (16.10.2026 03:20) — это последняя версия кода;
прод `aco.24oros.ru` работает на `4c4408e`, рядом подняты `aco-f33` (`f33-a26bb5a`) и `aco-next` (`next-8b5d854`).

Предыдущие документы: [PLAN-2026-10-16-FILES.md](PLAN-2026-10-16-FILES.md) (фазы П1–П7: надёжность, бета, разбивка
файлов, ускорение, проверки, пилот) и [PLAN-2026-10-15.md](PLAN-2026-10-15.md). Этот разбор их **не повторяет**: он
занимается тем, чего в них почти нет, — как именно отбираются объявления, как из их цен получается итог и как работают
карты. Макеты: [mockups/plan-2026-10-16-selection/index.html](../mockups/plan-2026-10-16-selection/index.html).
Приёмочные проверки: [TEST-ACCEPTANCE-2026-10-16.md](TEST-ACCEPTANCE-2026-10-16.md).

Онлайн (Сагар, контейнер `aco-selection-1016`): **https://aco-selection-1016.24oros.ru/** — макеты и оба документа.
Проверено снаружи 16.10.2026: страница и `docs/*.md` — 200, сертификат Let's Encrypt до 13.01.2027, http → https.

---

## 1. Что проверено в этот раз и чем это подтверждено

| Проверка | Как запущено | Результат |
|---|---|---|
| Тесты бэкенда | `PYTHON=.../.venv/bin/python ./scripts/run_tests.sh -q` | **929 прошли, 7 пропущены**, 119 с, код 0 |
| Правила кода и типы фронтенда | `npm run lint` (eslint `--max-warnings 0` + `tsc --noEmit`) | **0 замечаний**, код 0 |
| Сборка фронтенда | `npm run build` (`tsc -b` + vite + упаковка расширения + `check-map-worker`) | код 0; воркер карты на месте |
| Размеры сборки | из вывода vite | карта 1 049 кБ (287 кБ gzip), воркер карты 510 кБ (144 кБ), вход 351 кБ (118 кБ), справка 192 кБ (74 кБ) |
| Поведение отбора | проба на `_unlikeness` искусственными данными (п. 2.3) | порядок подтверждает В-1 |
| Состав поправок | чтение `methodology_1_6_2.json` | 5 корректируемых элементов, 5 с нулём и обоснованием |
| Сквозные проверки интерфейса | `npm run test:e2e` (38 файлов) | **91 прошла**, 2,1 мин, код 0 (в воркtree не было venv — добавлена ссылка на общий) |

Прод живыми запросами в этой сессии **не проверялся**: защита среды не пропустила ни чтение `/health/release`, ни
чтение файлов окружения на сервере. Поэтому всё ниже опирается на код, тесты и записи выкладок, а не на замеры прода;
что нужно замерить на проде — в С5 и в приёмочном документе.

---

## 2. Выборка объявлений и цены — как это работает сегодня

### 2.1. Путь от адреса до итоговой цифры

| № | Шаг | Где в коде | Чем ограничено |
|---|---|---|---|
| 1 | Запрос к источнику: город (для села — область), комнатность (только квартиры, строгое равенство), площадь ±25 %, продажа/аренда, прямоугольник радиуса | `api/directory.py:389` `market_search`, `:322` `_catalog_place` | радиус 500 м…50 км |
| 2 | Яндекс Недвижимость: открытый каталог читается сервером | `parser/yandex_realty.py:246` `search(limit=20)` | **первые 20 в порядке релевантности самого Яндекса** |
| 3 | Циан, Авито, Домклик: сервер ACO они не пускают (403/429/401), данные берутся у поставщика Inpars по API | `parser/inpars.py:258` `search`, `sortBy=updated_desc` | 200 за запрос, 10 запросов в минуту, ключ платный |
| 4 | Расстояние до объекта, отсев дальше радиуса; без точки — помечается `no_point` и уходит в конец | `api/directory.py:359` `_within` | без точки объекта радиус не применяется |
| 5 | Сортировка по «непохожести»: площадь, первый этаж, год постройки, этажность | `api/directory.py:335` `_unlikeness` | **ни расстояния, ни цены** |
| 6 | У поставщика остаются 15 на площадку — они ложатся в «Собранные» | `api/directory.py:499` `PROVIDER_KEEP = 15` | обрезка по шагу 5 |
| 7 | Кольца 500 м → 1,5 км → 3 км → 5 км (дом до 10 км, участок до 25 км): первое кольцо, где набрался минимум | `domain/categories.py:185` `RINGS_M`, `:353` `choose_ring` | минимум — 5 аналогов |
| 8 | Лента найденного сортируется по сходству: 70 баллов за малые ожидаемые поправки, 20 за расстояние, 10 за полноту; штраф −10 за цену 1 м² дальше ±35 % от медианы и −5 за разницу лет > 25 | `frontend/src/lib/similarity.ts` `methodSimilarity`, `marketFlags` | считается в браузере |
| 9 | «Взять 5 лучших» переносит верхние пять в карточки аналогов | `components/object/MarketSources.tsx:238` | — |
| 10 | Поправки: торг, площадь, этаж, отделка, стены. Вес 1/(σ₀² + (c·Σ)²), доля одного аналога ≤ 40 %, отсев по Хампелю на логарифме цены, средневзвешенная, таблица устойчивости | `calculator/service.py`, `calculator/robust.py`, `methodology_1_6_2.json` | методика 1.6.2 |

Шаги 7–10 сделаны хорошо и подтверждены эталонами (8 дел до рубля). Слабое место — шаги 2, 5 и 6.

### 2.2. Расчётная часть: придираться почти не к чему

Это надо сказать прямо, чтобы план не выглядел списком претензий. Вес аналога по обратной дисперсии вместо 1/(ε+Σ),
потолок доли 40 %, отсев по Хампелю с защитой самого весомого, одна функция `_comparative_estimate` и для расчёта, и
для перерасчёта, таблица устойчивости «итог без каждого аналога и при каждой поправке ±10 %», запрет расхождения
методики и отчёта (параметры печатаются в данные отчёта) — это уровень, на котором расчёт можно защищать перед
проверяющим. Устойчивые статистики вынесены в отдельный модуль без базы и сети и тестируются мгновенно.

### 2.3. В-1 (главное). Список обрезается ранжированием, которое не знает ни расстояния, ни цены

`_unlikeness` считает непохожесть по площади, первому этажу, году постройки и этажности. Расстояния в ней нет —
хотя оно уже посчитано шагом раньше, в `_within`. Цены нет тоже.

Проба на искусственных данных (объект: 48 м², 3-й этаж из 5, 1972 год):

| Объявление | Расстояние | Площадь | Цена 1 м² | «Непохожесть» | Место в выдаче |
|---|---|---|---|---|---|
| ул. Другая, 90 | 4 800 м | 48 м² | 145 833 ₽ | 0,0000 | **1** |
| ул. Ленина, 5 (приманка) | 300 м | 48 м² | 39 583 ₽ | 0,0000 | 2 |
| ул. Ленина, 3 | 180 м | 50 м² | 80 000 ₽ | 0,0417 | 3 |

Первым идёт аналог за 4,8 км по цене вдвое выше рынка, вторым — приманка вдвое ниже, последним — тот, который и нужен.

Почему это важнее, чем кажется:

* у Яндекса обрезка до 20 объявлений происходит **в порядке релевантности Яндекса**, до фильтра радиуса и до
  сортировки ACO: близкий дом-двойник, стоящий у Яндекса на второй странице, в ACO не попадает вообще;
* у поставщика из 200 найденных остаются 15 на площадку — и выбирает их именно `_unlikeness`;
* правильное ранжирование (`methodSimilarity`) живёт в браузере и сортирует только то, что доехало. «5 лучших»
  выбираются из уже испорченного пула;
* чем теснее кольцо, тем выше шанс, что близкие объявления отсеклись раньше — то есть ошибка растёт там, где качество
  важнее всего.

Тестом порядок не покрыт: `tests/test_search_radius.py` проверяет, что дальше радиуса отсекается, но не проверяет, кто
стоит первым.

### 2.4. В-2. Два определения сходства на двух языках

`_unlikeness` (Python, бэкенд) и `methodSimilarity` + `marketFlags` (TypeScript, браузер) считают разное и живут
отдельно. Любая правка методики — кольца, предел суммы поправок, пороги — должна попасть в оба места, и ничто этого не
сторожит. Это ровно тот тип расхождения, из-за которого в проекте однажды разъехались чек-лист и гейт выгрузки (и
потому сборку проверок вынесли в `services/readiness.py`).

### 2.5. В-3. Допуски площади разъехались и не берутся из методики

| Место | Допуск | Код |
|---|---|---|
| Подбор у источников | ±25 % | `api/directory.py:439` `area * 0.75 … area * 1.25` |
| Подсказки из базы оценщика | ±30 % | `services/market_base.py:41` `AREA_TOLERANCE = 0.30` |

Оба числа зашиты в код, а не взяты из формы категории или методики — хотя для участка и для квартиры разумный допуск
разный (у участка цена 1 м² падает с площадью заметно сильнее: показатель −0,25 против −0,08).

### 2.6. В-4. Флаг «цена выбивается» не работает в тот момент, когда он нужен

Медиана для флага считается по уже собранным объявлениям: `medianPricePerM2([...captures, ...legacy])`
(`MarketSources.tsx:159`), а при меньше трёх значениях возвращается `null` — флага нет совсем. То есть на первом
подборе, когда оценщик впервые смотрит ленту и жмёт «Взять 5 лучших», приманка ничем не помечена. Медиану надо считать
по всему найденному пулу (он как раз и есть выборка рынка), а не по тому, что уже отложено.

### 2.7. В-5. Нулевая поправка на местоположение печатается без всякой проверки

В отчёт дословно уходит обоснование из методики:

> **Местоположение.** Аналоги подобраны в том же населённом пункте и сегменте рынка (расстояние до объекта — в таблице
> источников); поправка 0 %.

При этом:

* кольца расширяются до 5 км для квартиры, 10 км для дома, 25 км для участка (`RINGS_M`);
* для села подбор идёт по **всей области** (`_catalog_place`: «Яндекс не знает слага села»), то есть аналог может быть в
  другом населённом пункте — и обоснование станет неправдой;
* в `services/release_rules.py` правила про расстояние аналогов **нет** (есть разрыв даты предложения 3 месяца и в
  контроле документа — метро не дальше 10 км);
* поправки на местоположение в методике нет вовсе: `comparison_elements.adjusted` — только `trade`, `area`, `floor`,
  `condition`, `wall_material`.

Сравним с датой предложения: там ровно такое же «поправка не вводится», но оно подпёрто правилом выпуска
(`release_rules.py:304–357`: разрыв больше 3 месяцев — предупреждение с номерами аналогов). У местоположения такой
страховки нет. Это не ошибка в цифрах, это утверждение в юридическом документе, которое программа не проверяет.

### 2.8. В-6. Одна квартира с двух площадок может попасть в расчёт дважды

Предупреждение есть — в редакторе аналогов: «похоже на аналог № N» при совпадении адреса, площади и этажа
(`AnalogEditor.tsx:394`). Чего нет:

* в ленте найденного такого предупреждения нет, и «Взять 5 лучших» спокойно возьмёт два объявления одной квартиры;
* выпуск этим не блокируется — правила в `release_rules.py` нет;
* для расчёта это два независимых наблюдения: размер выборки завышен, суммарный вес этой квартиры — до 80 % при
  потолке 40 % на каждое;
* готовая функция `_one_per_flat` (`market_base.py:263`) применяется только в подсказках и сводке рынка.

### 2.9. В-7. Полугодовое окно без приведения цен к дате

`FRESH_DAYS = 180`: в сводку рынка попадают наблюдения за полгода, медиана считается по всем сразу, период печатается
как «12.04.2026–16.10.2026». Поправки на дату предложения нет (осознанно, см. 2.7), но тогда разброс внутри окна
должен хотя бы попадать на глаза — сейчас он не показывается.

### 2.10. В-8. Коэффициенты поправок не откалиброваны — и это печатается в отчёте

Все значения в `methodology_1_6_2.json` и `refbook.DEFAULT_TABLES` помечены «до калибровки, порядок величин, заменить
значением справочника для региона объекта»: торг −5 %, показатель площади −0,08, этаж 0,93 / 1,0 / 0,96, отделка
0,7…1,25, стены 0,85…1,05. Честность формулировок — плюс, но для банка это единственная часть расчёта без источника, и
спросят именно про неё. Техническая часть (`refbook.py` с `citation()` вида «Справочник…, 2024, с. 215, табл. 136»)
готова — не хватает самих значений.

---

## 3. Карты: что работает и где рвётся

### 3.1. Что работает

| Что | Как сделано | Подтверждение |
|---|---|---|
| Карта на экране | MapLibre, стиль OneMaps «liberty» через прокси `/onemaps/…`, подписи приводятся к русским | `components/OneMap.tsx` |
| Живучесть стиля | 6 с на стиль OneMaps по `AbortController`, затем тот же стиль прямо с OpenFreeMap, затем URL в руки MapLibre | `OneMap.tsx:72–111` |
| Воркер | своим файлом сборки (`?worker&url`), после сборки проверяется скриптом | `check-map-worker: ok` в сборке сегодня |
| Точка дома | OneMaps `/suggest` → `/buildings/resolve`: этажность, тип дома, код ФИАС, контур | `services/onemaps.py` |
| Окружение и метро | рубрики OneMaps + пешеходный маршрут OSRM — «N минут пешком», а не «по прямой» | `services/location_context.py` |
| Схема в отчёт | PyMuPDF: дороги, вода, контуры домов, радиус, объект и пронумерованные аналоги, линейка, север, атрибуция | `services/map_scheme.py` |
| Расстояния до аналогов | только точка уровня дома; не нашлось — честно «расстояние не определено» | `services/report_location.py` |

Подход правильный: ни один сбой карты не роняет расчёт, у каждого внешнего вызова есть предел времени и запасной путь.

### 3.2. К-1. Отчёт может уйти со схемой без карты, и об этом никто не узнаёт

Под нагрузкой Сагара отрисовка подложки (до 18 тыс. объектов, ~7 с) не укладывается в запас 10 с, и тогда схема
рисуется без подложки за 0,05 с (`report_location.py:154–164`, правка от 16.10 03:20). Решение само по себе верное —
лучше схема без подложки, чем потеря всего раздела. Но:

* признак `with_layers` возвращается в API (`api/report_map.py:99`) и описан в типе фронтенда
  (`api/objects.ts:193`) — и **ни на одном экране не показан**;
* в документе тоже нет пометки, что схема без подложки;
* то есть оценщик подтверждает и отдаёт в банк отчёт, не зная, что карта в нём — голые точки на пустом поле.

### 3.3. К-2. Слои окна не кэшируются

`onemaps.window_layers` (`:707`) зовёт `_request` напрямую, а кэш `_cached` / `_remember` (сутки, 4 000 записей)
применяется только в `geocode`, `building` и окружении. Значит каждый перерасчёт и каждое нажатие «Обновить карту и
расстояния» заново тянут три GeoJSON, включая до 18 тыс. контуров домов на zoom 16 — для картинки 760×520 pt, где
большинство этих домов занимает 1–2 пикселя.

### 3.4. К-3. Нет ни предела числа объектов подложки, ни прореживания по масштабу

Запрос один и тот же — `buildings.geojson?zoom=16` — и для кольца 500 м, и для кольца 5 км. Корень К-1 именно здесь: не
сеть, а отрисовка того, что рисовать не нужно. Ограничивать время уже научились; ограничивать объём — ещё нет.

### 3.5. К-4. Карта — самый тяжёлый кусок фронтенда

Сборка сегодня: `OneMap` 1 049 кБ (287 кБ gzip) и воркер 510 кБ (144 кБ) — общий код MapLibre лежит в обоих, и vite об
этом прямо предупреждает. Это уже стоит в плане П4 (`manualChunks`, карта по появлению блока в окне) — здесь только
подтверждаю числа, чтобы фазы не пересекались.

### 3.6. К-5. Два слабых места сходятся в одной точке

Бюджет шага разделён жёсткими константами: 25 с всего, 8 с на точки аналогов, 10 с запас на схему, 2 с на запись. При
медленном OneMaps первыми страдают точки аналогов — остаётся «расстояние не определено». А ровно на этих расстояниях
держится обоснование нулевой поправки на местоположение (В-5): «расстояние до объекта — в таблице источников». Нет
расстояний → обоснование проверить нечем, а печатается оно всё равно.

---

## 4. План по фазам С1–С6

Фазы названы С (сравнительный подход и сбор), чтобы не путаться с П1–П7 плана от 16.10, который в работе у другой
сессии. **Разделение файлов** (правило «две сессии не правят одни файлы»):

| Файлы | Чьи |
|---|---|
| `api/directory.py`, `parser/*`, `lib/similarity.ts`, `MarketSources.tsx`, `release_rules` (правило расстояния), `map_scheme.py`, `onemaps.py` (кэш окна), `report_location.py` | С1–С6 (этот план) |
| `compose.yml`, `nightly-check.sh`, `external-check.sh`, `ReleasePanel.tsx`, `legal.py`, `Dashboard.tsx`, `AdminPage.tsx`, `vite.config.ts`, `OneMap.tsx`, `main.tsx` | П1–П7 (план 16.10) |

Пересечение одно: `onemaps.py` разбивается в П3 и правится в С4. Разумный порядок — сначала С4 (маленькая правка в
`window_layers`), затем П3 разносит модуль уже с ней.

### С1. Одно ранжирование на всех и обрезка по нему · 17–19.10

Главная фаза: она закрывает В-1, В-2, В-3 и половину В-4.

| Файл | Что сделать | Готово, когда |
|---|---|---|
| новый `backend/app/domain/listing_rank.py` | чистая функция `score(subject, listing, distance_m, tables, median_ppm)` — ровно та же формула, что в `lib/similarity.ts`: 70 баллов ожидаемых поправок, 20 расстояние, 10 полнота, штрафы за цену ±35 % и год > 25. Без базы и HTTP | есть тесты на каждое слагаемое |
| `backend/app/api/directory.py` | сортировка и обрезка — по `listing_rank.score`, а не по `_unlikeness`; `_unlikeness` удаляется | проба из 2.3 даёт порядок 180 м → 4,8 км → приманка последней |
| `backend/app/api/methodology.py` | отдавать браузеру те же пороги (±35 %, 25 лет, пояса расстояний), что использует бэкенд | фронт не хранит своих копий порогов |
| `frontend/src/lib/similarity.ts` | пороги из `/methodology/current`, формула остаётся общей по смыслу | один набор чисел на два языка |
| новый `backend/tests/test_listing_rank.py` + `frontend/e2e/similarity-method.spec.ts` | один и тот же набор из 6 объявлений даёт один и тот же порядок на сервере и в браузере | расхождение роняет тест |
| `backend/app/api/directory.py`, `parser/yandex_realty.py` | допуск площади — из формы категории (участок шире квартиры), а не из константы; у Яндекса брать 2–3 страницы каталога, когда в радиусе набралось меньше минимума кольца | в кольце 500 м объявлений не меньше, чем раньше в 3 км |

Цена вопроса: `_unlikeness` — 25 строк, `listing_rank` — около 80. Эталоны расчёта не затрагиваются: ранжирование
влияет на то, что предложено, а не на то, как считается.

### С2. Приманки и двойники видны до переноса в карточки · 19–21.10

| Файл | Что сделать |
|---|---|
| `frontend/src/components/object/MarketSources.tsx` | медиана цены 1 м² — по всему найденному пулу, а не по «Собранным»; показывать её над лентой («медиана найденного: 82 400 ₽/м², разброс 71–94 тыс.») |
| `MarketSources.tsx`, `MarketSourceParts.tsx` | у каждой строки — пометка «цена ниже медианы на 52 % — проверьте объявление» и «похоже на № N: тот же адрес, площадь и этаж»; «Взять 5 лучших» помеченные не берёт, пока оценщик не подтвердит |
| новый `backend/app/domain/flat_twins.py` (перенос `_one_per_flat`) | один ключ квартиры на все площадки; использовать и в подсказках, и в ленте, и в правилах выпуска |
| `backend/app/services/release_rules.py` | новое правило: два аналога с одним ключом квартиры — предупреждение с номерами; подтверждается осознанно, как бета-вид |
| `backend/tests/test_market_base.py` | тест: Циан и Яндекс об одной квартире — одно наблюдение и предупреждение в выпуске |

### С3. Обоснование нулевой поправки на местоположение становится правдой · 21–24.10

| Файл | Что сделать |
|---|---|
| `backend/app/services/release_rules.py` | правило: все аналоги — в том же населённом пункте и в выбранном кольце. Дальше кольца или в другом населённом пункте — предупреждение с номерами и расстояниями; без расстояния — отдельная строка «расстояние не определено: № 2, 4» |
| `backend/app/calculator/methodology_1_6_3.json` (новая версия) + `docs/ADR-methodology-1.6.3.md` | обоснование `location` переписать так, чтобы оно зависело от данных: «все аналоги — в том же населённом пункте, в радиусе N м (таблица источников)»; при расширении кольца за пределы — текст про единый сегмент рынка с перечислением расстояний |
| `backend/app/generator/sections/comparative.py` | печатать радиус кольца и максимальное расстояние аналога рядом с обоснованием |
| `backend/app/services/document_qa.py` | проверка: напечатанное обоснование соответствует фактическим расстояниям |
| `backend/tests/golden/cases` | эталон «село, аналоги по области» — обоснование другое, чем у городской квартиры |

Это единственная фаза, которая меняет текст отчёта, поэтому — отдельной версией методики (1.6.3) и с ADR: прежние
отчёты должны пересчитываться прежним текстом.

### С4. Схема карты укладывается в бюджет и честно о себе сообщает · 22–24.10

| Файл | Что сделать | Цель |
|---|---|---|
| `backend/app/services/onemaps.py` | `window_layers` — через `_cached` / `_remember` (ключ: город + округлённое окно), сутки | повторный расчёт не ходит в сеть |
| `backend/app/services/onemaps.py` | zoom запроса домов — от ширины окна (кольцо ≤ 1,5 км → 16, 3 км → 15, дальше → 14); предел числа объектов в ответе | объектов в разы меньше при том же виде |
| `backend/app/services/map_scheme.py` | не рисовать контуры меньше 1,5 pt и дороги класса ниже `residential` при ширине окна > 3 км | 18 тыс. объектов → 2–4 тыс. |
| `backend/app/services/report_location.py` | бюджет — долями от остатка, а не константами; запас на схему считается по измеренной скорости | схема с подложкой при load 80 |
| `frontend/src/components/report/ReportLocationCard.tsx` | показать `with_layers`: «схема без подложки — обновить» с кнопкой | оценщик видит, что уйдёт в банк |
| `backend/app/generator/sections/comparative.py` | подпись под схемой без подложки: «схема расстояний без картографической подложки» | документ не вводит в заблуждение |
| `backend/tests/test_location_partial.py` | тест: при коротком бюджете схема без подложки и признак `with_layers=false` доходит до API | — |

### С5. Замеры на проде и приёмка выборки · 24–27.10

| Что | Как |
|---|---|
| Порядок выдачи на живых данных | три города (Рязань, Москва, село в Рязанской области), три кольца; записать, какие объявления пришли первыми до и после С1 |
| Качество «5 лучших» | на 10 делах: сколько из пяти оценщик оставил без замены (цель — не меньше 4 из 5) |
| Время `/directory/market-search` | медиана и максимум до и после С1 (ожидание: не хуже, лишних запросов нет) |
| Схема с подложкой | 10 расчётов при load > 50: доля схем с подложкой (цель ≥ 90 %) |
| Слои окна | число запросов к OneMaps на один повторный расчёт (цель 0 после кэша) |
| Приёмка | по документу [TEST-ACCEPTANCE-2026-10-16.md](TEST-ACCEPTANCE-2026-10-16.md) — все П-проверки зелёные |

### С6. Калибровка коэффициентов · после 1.0 (вместе с пилотом)

| Что | Как |
|---|---|
| Торг по регионам | собрать по сделкам пилота и по справочнику; заменить `trade` в `refbook` с `citation()` |
| Показатель площади | оценить по собранной базе объявлений оценщика (уже есть `market_base`: цена 1 м² по группам площади) |
| Этаж, отделка, стены | то же по группам базы; где данных мало — оставить «до калибровки» честно |
| Признак в отчёте | печатать источник каждой поправки: справочник или «до калибровки» (механика `citation()` уже есть) |

Критерий: в отчёте по квартире в городе-миллионнике и в областном центре ни одна поправка не помечена «до калибровки».

---

## 5. Что это даст

| Сейчас | После С1–С4 |
|---|---|
| Первым в ленте может стоять аналог за 4,8 км по цене вдвое выше рынка | первым стоит ближайший сопоставимый; дальние — ниже и с пометкой расстояния |
| Приманка вдвое ниже рынка не помечена, пока не собрано ≥ 3 объявлений | помечена с первой выдачи, в «5 лучших» сама не попадает |
| Одна квартира с Циана и Яндекса — два аналога в расчёте | одно наблюдение, предупреждение при выпуске |
| «Аналоги в том же населённом пункте, поправка 0 %» печатается всегда | печатается, когда это правда; иначе — другой текст и предупреждение |
| Схема без подложки уходит в банк молча | видно на экране и подписано в документе; подложка успевает в 9 случаях из 10 |
| Повторный расчёт снова тянет 18 тыс. контуров домов | берёт из кэша; объектов в разы меньше |
| Сходство считается по-разному на сервере и в браузере | одна формула, расхождение роняет тест |

---

## 6. Что нужно от владельца

1. **Ключ поставщика Inpars** (899 ₽/мес на регион) — без него Циан, Авито и Домклик не подбираются вовсе, и вся
   выборка висит на одном Яндексе. Это самый дешёвый способ поднять качество выборки прямо сейчас.
2. **Решение по С3**: менять текст обоснования местоположения в отчёте — значит выпускать методику 1.6.3. Подтвердить,
   что это делаем до 1.0, а не после.
3. **Значения справочника** (торг, показатель площади, этаж) хотя бы для Рязани и Москвы — или согласие выпускать 1.0 с
   честной пометкой «до калибровки».
4. **Доступ для замеров** (С5): либо учётная запись «проверяющий» на проде, либо разрешение сессии читать
   `/health/release` и делать живые запросы к `aco.24oros.ru`.
