---
type: tech-risks
work_item_id: ET-007
title: "Технические риски — ET-007: Спутниковая карта (Схема / Спутник)"
version: 2
status: approved
created_at: 2026-05-31
changelog:
  - "v2 (2026-05-31): code-review fix (12-review.md P1-1) — R-1 переписан под реальные halo-id (trails-track-halo-satellite, trails-path-bridleway-halo-satellite); исключён фиктивный массив grade1..5."
authors:
  - "agent:architect"
---

# Технические риски — ET-007

Технические риски этапа разработки. Бизнес-риски — в BRD §5
(пересечение есть, здесь акцент на техническую митигацию).
Шкала: вероятность (Н/С/В) × влияние (Н/С/В).

## R-1 — Дрейф halo-слоёв в `style.json` / `style-dark.json`

- **Описание:** ADR-004 §5 решает читаемость линий грунтовок и троп
  на спутнике через парные «underlay»-слои с `visibility: none` в
  обоих файлах стилей. Реальные id (подтверждены кодом
  `style.json:56–70`, `93–107` и `style-dark.json:56–70`, `93–107`):
  `trails-track-halo-satellite`, `trails-path-bridleway-halo-satellite`.
  Любая будущая правка основных trails-слоёв (цвет, ширина, фильтр)
  требует **согласованной правки halo-слоёв** в обоих файлах. Без
  явной проверки легко забыть один из четырёх случаев (2 темы × 2
  рода слоёв).
- **Вероятность / Влияние:** С / Н.
- **Митигация:**
  - При разработке завести единый список затрагиваемых пар в
    `applyBaseLayer()`: массив пар `[('trails-track',
    'trails-track-halo-satellite'), ('trails-path-bridleway',
    'trails-path-bridleway-halo-satellite')]`. Производное правило
    «`<base>-halo-satellite`» допустимо, но только для **этих двух**
    base-id; массив `['trails-grade1..5']` (как в более раннем
    черновике, см. 12-review.md P1-1) **не использовать** — таких
    слоёв в `style.json` нет, дифференциация grade хранится внутри
    одного `match`-выражения по `tracktype` в `trails-track`.
  - Code review-чеклист: при правке `trails-track`, `trails-path-
    bridleway` в `style*.json` — обязательная сверка соответствующего
    `*-halo-satellite` в том же файле.
  - UI-тест AC-04 проверяет видимость линий поверх спутника в обеих
    темах.

## R-2 — Провайдер Esri меняет условия / URL / вводит API-ключ

- **Описание:** Esri World Imagery — единственная внешняя зависимость
  фичи, выбранная без формального соглашения; в перспективе Esri
  может ограничить бесплатный доступ, изменить URL-схему или ввести
  обязательный API-ключ (BRD §5 риск №1). Тогда «Спутник» перестаёт
  работать у всех пользователей одновременно.
- **Вероятность / Влияние:** С / В.
- **Митигация:**
  - Точка расширения локализована: единственный объект source-spec
    в `applyBaseLayer()` (ADR-004 §1).
  - При деградации провайдера выполняется одна правка JS-фронтенда
    (новый URL-шаблон + новая атрибуция), без миграций и серверных
    изменений; откат прежнего поведения — обратный коммит.
  - Альтернативные провайдеры предварительно рассмотрены в ADR-004
    §«Вариант P»; быстрый switch на следующего по приоритету —
    Mapbox или MapTiler — потребует только введения переменной
    окружения для API-ключа (это уже инфра-изменение, выходящее за
    scope ET-007).
  - Регулярная smoke-проверка дос­тупности через UI-тест AC-02.

## R-3 — Утечка IP клиента на серверы Esri

- **Описание:** при активном «Спутник» браузер обращается напрямую
  к `server.arcgisonline.com`; IP пользователя и User-Agent видны
  Esri. Это **не регрессия** (OSM tile уже работает аналогично), но
  расширение списка третьих сторон, к которым обращается клиент.
- **Вероятность / Влияние:** В (т.е. произойдёт всегда при включении
  спутника, дизайн именно такой) / Н.
