--- type: tech-risks work_item_id: ET-009 title: "Технические риски — ET-009: Активация EnduroRussia + Wikiloc" version: 1 status: approved created_at: 2026-06-01 authors: - "agent:architect" --- # Технические риски — ET-009 Технические риски этапа активации двух новых GPS-источников. Бизнес-риски — в BRD §6 ET-009. Многие риски наследуются от ET-008 (R-1, R-5, R-9 из `docs/work-items/ET-008/10-tech-risks.md`); здесь — специфика ET-009. Шкала: вероятность (Н/С/В) × влияние (Н/С/В). ## R-1 — Wikiloc меняет HTML → парсер возвращает 0 треков - **Описание:** Парсер Wikiloc опирается на regex-извлечение `` и `

` для названия. Wikiloc может в любой момент изменить разметку (новый шаблон, JS-rendering) → парсер вернёт 0 треков. - **Вероятность / Влияние:** В / С. - **Митигация:** - Парсер уже спроектирован **graceful**: `return` без `raise` при отсутствии match'ей regex (см. `wikiloc.py::_extract_track_paths`). - Health-эндпоинт показывает `tracks_by_source.wikiloc = 0` после прогона → видимый сигнал оператору. - Unit-тест UT-WL-01 на снимке `wikiloc-search-page1.html` — при смене разметки CI зелёным быть не сможет, разработчик обновит фикстуру + парсер за 1 итерацию. - `gps_sources.yaml::wikiloc.enabled: false` — мгновенное отключение без deploy при критической поломке. - **Наследник от:** ET-008 R-1 (general). ## R-2 — Wikiloc банит IP mva154 - **Описание:** Скрейпер с фиксированного IP может попасть в чёрный список Wikiloc'а (особенно при ошибках rate-limit или накоплении 1000+ запросов в сутки). Pipeline начнёт получать 403/429 на все запросы → новых треков не будет. - **Вероятность / Влияние:** С / В. - **Митигация:** - `rate_limit_sec: 10` — самый консервативный rate в проекте. - `max_tracks_per_run: 50` — soft-cap на первом прогоне; ≤ 150 запросов на одну активацию. - `User-Agent` с контактным URL — платформа может связаться через email до бана. - **Graceful-stop** на 403/429 — не агрессивный retry, не вызывает дополнительных запросов. - **Мониторинг первых 3 прогонов** оператором; при систематических 403 → `enabled: false` + новый ADR-update «Wikiloc deprecated». - Запрет использования прокси через сторонний IP (нарушает дух прозрачности; см. ET-008 R-5). ## R-3 — EnduroRussia API меняет схему ответа - **Описание:** `enduro_russia.py::_parse_gpx` ожидает поля `id`, `name`, `difficulty`, `created_at` в JSON-items. Платформа может добавить/переименовать поля. - **Вероятность / Влияние:** Н / С. - **Митигация:** - Парсер использует `.get()` с дефолтами — отсутствие необязательных полей не валит. - Отсутствие `id` → запись пропускается (`continue`), не валит весь прогон. - Контрактный smoke-тест `tests/contract/test_endurorussia_api_smoke.py` с маркером `@pytest.mark.network` — запускается nightly или вручную, сигнализирует о поломке внешнего API до пропущенного cron-прогона. - Pipeline-error не лоадит всю БД: `errors_json` фиксирует, оператор видит через `/health`. ## R-4 — Расхождение конфига `enduro-russia.ru` (с дефисом) vs реального `endurorussia.ru` (без дефиса) - **Описание:** До ET-009 `gps_sources.yaml::enduro_russia.base_url` содержит `https://enduro-russia.ru` (с дефисом), но реальный домен — `https://endurorussia.ru` (без дефиса; парсер по default использует именно его). При активации `enabled: true` без фикса URL парсер использовал бы default из кода, но `external_url` сохранённых треков опирался бы на `base_url` из конфига → fragmentation external_url'ов между «корректным» и «дефис-вариантом». - **Вероятность / Влияние:** Случилось (известный bug в конфиге) / В (при активации). - **Митигация:** - **F-01 в BRD/TRZ** — фикс URL в одно изменение. - **Регрессионный тест UT-ER-05** — проверяет, что парсер сохраняет URL без дефиса при передаче `base_url` без дефиса. - One-shot UPDATE для существующих треков (опционально, см. `07-infra-requirements.md` §4.1). ## R-5 — EnduroRussia и Wikiloc — двойник одного и того же трека → массовые дубли - **Описание:** Авторы часто публикуют одну и ту же поездку и на Wikiloc, и на EnduroRussia (Wikiloc даже сохраняет `creator=Wikiloc` в GPX мета-теге, что подтверждается на практике). Без правильно работающего dedup'а в БД появятся два трека с одинаковой геометрией. - **Вероятность / Влияние:** В / С. - **Митигация:** - `compute_dedup_key` (ADR-006) основан на `bbox+length+date`, который при достаточно похожих координатах и одной дате попадает в один bucket → upsert ON CONFLICT мержит. - **Интеграционный тест IT-DEDUP-01** — задаёт фикстуру `wikiloc-track.gpx` с координатами, совпадающими с одним из EnduroRussia-треков; проверяет итоговое объединение `sources_json=['enduro_russia','wikiloc']`. - Метаданные при merge — берутся от source с большим `source_priority` (`enduro_russia=80 > wikiloc=70`); `external_urls` — оба сохраняются. - Если на практике dedup пропускает (например, точное время / точный bbox slightly off): план отступления ADR-006 §8 (сузить length-bucket, добавить activity). ## R-6 — Cron первого прогона превышает окно из-за rate-limit Wikiloc - **Описание:** При больших cap'ах `max_tracks_per_run` и rate-limit 10 сек × 3 запроса/трек первый прогон Wikiloc может занять часы. - **Вероятность / Влияние:** С / Н. - **Митигация:** - `max_tracks_per_run: 50` — soft-cap → ≤ 25 минут на прогон Wikiloc. - EnduroRussia при rate-limit 5 сек × 305 треков ≈ 25 минут — окей. - Cron автоматизация **отложена** до отдельного DevOps-task'а после двух успешных ручных прогонов; оператор контролирует длительность. - Опционально: `timeout 21600 docker compose ...` в cron (ET-008 R-11 уже фиксирует). ## R-7 — UI-фильтр «Источник» не подхватывает новые ID - **Описание:** Если в ET-008 UI-фильтр (`#gps-source-grid`) построен с захардкоженным списком `[osm]`, новые источники не появятся как чекбоксы. - **Вероятность / Влияние:** Н / С. - **Митигация:** - **Дизайн ET-008**: UI строит фильтр **динамически** из ответа `/api/gps-tracks/health.tracks_by_source` (источники с count > 0). После первого прогона ET-009 — фильтр сам покажет 3 чекбокса. - UI-тест TC-UI-04 (в `04b-ui-test-cases.md` ET-008) расширен для ET-009: проверяет наличие 3 чекбоксов после двух прогонов. - Маппинг `SOURCE_LABELS` (в `gps_tracks.js`) расширяется явно в ET-009 — даёт корректные читаемые названия. ## R-8 — Цветовая палитра в `style.json` / `style-dark.json` не содержит новых ID → линии серые - **Описание:** В ET-008 match-expression `line-color` может содержать только `osm`; новые источники получат fallback-серый. - **Вероятность / Влияние:** В / Н. - **Митигация:** - **REQ-F-13** явно требует обновить match-expression с тремя источниками + fallback. - Code-review-чеклист: проверить наличие `enduro_russia`, `wikiloc` в `paint.line-color` обоих стилей. - При пропуске: визуальный регресс легко заметен в smoke-тесте (TC-UI-05). ## R-9 — Дамп БД (резервная копия с старым URL) — orphan записи - **Описание:** Если на test-сервере есть резервная копия БД, в которой `external_urls_json` содержит `enduro-russia.ru` (с дефисом), то после фикса URL новые treki будут иметь `endurorussia.ru` (без дефиса), а старые — `enduro-russia.ru`. Это не криминал, но фрагментация атрибуции. - **Вероятность / Влияние:** Н / Н. - **Митигация:** - На практике `enduro_russia` до ET-009 был `enabled: false` → таких записей **нет**. Риск гипотетический. - Опциональный one-shot `UPDATE tracks SET external_urls_json = REPLACE(...)` — фиксируется в `14-deploy-log.md` если применяется. ## R-10 — ADR-010 / ADR-012 регрессировали в `proposed` - **Описание:** Между моментом написания BRD/TRZ ET-009 и моментом активации (merge → deploy) кто-то откатил статус ADR в `proposed`. Pipeline-guard заблокирует source с `skipped_license`. - **Вероятность / Влияние:** Н / В. - **Митигация:** - **F-03 / REQ-F-05** — pre-check перед активацией: ```bash grep -E "^status:" docs/work-items/ET-008/06-adr/ADR-010-enduro-russia-licensing.md grep -E "^status:" docs/work-items/ET-008/06-adr/ADR-012-wikiloc-licensing.md ``` Оба должны вернуть `accepted`. Иначе — STOP и эскалация архитектору. - Интеграционный тест IT-LIC-01 проверяет работу pipeline-guard'а: подменяет `accepted → proposed` в копии ADR-010 и убеждается, что pipeline скипает source с `status='skipped_license'`. - **Наследник от:** ET-008 R-9. ## R-11 — Пользовательский opt-in для новых источников - **Описание:** Пользователи с уже сохранённым `localStorage['gps-tracks-sources'] = ["osm"]` после ET-009 **не увидят** треки EnduroRussia/Wikiloc на своих устройствах — клиент сохраняет старое значение, новые источники по умолчанию не enabled в UI. - **Вероятность / Влияние:** В / Н. - **Митигация:** - Это **сознательное решение** UX (см. `08-data-requirements.md` §4.2): добавление источников без согласия пользователя — нарушение принципа без сюрпризов. - Чекбоксы новых источников появятся в `#sheet-gps-filters` automatically (через health-endpoint), пользователь может включить их вручную. - В release-notes (если они есть в проекте) — фиксируем «появились два новых источника, активация в фильтре». ## R-12 — Wikiloc-парсер сохраняет описание / автора несмотря на ADR-012 - **Описание:** ADR-012 §3 явно запрещает сохранять `description` и `user` для Wikiloc. Если реализация парсера не уважает этот запрет (например, `TrackInsert.description` заполняется), нарушение licensing-условий. - **Вероятность / Влияние:** Н / В. - **Митигация:** - **Текущая реализация:** `wikiloc.py::_parse_gpx` возвращает `TrackInsert(description=None, user=None)` (зашито в коде). - Unit-тест UT-WL-05 проверяет, что `description=None` и `user=None` в возвращаемом `TrackInsert`. - Code-review checklist в `12-review.md`: при любом изменении парсера Wikiloc убедиться, что эти поля остаются null. ## R-13 — Тестовые фикстуры устаревают - **Описание:** Снимки HTML/JSON, использованные в unit-тестах, отражают состояние API/HTML **на момент снятия**. Через 6-12 месяцев платформа может изменить разметку, и фикстуры станут неактуальны. Тесты пройдут (фикстура соответствует тесту), но парсер **не будет работать** в production. - **Вероятность / Влияние:** С / С. - **Митигация:** - Контрактный smoke-тест `test_endurorussia_api_smoke.py` (`@pytest.mark.network`, nightly) — проверяет реальную схему API, ловит расхождение. - Аналогичный smoke для Wikiloc **не** делаем (риск бана IP при регулярных запросах; ETC-009 §«REQ-F-16»). - Health-эндпоинт показывает `tracks_by_source.wikiloc` после каждого продакшн-прогона; устойчивое 0 — сигнал. - При устаревании фикстуры — снимаем заново (1 час работы), парсер обновляем (1-3 часа). ## R-14 — Производительность endpoint деградирует при росте кол-ва треков - **Описание:** REQ-NF-02 ET-008 фиксирует p95 ≤ 300 мс на bbox с ≤ 500 треков. После ET-009 в БД появятся ещё ≤ 250 треков — пренебрежимо относительно 5000 OSM. - **Вероятность / Влияние:** Н / Н. - **Митигация:** - R-tree индекс по `geom` (ADR-005) → O(log n) bbox-prefetch. - AC-20 — нагрузочный тест 100 запросов после первого прогона. - При деградации — анализ EXPLAIN QUERY PLAN; добавление индекса `idx_tracks_source` опционально (out of scope ET-009). ## R-15 — Конфликт MAPPING-таблиц для одной активности - **Описание:** EnduroRussia маппит `motorcycle → moto`, Wikiloc тоже `motorcycle → moto` — корректно. Но: EnduroRussia при отсутствии match'а в MAPPING возвращает `enduro` (fallback), Wikiloc — `moto`. Для одного и того же трека (попавшего в оба источника) при merge получим `activity_type` от source с большим `source_priority` = `enduro_russia` → `enduro`. Это **OK**: priority делает выбор детерминированным. - **Вероятность / Влияние:** Н / Н. - **Митигация:** - Принято as is. Уточнение в `08-data-requirements.md` §3.4. - Unit-тесты UT-ER-04 и UT-WL-06 проверяют отдельные MAPPING'и. ## R-16 — Регрессия e2e-тестов ET-008 - **Описание:** Расширение `style.json` / `gps_tracks.js` атрибуцией и цветами может случайно сломать существующие selectors / визуальные тесты ET-008. - **Вероятность / Влияние:** Н / С. - **Митигация:** - **AC-19** — все e2e ET-008 (E-01..E-41) должны пройти после мерджа ET-009. - Регрессионный прогон `pytest tests/e2e/ -v` — обязательный шаг CI. ## R-17 — Pipeline скипает source из-за неправильного `license_adr` path - **Описание:** Pipeline-guard `_check_license_adr` читает YAML front-matter файла по пути из `license_adr`. Если путь опечатан (например, `ADR-12-...` вместо `ADR-012-...`), guard вернёт false → `status='skipped_license'`. - **Вероятность / Влияние:** Н / В. - **Митигация:** - Pre-deploy check: убедиться, что `license_adr` указывает на реально существующий файл с `status: accepted`. - При первом запуске pipeline в test-среде оператор смотрит `pipeline_runs[-1].status`; если `skipped_license` — диагностирует и исправляет до merge в main. - Pydantic-валидация `gps_sources.yaml` в pipeline ET-008 уже требует обязательное `license_adr` поле; отсутствие — exception при старте. - **Наследник от:** ET-008 R-9. ## Сводная таблица | ID | Риск | Вер. | Влияние | Класс | Статус | |---|---|---|---|---|---| | R-1 | Wikiloc меняет HTML | В | С | Высокий | принят + graceful + быстрое отключение | | R-2 | Wikiloc банит IP mva154 | С | В | Высокий | rate-limit 10s + cap 50 + UA + monitor | | R-3 | EnduroRussia API меняет схему | Н | С | Низкий | smoke-тест + graceful + health | | R-4 | Расхождение URL `enduro-russia` vs `endurorussia` | Случилось | В | Высокий | F-01 фикс + UT-ER-05 | | R-5 | Дубли EnduroRussia/Wikiloc | В | С | Средний | dedup-key + IT-DEDUP-01 | | R-6 | Cron первого прогона долго | С | Н | Низкий | `max_tracks_per_run=50` + ручной прогон | | R-7 | UI-фильтр не подхватит | Н | С | Низкий | динамика из health + SOURCE_LABELS | | R-8 | Стили без новых цветов | В | Н | Низкий | REQ-F-13 + review + smoke | | R-9 | Orphan записи с старым URL | Н | Н | Низкий | гипотетический (БД чистая); опц UPDATE | | R-10 | ADR-010/012 регрессировали в proposed | Н | В | Высокий | pre-check + IT-LIC-01 | | R-11 | Пользовательский opt-in для новых источников | В | Н | Низкий | сознательный UX-compromise | | R-12 | Wikiloc сохраняет description/user | Н | В | Высокий | parser-design + UT-WL-05 + review | | R-13 | Фикстуры устаревают | С | С | Средний | smoke-test + health + ручной refresh | | R-14 | Деградация endpoint | Н | Н | Низкий | R-tree + AC-20 | | R-15 | Конфликт MAPPING | Н | Н | Низкий | source_priority детерминирует | | R-16 | Регрессия ET-008 e2e | Н | С | Низкий | AC-19 + pytest e2e | | R-17 | Неправильный `license_adr` path | Н | В | Высокий | pre-deploy check + Pydantic | **Высокие классы:** - R-1, R-2 — операционные, ожидаемые для скрейп-источника Wikiloc; митигация — multi-layer (graceful + monitor + конфиг-kill-switch). - R-4 — known bug в конфиге, прямо адресован REQ-F-01. - R-10, R-17 — критичны для legal compliance; митигация многослойная (pre-check + integration-тест + Pydantic). - R-12 — критичен для соблюдения ADR-012; митигация через design + UT-WL-05 + review. **Блокирующих рисков нет.** Высокие классы требуют внимания на этапе разработки и code review. ## Эскалация - **arch:major-change** — **не выставляется** (см. ADR-013 §«Классификация»). Изменение не вводит новых архитектурных компонентов. - **back-to:analysis** — не требуется. ТЗ полное, BRD ясный, open-questions в `TRZ §6` закрыты дефолтными решениями. - Эскалация архитектору требуется **только** при срабатывании R-10 (ADR в `proposed` на момент активации). Тогда задача останавливается до повторного апрува ADR.