Files
enduro-trails/docs/work-items/ET-007/10-tech-risks.md
claude-bot 1984b0bde6
All checks were successful
CI / lint (push) Successful in 4s
CI / test (push) Successful in 6s
CI / lint (pull_request) Successful in 4s
CI / test (pull_request) Successful in 5s
CI / build (push) Successful in 4s
CI / build (pull_request) Successful in 2s
fix(ET-007): address 6 P1 findings from review (docs + code)
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>
2026-05-31 21:05:49 +00:00

16 KiB
Raw Permalink Blame History

type, work_item_id, title, version, status, created_at, changelog, authors
type work_item_id title version status created_at changelog authors
tech-risks ET-007 Технические риски — ET-007: Спутниковая карта (Схема / Спутник) 2 approved 2026-05-31
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.
agent:architect

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

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

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

  • Описание: ADR-004 §5 решает читаемость линий грунтовок и троп на спутнике через парные «underlay»-слои с visibility: none в обоих файлах стилей. Реальные id (подтверждены кодом style.json:5670, 93107 и style-dark.json:5670, 93107): 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', ...) обработчиков на свои слои (он — невзаимодействующий растр), поэтому дублирования обработчиков здесь не возникает.
  • Вероятность / Влияние: Н / Н.
  • Митигация: проверка перед addSourceif (!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 или возврат в Анализ не требуются.