- **Митигация:**
  - **Ленивое создание source** (ADR-004 §3): пользователь,
    никогда не включающий «Спутник», ни одного запроса в Esri не
    отправляет. Это обеспечивает «приватный по умолчанию» режим.
  - Документировано в `08-data-requirements.md` §7.
  - В отдельный политический документ выноситься не требуется —
    приватность фичи на уровне рейзанса вынесена в ADR-004 §«Последствия».

## R-4 — Корпсеть / DNS-блокировка `arcgisonline.com`

- **Описание:** часть пользователей работает в сетях, блокирующих
  arcgisonline.com (анти-трекинг-DNS типа NextDNS/Pi-hole,
  корпоративные firewall). MapLibre будет показывать прозрачные
  плитки поверх фона `#2a2a2a`; пользователь увидит «дыры».
- **Вероятность / Влияние:** Н / С.
- **Митигация:**
  - TRZ §1 REQ-F-08 явно фиксирует: автоматический fallback на
    «Схему» не закладывается — пользователь возвращается на схему
    вручную; это сознательное проектное решение.
  - В виду фона `#2a2a2a` пустота визуально опознаётся как ошибка
    подложки, а не «лёг" сайт.
  - Эскалация / альтернативный провайдер при единичных жалобах не
    требуется; при системных — переход к R-2.

## R-5 — Дублирование `background-color` между `style*.json` и `app.js`

- **Описание:** ADR-004 §6 требует менять `background-color` на
  единую satellite-константу `#2a2a2a` (обе темы) при включении
  «Спутник» и возвращать к исходному при возврате на «Схему».
  «Исходные» значения (`#f0ede6` для светлой, `#1a1a2e` для тёмной —
  именно `#1a1a2e`, как в `style-dark.json:28`, а не `#1a1a1a` из
  более раннего черновика, см. 12-review.md P1-4 / P2-3)
  дублируются в `applyBaseLayer()` и в `style*.json` — при смене
  палитры тем легко забыть один из двух.
- **Вероятность / Влияние:** Н / Н.
- **Митигация:**
  - Альтернатива — при возврате на «Схему» **читать** актуальное
    значение через `getPaintProperty('background', 'background-color')`
    непосредственно перед мутацией в «Спутник», и кэшировать его в
    замыкании. Однако `setStyle()` сбрасывает кэш, что усложняет
    логику. Принято: задублировать в коде с явным комментарием
    в `app.js` и code review-чеклистом.
  - Покрытие AC-06 (смена темы при активном «Спутник») косвенно
    проверяет согласованность.

## R-6 — Накопление обработчиков и source/layer после `map.setStyle()`

- **Описание:** при `map.setStyle()` (переключение тёмной/светлой
  темы) спутниковый source/layer удаляются вместе со стилем.
  `restoreBaseLayerState()` пересоздаёт их в `rebuildMapOverlays()`.
  Аналогичный риск зафиксирован для GPX (ET-006, R-4: «дублирование
  обработчиков»). Спутник, в отличие от GPX, **не вешает свои
  `map.on('click', ...)`** обработчиков на свои слои (он —
  невзаимодействующий растр), поэтому дублирования обработчиков
  здесь не возникает.
- **Вероятность / Влияние:** Н / Н.
- **Митигация:** проверка перед `addSource` — `if
  (!map.getSource('satellite-raster')) map.addSource(...)`; то же для
  layer. Это идемпотентный паттерн, уже используемый в проекте для
  terrain/trails.

## R-7 — Несовместимость z-order при `restoreBaseLayerState()` после terrain

- **Описание:** если разработчик случайно вызовет
  `restoreBaseLayerState()` **после** `restoreTerrainState()` в
  `rebuildMapOverlays()`, спутник окажется поверх hillshade и
  перекроет его. Это нарушит AC-04 («Hillshade поверх спутника»).
- **Вероятность / Влияние:** Н / С.
- **Митигация:**
  - ADR-004 §4 явно фиксирует: `restoreBaseLayerState()` вызывается
    **ПЕРВЫМ** в `rebuildMapOverlays()`.
  - Комментарий в коде `app.js` непосредственно у вызова —
    `// ET-007/ADR-004: ПЕРВЫМ, чтобы trails/terrain легли поверх`.
  - UI-тест AC-04 «Hillshade поверх спутника» отлавливает регрессию.

