--- type: tech-risks work_item_id: ET-007 title: "Технические риски — ET-007: Спутниковая карта (Схема / Спутник)" version: 1 status: approved created_at: 2026-05-31 authors: - "agent:architect" --- # Технические риски — ET-007 Технические риски этапа разработки. Бизнес-риски — в BRD §5 (пересечение есть, здесь акцент на техническую митигацию). Шкала: вероятность (Н/С/В) × влияние (Н/С/В). ## R-1 — Дрейф halo-слоёв в `style.json` / `style-dark.json` - **Описание:** ADR-004 §5 решает читаемость линий грунтовок и троп на спутнике через парные «underlay»-слои `*-halo-satellite` с `visibility: none` в обоих файлах стилей. Любая будущая правка основных trails-слоёв (цвет, ширина, фильтр) требует **согласованной правки halo-слоёв** в обоих файлах. Без явной проверки легко забыть один из четырёх случаев (2 темы × 2 рода слоёв). - **Вероятность / Влияние:** С / Н. - **Митигация:** - При разработке завести единый список затрагиваемых пар в `applyBaseLayer()`: массив `['trails-grade1', 'trails-grade2', ...]` с производным правилом `-halo-satellite`. Это исключит «забытый» halo-слой со стороны JS. - Code review-чеклист: при правке trails-* в `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` на тёмно-серый при включении «Спутник» и возвращать к исходному при возврате на «Схему». «Исходные» значения (`#f0ede6` для светлой, тёмное для тёмной) дублируются в `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` или возврат в Анализ не требуются.