All checks were successful
12-review.md (REQUEST_CHANGES, attempt 2/3) flagged 6 must-fix items
in the analysis/architecture artefacts plus matching bugs that had
already leaked into the committed implementation. This patch lands
both: documents corrected, code aligned with corrected specs, tests
updated.
P1-1: TRZ/ADR/Data/Risks referenced fictional layer ids
(`trails-grade1..5-halo-satellite`, `paths-bridleway-halo-satellite`).
Actual style*.json has only `trails-track-halo-satellite` and
`trails-path-bridleway-halo-satellite`; grade differentiation lives
inside one `match` expression on `tracktype` within `trails-track`.
Docs rewritten to operate on real ids.
P1-2: POI labels contrast was broken — spec changed only halo-color
to black, leaving `text-color: #333333` (light theme baseline)
unreadable over the new black halo. Code+docs now switch BOTH
`text-color` (-> `#ffffff` on satellite) AND halo together, with
per-theme baselines (`#333333` light / `#e0e0e0` dark) restored on
return to Schematic.
P1-3: BRD §5 hillshade risk said «hillshade auto-disabled on
satellite», contradicting TRZ/ADR/AC. BRD wording aligned: hillshade
keeps working over satellite; visual check is AC-04.
P1-4: background-color had four divergent sources (`#1a1a1a`,
`#2a2a2a`, `#1a1a2e`, `#f0ede6`), incl. an inverted-theme typo and a
baseline `#1a1a1a` that didn't match the actual `style-dark.json:28`
value `#1a1a2e`. Settled on ADR-004's single-constant model: `#2a2a2a`
on satellite for both themes; on Schematic restore per-theme baselines
`#f0ede6` (light) / `#1a1a2e` (dark). `_applyBackgroundForSatellite`
fixed accordingly.
P1-5: app.js already had `layerState.basemap` and `toggleLayer
('basemap')` (legacy «Базовая карта» switch). Neither TRZ nor ADR
specified the interaction. Added save&restore contract: on entering
Satellite save `layerState.basemap` to `_savedBasemapState` and
force-hide `osm-base`; on returning to Schematic restore osm-base
visibility from the saved value. CSS hook `body.satellite-active
#btn-basemap { display:none }` keeps the user from trying to enable
a hybrid mode (out of scope, BRD §3). TRZ §5.6, ADR-004 §8.
P1-6: `restoreTrailsState()` and `onTrailsCheckbox()` only managed
visibility of `trails-track` / `trails-path-bridleway`, leaving
their halo-underlay siblings as «phantom» halos when the user
unchecked grunты/тропы under Satellite. Introduced
`_applyTrailHaloVisibility(map, base)` reading checkbox state from
DOM; called from `onTrailsCheckbox`, `restoreTrailsState`, and both
branches of `applyBaseLayer`. Rule: halo visible ⇔ (base ===
satellite) AND (checkbox ON). TRZ §5.7, ADR-004 §9.
Docs bumped: BRD v2, TRZ v2, AC v2, Data v2, Risks v2; ADR-004
получает «Ревизии»-секцию (status remains accepted — only editorial
fixes, no decision change).
Tests:
- tests/unit/base_layer.test.js: rewritten 2 background-color
assertions (#1a1a1a expectation removed), added 6 new tests for
P1-2 / P1-4 (POI text-color per-theme baselines, single satellite
bg #2a2a2a, baseline restore on Schematic).
- All 33 JS unit tests + 22 pytest static checks green.
- Full pytest suite: 76 passed (excluding pre-existing
shapely-import skipped collection in tests/unit/test_health.py).
Refs: ET-007
Review: docs/work-items/ET-007/12-review.md (P1-1..P1-6)
ADR: docs/work-items/ET-007/06-adr/ADR-004-satellite-base-layer.md (rev. 2026-05-31)
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
215 lines
16 KiB
Markdown
215 lines
16 KiB
Markdown
---
|
||
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`
|
||
или возврат в Анализ не требуются.
|