## R-8 — Производительность переключения «Схема → Спутник» > 500 мс

- **Описание:** НФТ ТЗ — ≤ 500 мс до первой видимой плитки. При
  холодном переключении в одном кадре происходит: чтение
  `localStorage`, `addSource`, `addLayer`, `setLayoutProperty`,
  `setPaintProperty` ×N для POI, `setLayoutProperty` ×K для halo-
  underlays. Главная неопределённость — сетевая задержка до Esri.
- **Вероятность / Влияние:** Н / С.
- **Митигация:**
  - Все операции стиля MapLibre — синхронные O(1) на source/layer;
    суммарно < 50 мс.
  - Сетевая задержка для PNG 30–80 КБ из Esri CDN на канале
    ≥ 5 Мбит/с укладывается в 200–300 мс на тайл (по практике
    Leaflet/OpenLayers с этим же провайдером).
  - Тест НФТ TP-Performance в `04-test-plan.yaml` проверяет
    верхнюю границу.

## R-9 — Конфликт mobile-вёрстки попапа

- **Описание:** новая строка `terrain-base-row` добавляется в
  `#terrain-popup` сверху. На узких экранах (375 px, ET-005 TP-05)
  возможен выход за пределы попапа или перекрытие смежных строк.
- **Вероятность / Влияние:** Н / Н.
- **Митигация:**
  - Переиспользуется готовый компонент `.seg-control` (адаптивен по
    ширине), без введения нового CSS-компонента.
  - UI-тест AC-09 (mobile viewport 375 × 812) — обязательный.

## R-10 — Включение спутника после рестарта при отсутствии сети у Esri

- **Описание:** пользователь сохранил `map-base-layer = "satellite"`,
  затем при следующем визите Esri недоступен. `restoreBaseLayerState()`
  вызовет `applyBaseLayer('satellite')`, source создастся, плиток не
  будет — пользователь увидит пустой тёмный фон вместо привычной
  карты.
- **Вероятность / Влияние:** Н / Н.
- **Митигация:**
  - Поведение явно соответствует TRZ §1 REQ-F-08; на mobile/desktop
    пользователь нажмёт «Схема» и продолжит работу.
  - Авто-fallback на «Схему» при сетевой ошибке провайдера —
    **не закладывается** (см. ADR-004 §«Последствия»). Введение
    fallback возможно в будущей итерации без изменения внешнего
    контракта `applyBaseLayer()`.

## Сводная таблица

| ID  | Риск | Вер. | Влияние | Класс | Статус |
|-----|------|------|---------|-------|--------|
| R-1 | Дрейф halo-слоёв в обоих style.json | С | Н | Средний | внимание разработки + review |
| R-2 | Esri меняет условия / URL / вводит ключ | С | В | Высокий | митигация — точка расширения |
| R-3 | Утечка IP на Esri при активном спутнике | В | Н | Средний | приватный-по-умолчанию (lazy) |
| R-4 | DNS-блокировка `arcgisonline.com` | Н | С | Низкий | принят (TRZ REQ-F-08) |
| R-5 | Дубль background-color в style/app.js | Н | Н | Низкий | принят + комментарий в коде |
| R-6 | Source/layer после setStyle | Н | Н | Низкий | идемпотентные `if (!getSource)` |
| R-7 | Неверный порядок restoreBaseLayerState | Н | С | Низкий | ADR явно + комментарий + AC-04 |
| R-8 | Переключение > 500 мс | Н | С | Низкий | покрыто НФТ-тестом |
| R-9 | Mobile-вёрстка попапа | Н | Н | Низкий | AC-09 |
| R-10 | Restore satellite при недоступности Esri | Н | Н | Низкий | принят, fallback не закладываем |

Блокирующих рисков нет. R-2 — единственный «высокий» класс, но
вероятность средняя и митигация (локализация точки расширения)
делает реакцию операционно простой. Эскалация `arch:major-change`
или возврат в Анализ не требуются.
