Files
enduro-trails/docs/work-items/ET-007/10-tech-risks.md
claude-bot 231c99c045
All checks were successful
CI / lint (push) Successful in 3s
CI / test (push) Successful in 6s
CI / build (push) Successful in 1s
docs(ET-007): architecture - ADR, infra-requirements, data-requirements, tech-risks
2026-05-31 20:01:06 +00:00

201 lines
14 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
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', ...]`
с производным правилом `<base>-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 3080 КБ из Esri CDN на канале
≥ 5 Мбит/с укладывается в 200300 мс на тайл (по практике
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`
или возврат в Анализ не требуются.